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.22 2004/02/19 03:45:44 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>
43 #include <rosrtl/string.h>
48 /* Directory to load key layouts from */
49 #define SYSTEMROOT_DIR L"\\SystemRoot\\System32\\"
51 #define CAPITAL_BIT 0x80000000
52 #define NUMLOCK_BIT 0x40000000
53 #define MOD_BITS_MASK 0x3fffffff
54 #define MOD_KCTRL 0x02
56 #define KS_DOWN_MASK 0xc0
57 #define KS_DOWN_BIT 0x80
58 #define KS_EXT_BIT 0x40
59 #define KS_LOCK_BIT 0x01
61 #define LP_EXT_BIT (1<<24)
62 /* From kbdxx.c -- Key changes with numlock */
65 /* Lock the keyboard state to prevent unusual concurrent access */
66 FAST_MUTEX QueueStateLock
;
68 BYTE QueueKeyStateTable
[256];
70 /* FUNCTIONS *****************************************************************/
72 /* Initialization -- Right now, just zero the key state and init the lock */
73 NTSTATUS FASTCALL
InitKeyboardImpl(VOID
) {
74 ExInitializeFastMutex(&QueueStateLock
);
75 RtlZeroMemory(&QueueKeyStateTable
,0x100);
76 return STATUS_SUCCESS
;
79 /*** Statics used by TranslateMessage ***/
81 /*** Shift state code needs to be cleaned up here. Sorry, I let it get out
84 static UINT
DontDistinguishShifts( UINT ret
) {
85 if( ret
== VK_LSHIFT
|| ret
== VK_RSHIFT
) ret
= VK_SHIFT
;
86 if( ret
== VK_LCONTROL
|| ret
== VK_RCONTROL
) ret
= VK_CONTROL
;
87 if( ret
== VK_LMENU
|| ret
== VK_RMENU
) ret
= VK_MENU
;
91 static VOID STDCALL
SetKeyState(DWORD key
, DWORD vk
, DWORD ext
, BOOL down
) {
92 /* Special handling for toggles like numpad and caps lock */
93 if (vk
== VK_CAPITAL
|| vk
== VK_NUMLOCK
)
95 if (down
) QueueKeyStateTable
[key
] ^= 1;
99 QueueKeyStateTable
[key
] |= KS_DOWN_BIT
| (ext
? KS_EXT_BIT
: 0);
101 QueueKeyStateTable
[key
] &= ~KS_DOWN_MASK
;
104 VOID
DumpKeyState( PBYTE KeyState
) {
107 DbgPrint( "KeyState { " );
108 for( i
= 0; i
< 0x100; i
++ ) {
109 if( KeyState
[i
] ) DbgPrint( "%02x(%02x) ", i
, KeyState
[i
] );
114 static BYTE
KeysSet( PKBDTABLES pkKT
, PBYTE KeyState
,
115 int Mod
, int FakeModLeft
, int FakeModRight
) {
119 if( !KeyState
|| !pkKT
) return 0;
121 for( i
= 0; i
< pkKT
->bMaxVSCtoVK
; i
++ ) {
122 Vk
= pkKT
->pusVSCtoVK
[i
] & 0xff;
125 (FakeModLeft
&& Vk
== FakeModLeft
) ||
126 (FakeModRight
&& Vk
== FakeModRight
)) ) {
134 static DWORD
ModBits( PKBDTABLES pkKT
, PBYTE KeyState
) {
139 if( !KeyState
) return 0;
141 /* DumpKeyState( KeyState ); */
143 for( i
= 0; pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
; i
++ ) {
144 int Vk
= pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
;
148 Mask
= KeysSet( pkKT
, KeyState
, Vk
, VK_LSHIFT
, VK_RSHIFT
);
149 if (Mask
& KS_DOWN_MASK
)
150 ModBits
|= pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
153 Mask
= KeysSet( pkKT
, KeyState
, Vk
, VK_LCONTROL
, VK_RCONTROL
);
154 if (Mask
& KS_DOWN_MASK
)
155 ModBits
|= pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
158 Mask
= KeysSet( pkKT
, KeyState
, Vk
, VK_LMENU
, VK_RMENU
);
159 if (Mask
& KS_DOWN_MASK
)
160 ModBits
|= pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
161 if (Mask
& KS_EXT_BIT
)
162 ModBits
|= MOD_KCTRL
;
165 Mask
= KeysSet( pkKT
, KeyState
, Vk
, 0, 0 );
166 if (Mask
& KS_DOWN_BIT
)
167 ModBits
|= pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
172 /* Deal with VK_CAPITAL */
173 if (KeysSet( pkKT
, KeyState
, VK_CAPITAL
, 0, 0 ) & KS_LOCK_BIT
)
175 ModBits
|= CAPITAL_BIT
;
178 /* Deal with VK_NUMLOCK */
179 if (KeysSet( pkKT
, KeyState
, VK_NUMLOCK
, 0, 0 ) & KS_LOCK_BIT
)
181 ModBits
|= NUMLOCK_BIT
;
184 DPRINT( "Current Mod Bits: %x\n", ModBits
);
189 static BOOL
TryToTranslateChar(WORD wVirtKey
,
193 PWCHAR pwcTranslatedChar
,
194 PKBDTABLES keyLayout
)
196 PVK_TO_WCHAR_TABLE vtwTbl
;
197 PVK_TO_WCHARS10 vkPtr
;
198 size_t size_this_entry
;
200 DWORD CapsMod
= 0, CapsState
= 0;
202 CapsState
= ModBits
& ~MOD_BITS_MASK
;
203 ModBits
= ModBits
& MOD_BITS_MASK
;
205 DPRINT ( "TryToTranslate: %04x %x\n", wVirtKey
, ModBits
);
207 if (ModBits
> keyLayout
->pCharModifiers
->wMaxModBits
)
211 shift
= keyLayout
->pCharModifiers
->ModNumber
[ModBits
];
213 for (nMod
= 0; keyLayout
->pVkToWcharTable
[nMod
].nModifications
; nMod
++)
215 if (shift
> keyLayout
->pVkToWcharTable
[nMod
].nModifications
)
219 vtwTbl
= &keyLayout
->pVkToWcharTable
[nMod
];
220 size_this_entry
= vtwTbl
->cbSize
;
221 vkPtr
= (PVK_TO_WCHARS10
)((BYTE
*)vtwTbl
->pVkToWchars
);
222 while(vkPtr
->VirtualKey
)
224 if( wVirtKey
== (vkPtr
->VirtualKey
& 0xff) )
227 shift
| ((CapsState
& CAPITAL_BIT
) ? vkPtr
->Attributes
: 0);
229 *pbDead
= vkPtr
->wch
[CapsMod
] == WCH_DEAD
;
230 *pbLigature
= vkPtr
->wch
[CapsMod
] == WCH_LGTR
;
231 *pwcTranslatedChar
= vkPtr
->wch
[CapsMod
];
233 DPRINT("CapsMod %08x CapsState %08x shift %08x Char %04x\n",
234 CapsMod
, CapsState
, shift
, *pwcTranslatedChar
);
238 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
239 if( vkPtr
->VirtualKey
!= 0xff )
241 DPRINT( "Found dead key with no trailer in the table.\n" );
242 DPRINT( "VK: %04x, ADDR: %08x\n", wVirtKey
, (int)vkPtr
);
245 *pwcTranslatedChar
= vkPtr
->wch
[shift
];
249 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
257 ToUnicodeInner(UINT wVirtKey
,
265 WCHAR wcTranslatedChar
;
269 if( !pkKT
) return 0;
271 if( TryToTranslateChar( wVirtKey
,
272 ModBits( pkKT
, lpKeyState
),
280 DPRINT("Not handling ligature (yet)\n" );
284 if( cchBuff
> 0 ) pwszBuff
[0] = wcTranslatedChar
;
286 return bDead
? -1 : 1;
299 ExAcquireFastMutex(&QueueStateLock
);
301 ret
= ((DWORD
)(QueueKeyStateTable
[key
] & KS_DOWN_BIT
) << 8 ) |
302 (QueueKeyStateTable
[key
] & KS_EXT_BIT
) |
303 (QueueKeyStateTable
[key
] & KS_LOCK_BIT
);
305 ExReleaseFastMutex(&QueueStateLock
);
309 int STDCALL
ToUnicodeEx( UINT wVirtKey
,
316 int ToUnicodeResult
= 0;
318 ExAcquireFastMutex(&QueueStateLock
);
319 ToUnicodeResult
= ToUnicodeInner( wVirtKey
,
326 PsGetWin32Thread()->KeyboardLayout
: 0 );
327 ExReleaseFastMutex(&QueueStateLock
);
329 return ToUnicodeResult
;
332 int STDCALL
ToUnicode( UINT wVirtKey
,
338 return ToUnicodeEx( wVirtKey
,
348 * Utility to copy and append two unicode strings.
350 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
351 * IN PUNICODE_STRING Second -> Second string to append
352 * IN BOOL Deallocate -> TRUE: Deallocate First string before
358 NTSTATUS NTAPI
AppendUnicodeString(PUNICODE_STRING ResultFirst
,
359 PUNICODE_STRING Second
,
363 ExAllocatePool(PagedPool
,
364 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)));
366 return STATUS_NO_MEMORY
;
368 memcpy( new_string
, ResultFirst
->Buffer
,
369 ResultFirst
->Length
);
370 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
373 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
374 ResultFirst
->Length
+= Second
->Length
;
375 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
376 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
377 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
378 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
379 ExFreePool(new_string
);
384 * Utility function to read a value from the registry more easily.
386 * IN PUNICODE_STRING KeyName -> Name of key to open
387 * IN PUNICODE_STRING ValueName -> Name of value to open
388 * OUT PUNICODE_STRING ReturnedValue -> String contained in registry
393 static NTSTATUS NTAPI
ReadRegistryValue( PUNICODE_STRING KeyName
,
394 PUNICODE_STRING ValueName
,
395 PUNICODE_STRING ReturnedValue
) {
398 OBJECT_ATTRIBUTES KeyAttributes
;
399 PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo
;
404 InitializeObjectAttributes(&KeyAttributes
, KeyName
, OBJ_CASE_INSENSITIVE
,
406 Status
= ZwOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &KeyAttributes
);
407 if( !NT_SUCCESS(Status
) ) {
411 Status
= ZwQueryValueKey(KeyHandle
, ValueName
, KeyValuePartialInformation
,
416 if( Status
!= STATUS_BUFFER_TOO_SMALL
) {
421 ResLength
+= sizeof( *KeyValuePartialInfo
);
422 KeyValuePartialInfo
=
423 ExAllocatePool(PagedPool
, ResLength
);
426 if( !KeyValuePartialInfo
) {
428 return STATUS_NO_MEMORY
;
431 Status
= ZwQueryValueKey(KeyHandle
, ValueName
, KeyValuePartialInformation
,
432 (PVOID
)KeyValuePartialInfo
,
436 if( !NT_SUCCESS(Status
) ) {
438 ExFreePool(KeyValuePartialInfo
);
442 Temp
.Length
= Temp
.MaximumLength
= KeyValuePartialInfo
->DataLength
;
443 Temp
.Buffer
= (PWCHAR
)KeyValuePartialInfo
->Data
;
445 /* At this point, KeyValuePartialInfo->Data contains the key data */
446 RtlInitUnicodeString(ReturnedValue
,L
"");
447 AppendUnicodeString(ReturnedValue
,&Temp
,FALSE
);
449 ExFreePool(KeyValuePartialInfo
);
455 typedef PVOID (*KbdLayerDescriptor
)(VOID
);
456 NTSTATUS STDCALL
LdrGetProcedureAddress(PVOID module
,
457 PANSI_STRING import_name
,
461 void InitKbdLayout( PVOID
*pkKeyboardLayout
) {
462 UNICODE_STRING KeyName
;
463 UNICODE_STRING ValueName
;
464 UNICODE_STRING LayoutKeyName
;
465 UNICODE_STRING LayoutValueName
;
466 UNICODE_STRING DefaultLocale
;
467 UNICODE_STRING LayoutFile
;
468 UNICODE_STRING FullLayoutPath
;
469 PWCHAR KeyboardLayoutWSTR
;
470 HMODULE kbModule
= 0;
472 ANSI_STRING kbdProcedureName
;
473 KbdLayerDescriptor layerDescGetFn
;
475 #define XX_STATUS(x) if (!NT_SUCCESS(Status = (x))) continue;
478 RtlInitUnicodeString(&KeyName
,
479 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet"
480 L
"\\Control\\Nls\\Locale");
481 RtlInitUnicodeString(&ValueName
,
484 DPRINT("KeyName = %wZ, ValueName = %wZ\n", &KeyName
, &ValueName
);
486 Status
= ReadRegistryValue(&KeyName
,&ValueName
,&DefaultLocale
);
488 if( !NT_SUCCESS(Status
) ) {
489 DPRINT1( "Could not get default locale (%08x).\n", Status
);
491 DPRINT( "DefaultLocale = %wZ\n", &DefaultLocale
);
493 RtlInitUnicodeString(&LayoutKeyName
,
494 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet"
495 L
"\\Control\\KeyboardLayouts\\");
497 AppendUnicodeString(&LayoutKeyName
,&DefaultLocale
,FALSE
);
499 RtlFreeUnicodeString(&DefaultLocale
);
500 RtlInitUnicodeString(&LayoutValueName
,L
"Layout File");
502 Status
= ReadRegistryValue(&LayoutKeyName
,&LayoutValueName
,&LayoutFile
);
503 RtlInitUnicodeString(&FullLayoutPath
,SYSTEMROOT_DIR
);
505 if( !NT_SUCCESS(Status
) ) {
506 DPRINT1("Got default locale but not layout file. (%08x)\n",
508 RtlFreeUnicodeString(&LayoutFile
);
510 DPRINT("Read registry and got %wZ\n", &LayoutFile
);
512 RtlFreeUnicodeString(&LayoutKeyName
);
514 AppendUnicodeString(&FullLayoutPath
,&LayoutFile
,FALSE
);
516 DPRINT("Loading Keyboard DLL %wZ\n", &FullLayoutPath
);
518 RtlFreeUnicodeString(&LayoutFile
);
520 KeyboardLayoutWSTR
= ExAllocatePool(PagedPool
,
521 (FullLayoutPath
.Length
+ 1) *
524 if( !KeyboardLayoutWSTR
) {
525 DPRINT1("Couldn't allocate a string for the keyboard layout name.\n");
526 RtlFreeUnicodeString(&FullLayoutPath
);
529 memcpy(KeyboardLayoutWSTR
,FullLayoutPath
.Buffer
,
530 (FullLayoutPath
.Length
+ 1) * sizeof(WCHAR
));
531 KeyboardLayoutWSTR
[FullLayoutPath
.Length
] = 0;
533 kbModule
= EngLoadImage(KeyboardLayoutWSTR
);
534 DPRINT( "Load Keyboard Layout: %S\n", KeyboardLayoutWSTR
);
537 DPRINT1( "Load Keyboard Layout: No %wZ\n", &FullLayoutPath
);
540 RtlFreeUnicodeString(&FullLayoutPath
);
545 DPRINT1("Trying to load US Keyboard Layout\n");
546 kbModule
= EngLoadImage(L
"\\SystemRoot\\system32\\kbdus.dll");
550 DPRINT1("Failed to load any Keyboard Layout\n");
555 RtlInitAnsiString( &kbdProcedureName
, "KbdLayerDescriptor" );
557 LdrGetProcedureAddress((PVOID
)kbModule
,
560 (PVOID
*)&layerDescGetFn
);
562 if( layerDescGetFn
) {
563 *pkKeyboardLayout
= layerDescGetFn();
567 if( !*pkKeyboardLayout
) {
568 DPRINT1("Failed to load the keyboard layout.\n");
574 PKBDTABLES
W32kGetDefaultKeyLayout() {
575 PKBDTABLES pkKeyboardLayout
= 0;
576 InitKbdLayout( (PVOID
) &pkKeyboardLayout
);
577 return pkKeyboardLayout
;
581 IntTranslateKbdMessage(LPMSG lpMsg
,
584 static INT dead_char
= 0;
589 PKBDTABLES keyLayout
;
594 keyLayout
= PsGetWin32Thread()->KeyboardLayout
;
598 if (lpMsg
->message
!= WM_KEYDOWN
&& lpMsg
->message
!= WM_SYSKEYDOWN
)
601 ScanCode
= (lpMsg
->lParam
>> 16) & 0xff;
603 ExAcquireFastMutex(&QueueStateLock
);
605 UState
= ToUnicodeInner(lpMsg
->wParam
, HIWORD(lpMsg
->lParam
) & 0xff,
606 QueueKeyStateTable
, wp
, 2, 0,
611 NewMsg
.message
= (lpMsg
->message
== WM_KEYDOWN
) ? WM_CHAR
: WM_SYSCHAR
;
616 DPRINT("PREVIOUS DEAD CHAR: %c\n", dead_char
);
618 for( i
= 0; keyLayout
->pDeadKey
[i
].dwBoth
; i
++ )
620 first
= keyLayout
->pDeadKey
[i
].dwBoth
>> 16;
621 second
= keyLayout
->pDeadKey
[i
].dwBoth
;
622 if (first
== dead_char
&& second
== wp
[0])
624 wp
[0] = keyLayout
->pDeadKey
[i
].wchComposed
;
630 DPRINT("FINAL CHAR: %c\n", wp
[0]);
634 NewMsg
.hwnd
= lpMsg
->hwnd
;
635 NewMsg
.wParam
= dead_char
;
636 NewMsg
.lParam
= lpMsg
->lParam
;
637 UMsg
= MsqCreateMessage(&NewMsg
);
640 MsqPostMessage(PsGetWin32Thread()->MessageQueue
, UMsg
);
643 NewMsg
.hwnd
= lpMsg
->hwnd
;
644 NewMsg
.wParam
= wp
[0];
645 NewMsg
.lParam
= lpMsg
->lParam
;
646 UMsg
= MsqCreateMessage(&NewMsg
);
647 DPRINT( "CHAR='%c' %04x %08x\n", wp
[0], wp
[0], lpMsg
->lParam
);
649 MsqPostMessage(PsGetWin32Thread()->MessageQueue
, UMsg
);
652 else if (UState
== -1)
655 (lpMsg
->message
== WM_KEYDOWN
) ? WM_DEADCHAR
: WM_SYSDEADCHAR
;
656 NewMsg
.hwnd
= lpMsg
->hwnd
;
657 NewMsg
.wParam
= wp
[0];
658 NewMsg
.lParam
= lpMsg
->lParam
;
660 UMsg
= MsqCreateMessage(&NewMsg
);
662 MsqPostMessage(PsGetWin32Thread()->MessageQueue
, UMsg
);
666 ExReleaseFastMutex(&QueueStateLock
);
672 NtUserGetKeyboardState(
677 ExAcquireFastMutex(&QueueStateLock
);
679 if(!NT_SUCCESS(MmCopyToCaller(lpKeyState
, QueueKeyStateTable
, 256)))
682 ExReleaseFastMutex(&QueueStateLock
);
688 NtUserSetKeyboardState(
693 ExAcquireFastMutex(&QueueStateLock
);
695 if(! NT_SUCCESS(MmCopyFromCaller(QueueKeyStateTable
, lpKeyState
, 256)))
698 ExReleaseFastMutex(&QueueStateLock
);
703 static UINT
VkToScan( UINT Code
, BOOL ExtCode
, PKBDTABLES pkKT
) {
706 for( i
= 0; i
< pkKT
->bMaxVSCtoVK
; i
++ ) {
707 if( pkKT
->pusVSCtoVK
[i
] == Code
) { return i
; }
713 UINT
ScanToVk( UINT Code
, BOOL ExtKey
, PKBDTABLES pkKT
) {
715 DPRINT("ScanToVk: No layout\n");
722 for( i
= 0; pkKT
->pVSCtoVK_E0
[i
].Vsc
; i
++ ) {
723 if( pkKT
->pVSCtoVK_E0
[i
].Vsc
== Code
)
724 return pkKT
->pVSCtoVK_E0
[i
].Vk
& 0xff;
726 for( i
= 0; pkKT
->pVSCtoVK_E1
[i
].Vsc
; i
++ ) {
727 if( pkKT
->pVSCtoVK_E1
[i
].Vsc
== Code
)
728 return pkKT
->pVSCtoVK_E1
[i
].Vk
& 0xff;
733 if( Code
>= pkKT
->bMaxVSCtoVK
) { return 0; }
734 return pkKT
->pusVSCtoVK
[Code
] & 0xff;
739 * Map a virtual key code, or virtual scan code, to a scan code, key code,
740 * or unshifted unicode character.
744 * 0 -- Code is a virtual key code that is converted into a virtual scan code
745 * that does not distinguish between left and right shift keys.
746 * 1 -- Code is a virtual scan code that is converted into a virtual key code
747 * that does not distinguish between left and right shift keys.
748 * 2 -- Code is a virtual key code that is converted into an unshifted unicode
750 * 3 -- Code is a virtual scan code that is converted into a virtual key code
751 * that distinguishes left and right shift keys.
752 * KeyLayout: Keyboard layout handle (currently, unused)
757 static UINT
IntMapVirtualKeyEx( UINT Code
, UINT Type
, PKBDTABLES keyLayout
) {
762 if( Code
== VK_RSHIFT
) Code
= VK_LSHIFT
;
763 if( Code
== VK_RMENU
) Code
= VK_LMENU
;
764 if( Code
== VK_RCONTROL
) Code
= VK_LCONTROL
;
765 ret
= VkToScan( Code
, FALSE
, keyLayout
);
770 DontDistinguishShifts
771 (IntMapVirtualKeyEx( Code
, 3, keyLayout
) );
777 ret
= VkToScan( Code
, FALSE
, keyLayout
);
778 ToUnicodeInner( Code
, ret
, 0, wp
, 2, 0, keyLayout
);
783 ret
= ScanToVk( Code
, FALSE
, keyLayout
);
792 NtUserMapVirtualKeyEx( UINT Code
, UINT Type
, DWORD keyboardId
, HKL dwhkl
) {
793 PKBDTABLES keyLayout
= PsGetWin32Thread() ?
794 PsGetWin32Thread()->KeyboardLayout
: 0;
796 if( !keyLayout
) return 0;
798 return IntMapVirtualKeyEx( Code
, Type
, keyLayout
);
812 BYTE KeyStateBuf
[0x100];
813 PWCHAR OutPwszBuff
= 0;
817 if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf
,
819 sizeof(KeyStateBuf
))) ) {
820 DPRINT1( "Couldn't copy key state from caller.\n" );
823 OutPwszBuff
= ExAllocatePool(NonPagedPool
,sizeof(WCHAR
) * cchBuff
);
825 DPRINT1( "ExAllocatePool(%d) failed\n", sizeof(WCHAR
) * cchBuff
);
828 RtlZeroMemory( OutPwszBuff
, sizeof( WCHAR
) * cchBuff
);
830 ret
= ToUnicodeEx( wVirtKey
,
838 MmCopyToCaller(pwszBuff
,OutPwszBuff
,sizeof(WCHAR
)*cchBuff
);
839 ExFreePool(OutPwszBuff
);
844 static int W32kSimpleToupper( int ch
) {
845 if( ch
>= 'a' && ch
<= 'z' ) ch
= ch
- 'a' + 'A';
851 NtUserGetKeyNameText( LONG lParam
, LPWSTR lpString
, int nSize
) {
856 UINT ScanCode
= (lParam
>> 16) & 0xff;
857 BOOL ExtKey
= lParam
& (1<<24) ? TRUE
: FALSE
;
858 PKBDTABLES keyLayout
=
860 PsGetWin32Thread()->KeyboardLayout
: 0;
862 if( !keyLayout
|| nSize
< 1 ) return 0;
864 if( lParam
& (1<<25) ) {
865 CareVk
= VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
866 if( VkCode
== VK_LSHIFT
|| VkCode
== VK_RSHIFT
)
868 if( VkCode
== VK_LCONTROL
|| VkCode
== VK_RCONTROL
)
869 VkCode
= VK_LCONTROL
;
870 if( VkCode
== VK_LMENU
|| VkCode
== VK_RMENU
)
873 VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
876 VSC_LPWSTR
*KeyNames
= 0;
878 if( CareVk
!= VkCode
)
879 ScanCode
= VkToScan( VkCode
, ExtKey
, keyLayout
);
882 KeyNames
= keyLayout
->pKeyNamesExt
;
884 KeyNames
= keyLayout
->pKeyNames
;
886 for( i
= 0; KeyNames
[i
].pwsz
; i
++ ) {
887 if( KeyNames
[i
].vsc
== ScanCode
) {
888 UINT StrLen
= wcslen(KeyNames
[i
].pwsz
);
889 UINT StrMax
= StrLen
> (nSize
- 1) ? (nSize
- 1) : StrLen
;
891 if( NT_SUCCESS( MmCopyToCaller( lpString
,
893 StrMax
* sizeof(WCHAR
) ) ) &&
894 NT_SUCCESS( MmCopyToCaller( lpString
+ StrMax
,
896 sizeof( WCHAR
) ) ) ) {
906 UCName
[0] = W32kSimpleToupper(IntMapVirtualKeyEx( VkCode
, 2, keyLayout
));
910 if( !NT_SUCCESS(MmCopyToCaller( lpString
, UCName
, 2 * sizeof(WCHAR
) )) )
917 /* Search the keyboard layout modifiers table for the shift bit. I don't
918 * want to count on the shift bit not moving, because it can be specified
921 static DWORD FASTCALL
GetShiftBit( PKBDTABLES pkKT
) {
924 for( i
= 0; pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
; i
++ )
925 if( pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
== VK_SHIFT
)
926 return pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
932 * Filter this message according to the current key layout, setting wParam
936 VOID FASTCALL
W32kKeyProcessMessage(LPMSG Msg
, PKBDTABLES KeyboardLayout
) {
937 DWORD ScanCode
= 0, ModifierBits
= 0;
939 DWORD BaseMapping
= 0;
941 static WORD NumpadConversion
[][2] =
942 { { VK_DELETE
, VK_DECIMAL
},
943 { VK_INSERT
, VK_NUMPAD0
},
944 { VK_END
, VK_NUMPAD1
},
945 { VK_DOWN
, VK_NUMPAD2
},
946 { VK_NEXT
, VK_NUMPAD3
},
947 { VK_LEFT
, VK_NUMPAD4
},
948 { VK_CLEAR
, VK_NUMPAD5
},
949 { VK_RIGHT
, VK_NUMPAD6
},
950 { VK_HOME
, VK_NUMPAD7
},
951 { VK_UP
, VK_NUMPAD8
},
952 { VK_PRIOR
, VK_NUMPAD9
},
955 if( !KeyboardLayout
|| !Msg
||
956 (Msg
->message
!= WM_KEYDOWN
&& Msg
->message
!= WM_SYSKEYDOWN
&&
957 Msg
->message
!= WM_KEYUP
&& Msg
->message
!= WM_SYSKEYUP
) )
962 ExAcquireFastMutex(&QueueStateLock
);
964 /* arty -- handle numpad -- On real windows, the actual key produced
965 * by the messaging layer is different based on the state of numlock. */
966 ModifierBits
= ModBits(KeyboardLayout
,QueueKeyStateTable
);
968 /* Get the raw scan code, so we can look up whether the key is a numpad
971 * Shift and the LP_EXT_BIT cancel. */
972 ScanCode
= (Msg
->lParam
>> 16) & 0xff;
973 BaseMapping
= Msg
->wParam
=
974 IntMapVirtualKeyEx( ScanCode
, 1, KeyboardLayout
);
975 RawVk
= KeyboardLayout
->pusVSCtoVK
[ScanCode
];
977 if ((ModifierBits
& NUMLOCK_BIT
) &&
978 !(ModifierBits
& GetShiftBit(KeyboardLayout
)) &&
980 !(Msg
->lParam
& LP_EXT_BIT
))
982 /* The key in question is a numpad key. Search for a translation. */
983 for (i
= 0; NumpadConversion
[i
][0]; i
++)
985 if ((BaseMapping
& 0xff) == NumpadConversion
[i
][0]) /* RawVk? */
987 Msg
->wParam
= NumpadConversion
[i
][1];
993 DPRINT("Key: [%04x -> %04x]\n", BaseMapping
, Msg
->wParam
);
995 /* Now that we have the VK, we can set the keymap appropriately
996 * This is a better place for this code, as it's guaranteed to be
997 * run, unlike translate message. */
998 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
)
1000 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
1001 TRUE
); /* Strike key */
1003 else if (Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1005 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
1006 FALSE
); /* Release key */
1009 ExReleaseFastMutex(&QueueStateLock
);