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.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
23 * FILE: subsys/win32k/ntuser/keyboard.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 06-06-2001 CSH Created
29 /* INCLUDES ******************************************************************/
36 /* Directory to load key layouts from */
37 #define SYSTEMROOT_DIR L"\\SystemRoot\\System32\\"
39 #define CAPITAL_BIT 0x80000000
40 #define NUMLOCK_BIT 0x40000000
41 #define MOD_BITS_MASK 0x3fffffff
42 #define MOD_KCTRL 0x02
44 #define KS_DOWN_MASK 0xc0
45 #define KS_DOWN_BIT 0x80
46 #define KS_LOCK_BIT 0x01
48 #define LP_EXT_BIT (1<<24)
49 /* From kbdxx.c -- Key changes with numlock */
52 /* Lock the keyboard state to prevent unusual concurrent access */
53 FAST_MUTEX QueueStateLock
;
55 BYTE QueueKeyStateTable
[256];
57 #define IntLockQueueState \
58 ExAcquireFastMutex(&QueueStateLock)
60 #define IntUnLockQueueState \
61 ExReleaseFastMutex(&QueueStateLock)
63 /* FUNCTIONS *****************************************************************/
65 /* Initialization -- Right now, just zero the key state and init the lock */
66 NTSTATUS FASTCALL
InitKeyboardImpl(VOID
) {
67 ExInitializeFastMutex(&QueueStateLock
);
68 RtlZeroMemory(&QueueKeyStateTable
,0x100);
69 return STATUS_SUCCESS
;
72 /*** Statics used by TranslateMessage ***/
74 /*** Shift state code was out of hand, sorry. --- arty */
76 static UINT
DontDistinguishShifts( UINT ret
) {
77 if( ret
== VK_LSHIFT
|| ret
== VK_RSHIFT
) ret
= VK_LSHIFT
;
78 if( ret
== VK_LCONTROL
|| ret
== VK_RCONTROL
) ret
= VK_LCONTROL
;
79 if( ret
== VK_LMENU
|| ret
== VK_RMENU
) ret
= VK_LMENU
;
83 static VOID STDCALL
SetKeyState(DWORD key
, DWORD vk
, DWORD ext
, BOOL down
) {
86 /* Special handling for toggles like numpad and caps lock */
87 if (vk
== VK_CAPITAL
|| vk
== VK_NUMLOCK
) {
88 if (down
) QueueKeyStateTable
[vk
] ^= KS_LOCK_BIT
;
91 if (ext
&& vk
== VK_LSHIFT
)
93 if (ext
&& vk
== VK_LCONTROL
)
95 if (ext
&& vk
== VK_LMENU
)
99 QueueKeyStateTable
[vk
] |= KS_DOWN_BIT
;
101 QueueKeyStateTable
[vk
] &= ~KS_DOWN_MASK
;
103 if (vk
== VK_LSHIFT
|| vk
== VK_RSHIFT
) {
104 if ((QueueKeyStateTable
[VK_LSHIFT
] & KS_DOWN_BIT
) ||
105 (QueueKeyStateTable
[VK_RSHIFT
] & KS_DOWN_BIT
)) {
106 QueueKeyStateTable
[VK_SHIFT
] |= KS_DOWN_BIT
;
108 QueueKeyStateTable
[VK_SHIFT
] &= ~KS_DOWN_MASK
;
112 if (vk
== VK_LCONTROL
|| vk
== VK_RCONTROL
) {
113 if ((QueueKeyStateTable
[VK_LCONTROL
] & KS_DOWN_BIT
) ||
114 (QueueKeyStateTable
[VK_RCONTROL
] & KS_DOWN_BIT
)) {
115 QueueKeyStateTable
[VK_CONTROL
] |= KS_DOWN_BIT
;
117 QueueKeyStateTable
[VK_CONTROL
] &= ~KS_DOWN_MASK
;
121 if (vk
== VK_LMENU
|| vk
== VK_RMENU
) {
122 if ((QueueKeyStateTable
[VK_LMENU
] & KS_DOWN_BIT
) ||
123 (QueueKeyStateTable
[VK_RMENU
] & KS_DOWN_BIT
)) {
124 QueueKeyStateTable
[VK_MENU
] |= KS_DOWN_BIT
;
126 QueueKeyStateTable
[VK_MENU
] &= ~KS_DOWN_MASK
;
131 VOID
DumpKeyState( PBYTE KeyState
) {
134 DbgPrint( "KeyState { " );
135 for( i
= 0; i
< 0x100; i
++ ) {
136 if( KeyState
[i
] ) DbgPrint( "%02x(%02x) ", i
, KeyState
[i
] );
141 static BYTE
KeysSet( PKBDTABLES pkKT
, PBYTE KeyState
,
142 int FakeModLeft
, int FakeModRight
) {
143 if( !KeyState
|| !pkKT
) return 0;
145 /* Search special codes first */
146 if( FakeModLeft
&& KeyState
[FakeModLeft
] )
147 return KeyState
[FakeModLeft
];
148 else if( FakeModRight
&& KeyState
[FakeModRight
] )
149 return KeyState
[FakeModRight
];
154 /* Search the keyboard layout modifiers table for the shift bit. I don't
155 * want to count on the shift bit not moving, because it can be specified
158 static DWORD FASTCALL
GetShiftBit( PKBDTABLES pkKT
, DWORD Vk
) {
161 for( i
= 0; pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
; i
++ )
162 if( pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
== Vk
)
163 return pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
168 static DWORD
ModBits( PKBDTABLES pkKT
, PBYTE KeyState
) {
171 if( !KeyState
) return 0;
173 /* DumpKeyState( KeyState ); */
175 if (KeysSet( pkKT
, KeyState
, VK_LSHIFT
, VK_RSHIFT
) &
177 ModBits
|= GetShiftBit( pkKT
, VK_SHIFT
);
179 if (KeysSet( pkKT
, KeyState
, VK_LCONTROL
, VK_RCONTROL
) &
181 ModBits
|= GetShiftBit( pkKT
, VK_CONTROL
);
183 if (KeysSet( pkKT
, KeyState
, VK_LMENU
, VK_RMENU
) &
185 ModBits
|= GetShiftBit( pkKT
, VK_MENU
);
188 if (KeysSet( pkKT
, KeyState
, VK_RMENU
, 0 ) &
190 ModBits
|= GetShiftBit( pkKT
, VK_CONTROL
);
192 /* Deal with VK_CAPITAL */
193 if (KeysSet( pkKT
, KeyState
, VK_CAPITAL
, 0 ) & KS_LOCK_BIT
)
195 ModBits
|= CAPITAL_BIT
;
198 /* Deal with VK_NUMLOCK */
199 if (KeysSet( pkKT
, KeyState
, VK_NUMLOCK
, 0 ) & KS_LOCK_BIT
)
201 ModBits
|= NUMLOCK_BIT
;
204 DPRINT( "Current Mod Bits: %x\n", ModBits
);
209 static BOOL
TryToTranslateChar(WORD wVirtKey
,
213 PWCHAR pwcTranslatedChar
,
214 PKBDTABLES keyLayout
)
216 PVK_TO_WCHAR_TABLE vtwTbl
;
217 PVK_TO_WCHARS10 vkPtr
;
218 size_t size_this_entry
;
220 DWORD CapsMod
= 0, CapsState
= 0;
222 CapsState
= ModBits
& ~MOD_BITS_MASK
;
223 ModBits
= ModBits
& MOD_BITS_MASK
;
225 DPRINT ( "TryToTranslate: %04x %x\n", wVirtKey
, ModBits
);
227 if (ModBits
> keyLayout
->pCharModifiers
->wMaxModBits
)
231 for (nMod
= 0; keyLayout
->pVkToWcharTable
[nMod
].nModifications
; nMod
++)
233 vtwTbl
= &keyLayout
->pVkToWcharTable
[nMod
];
234 size_this_entry
= vtwTbl
->cbSize
;
235 vkPtr
= (PVK_TO_WCHARS10
)((BYTE
*)vtwTbl
->pVkToWchars
);
236 while(vkPtr
->VirtualKey
)
238 if( wVirtKey
== (vkPtr
->VirtualKey
& 0xff) )
240 CapsMod
= keyLayout
->pCharModifiers
->ModNumber
242 ((CapsState
& CAPITAL_BIT
) ? vkPtr
->Attributes
: 0)];
244 if( CapsMod
> keyLayout
->pVkToWcharTable
[nMod
].nModifications
) {
247 keyLayout
->pVkToWcharTable
[nMod
].nModifications
)
250 CapsMod
&= MaxBit
- 1; /* Guarantee that CapsMod lies
254 *pbDead
= vkPtr
->wch
[CapsMod
] == WCH_DEAD
;
255 *pbLigature
= vkPtr
->wch
[CapsMod
] == WCH_LGTR
;
256 *pwcTranslatedChar
= vkPtr
->wch
[CapsMod
];
258 DPRINT("%d %04x: CapsMod %08x CapsState %08x Char %04x\n",
260 CapsMod
, CapsState
, *pwcTranslatedChar
);
264 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
265 if( vkPtr
->VirtualKey
!= 0xff )
267 DPRINT( "Found dead key with no trailer in the table.\n" );
268 DPRINT( "VK: %04x, ADDR: %08x\n", wVirtKey
, (int)vkPtr
);
271 *pwcTranslatedChar
= vkPtr
->wch
[CapsMod
];
275 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
283 ToUnicodeInner(UINT wVirtKey
,
291 WCHAR wcTranslatedChar
;
295 if( !pkKT
) return 0;
297 if( TryToTranslateChar( wVirtKey
,
298 ModBits( pkKT
, lpKeyState
),
306 DPRINT("Not handling ligature (yet)\n" );
310 if( cchBuff
> 0 ) pwszBuff
[0] = wcTranslatedChar
;
312 return bDead
? -1 : 1;
327 ret
= ((DWORD
)(QueueKeyStateTable
[key
] & KS_DOWN_BIT
) << 8 ) |
328 (QueueKeyStateTable
[key
] & KS_LOCK_BIT
);
334 int STDCALL
ToUnicodeEx( UINT wVirtKey
,
341 int ToUnicodeResult
= 0;
343 if (0 == (lpKeyState
[wVirtKey
] & KS_DOWN_BIT
))
350 ToUnicodeResult
= ToUnicodeInner( wVirtKey
,
357 PsGetWin32Thread()->KeyboardLayout
: 0 );
361 return ToUnicodeResult
;
364 int STDCALL
ToUnicode( UINT wVirtKey
,
370 return ToUnicodeEx( wVirtKey
,
380 * Utility to copy and append two unicode strings.
382 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
383 * IN PUNICODE_STRING Second -> Second string to append
384 * IN BOOL Deallocate -> TRUE: Deallocate First string before
390 NTSTATUS NTAPI
AppendUnicodeString(PUNICODE_STRING ResultFirst
,
391 PUNICODE_STRING Second
,
395 ExAllocatePoolWithTag(PagedPool
,
396 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)),
399 return STATUS_NO_MEMORY
;
401 memcpy( new_string
, ResultFirst
->Buffer
,
402 ResultFirst
->Length
);
403 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
406 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
407 ResultFirst
->Length
+= Second
->Length
;
408 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
409 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
410 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
411 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
412 ExFreePool(new_string
);
417 * Utility function to read a value from the registry more easily.
419 * IN PUNICODE_STRING KeyName -> Name of key to open
420 * IN PUNICODE_STRING ValueName -> Name of value to open
421 * OUT PUNICODE_STRING ReturnedValue -> String contained in registry
426 static NTSTATUS NTAPI
ReadRegistryValue( PUNICODE_STRING KeyName
,
427 PUNICODE_STRING ValueName
,
428 PUNICODE_STRING ReturnedValue
) {
431 OBJECT_ATTRIBUTES KeyAttributes
;
432 PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo
;
437 InitializeObjectAttributes(&KeyAttributes
, KeyName
, OBJ_CASE_INSENSITIVE
,
439 Status
= ZwOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &KeyAttributes
);
440 if( !NT_SUCCESS(Status
) ) {
444 Status
= ZwQueryValueKey(KeyHandle
, ValueName
, KeyValuePartialInformation
,
449 if( Status
!= STATUS_BUFFER_TOO_SMALL
) {
454 ResLength
+= sizeof( *KeyValuePartialInfo
);
455 KeyValuePartialInfo
=
456 ExAllocatePoolWithTag(PagedPool
, ResLength
, TAG_STRING
);
459 if( !KeyValuePartialInfo
) {
461 return STATUS_NO_MEMORY
;
464 Status
= ZwQueryValueKey(KeyHandle
, ValueName
, KeyValuePartialInformation
,
465 (PVOID
)KeyValuePartialInfo
,
469 if( !NT_SUCCESS(Status
) ) {
471 ExFreePool(KeyValuePartialInfo
);
475 Temp
.Length
= Temp
.MaximumLength
= KeyValuePartialInfo
->DataLength
;
476 Temp
.Buffer
= (PWCHAR
)KeyValuePartialInfo
->Data
;
478 /* At this point, KeyValuePartialInfo->Data contains the key data */
479 RtlInitUnicodeString(ReturnedValue
,L
"");
480 AppendUnicodeString(ReturnedValue
,&Temp
,FALSE
);
482 ExFreePool(KeyValuePartialInfo
);
488 typedef PVOID (*KbdLayerDescriptor
)(VOID
);
489 NTSTATUS STDCALL
LdrGetProcedureAddress(PVOID module
,
490 PANSI_STRING import_name
,
494 void InitKbdLayout( PVOID
*pkKeyboardLayout
)
496 WCHAR LocaleBuffer
[16];
497 UNICODE_STRING LayoutKeyName
;
498 UNICODE_STRING LayoutValueName
;
499 UNICODE_STRING DefaultLocale
;
500 UNICODE_STRING LayoutFile
;
501 UNICODE_STRING FullLayoutPath
;
503 PWCHAR KeyboardLayoutWSTR
;
504 HMODULE kbModule
= 0;
506 ANSI_STRING kbdProcedureName
;
507 KbdLayerDescriptor layerDescGetFn
;
509 #define XX_STATUS(x) if (!NT_SUCCESS(Status = (x))) continue;
512 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
513 if (!NT_SUCCESS(Status
))
515 DPRINT1("Could not get default locale (%08lx).\n", Status
);
519 DPRINT("DefaultLocale = %lx\n", LocaleId
);
520 swprintf(LocaleBuffer
, L
"%08lx", LocaleId
);
521 DPRINT("DefaultLocale = %S\n", LocaleBuffer
);
522 RtlInitUnicodeString(&DefaultLocale
, LocaleBuffer
);
524 RtlInitUnicodeString(&LayoutKeyName
,
525 L
"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet"
526 L
"\\Control\\KeyboardLayouts\\");
528 AppendUnicodeString(&LayoutKeyName
,&DefaultLocale
,FALSE
);
530 RtlInitUnicodeString(&LayoutValueName
,L
"Layout File");
532 Status
= ReadRegistryValue(&LayoutKeyName
,&LayoutValueName
,&LayoutFile
);
533 RtlInitUnicodeString(&FullLayoutPath
,SYSTEMROOT_DIR
);
535 if( !NT_SUCCESS(Status
) ) {
536 DPRINT1("Got default locale but not layout file. (%08lx)\n",
539 DPRINT("Read registry and got %wZ\n", &LayoutFile
);
541 RtlFreeUnicodeString(&LayoutKeyName
);
543 AppendUnicodeString(&FullLayoutPath
,&LayoutFile
,FALSE
);
545 DPRINT("Loading Keyboard DLL %wZ\n", &FullLayoutPath
);
547 RtlFreeUnicodeString(&LayoutFile
);
550 ExAllocatePoolWithTag(PagedPool
,
551 FullLayoutPath
.Length
+ sizeof(WCHAR
),
554 if( !KeyboardLayoutWSTR
) {
555 DPRINT1("Couldn't allocate a string for the keyboard layout name.\n");
556 RtlFreeUnicodeString(&FullLayoutPath
);
559 memcpy(KeyboardLayoutWSTR
,FullLayoutPath
.Buffer
,
560 FullLayoutPath
.Length
+ sizeof(WCHAR
));
561 KeyboardLayoutWSTR
[FullLayoutPath
.Length
/ sizeof(WCHAR
)] = 0;
563 kbModule
= EngLoadImage(KeyboardLayoutWSTR
);
564 DPRINT( "Load Keyboard Layout: %S\n", KeyboardLayoutWSTR
);
567 DPRINT1( "Load Keyboard Layout: No %wZ\n", &FullLayoutPath
);
569 RtlFreeUnicodeString(&FullLayoutPath
);
575 DPRINT1("Trying to load US Keyboard Layout\n");
576 kbModule
= EngLoadImage(L
"\\SystemRoot\\system32\\kbdus.dll");
580 DPRINT1("Failed to load any Keyboard Layout\n");
585 RtlInitAnsiString( &kbdProcedureName
, "KbdLayerDescriptor" );
587 LdrGetProcedureAddress((PVOID
)kbModule
,
590 (PVOID
*)&layerDescGetFn
);
592 if( layerDescGetFn
) {
593 *pkKeyboardLayout
= layerDescGetFn();
597 if( !*pkKeyboardLayout
) {
598 DPRINT1("Failed to load the keyboard layout.\n");
604 PKBDTABLES
W32kGetDefaultKeyLayout() {
605 PKBDTABLES pkKeyboardLayout
= 0;
606 InitKbdLayout( (PVOID
) &pkKeyboardLayout
);
607 return pkKeyboardLayout
;
611 IntTranslateKbdMessage(LPMSG lpMsg
,
614 static INT dead_char
= 0;
618 PKBDTABLES keyLayout
;
623 keyLayout
= PsGetWin32Thread()->KeyboardLayout
;
627 if (lpMsg
->message
!= WM_KEYDOWN
&& lpMsg
->message
!= WM_SYSKEYDOWN
)
630 ScanCode
= (lpMsg
->lParam
>> 16) & 0xff;
634 /* All messages have to contain the cursor point. */
635 IntGetCursorLocation(PsGetWin32Thread()->Desktop
->WindowStation
,
638 UState
= ToUnicodeInner(lpMsg
->wParam
, HIWORD(lpMsg
->lParam
) & 0xff,
639 QueueKeyStateTable
, wp
, 2, 0,
644 NewMsg
.message
= (lpMsg
->message
== WM_KEYDOWN
) ? WM_CHAR
: WM_SYSCHAR
;
649 DPRINT("PREVIOUS DEAD CHAR: %c\n", dead_char
);
651 for( i
= 0; keyLayout
->pDeadKey
[i
].dwBoth
; i
++ )
653 first
= keyLayout
->pDeadKey
[i
].dwBoth
>> 16;
654 second
= keyLayout
->pDeadKey
[i
].dwBoth
;
655 if (first
== dead_char
&& second
== wp
[0])
657 wp
[0] = keyLayout
->pDeadKey
[i
].wchComposed
;
663 DPRINT("FINAL CHAR: %c\n", wp
[0]);
668 NewMsg
.hwnd
= lpMsg
->hwnd
;
669 NewMsg
.wParam
= dead_char
;
670 NewMsg
.lParam
= lpMsg
->lParam
;
672 MsqPostMessage(PsGetWin32Thread()->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
675 NewMsg
.hwnd
= lpMsg
->hwnd
;
676 NewMsg
.wParam
= wp
[0];
677 NewMsg
.lParam
= lpMsg
->lParam
;
678 DPRINT( "CHAR='%c' %04x %08x\n", wp
[0], wp
[0], lpMsg
->lParam
);
679 MsqPostMessage(PsGetWin32Thread()->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
682 else if (UState
== -1)
685 (lpMsg
->message
== WM_KEYDOWN
) ? WM_DEADCHAR
: WM_SYSDEADCHAR
;
686 NewMsg
.hwnd
= lpMsg
->hwnd
;
687 NewMsg
.wParam
= wp
[0];
688 NewMsg
.lParam
= lpMsg
->lParam
;
690 MsqPostMessage(PsGetWin32Thread()->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
700 NtUserGetKeyboardState(
707 if(!NT_SUCCESS(MmCopyToCaller(lpKeyState
, QueueKeyStateTable
, 256)))
716 NtUserSetKeyboardState(
723 if(! NT_SUCCESS(MmCopyFromCaller(QueueKeyStateTable
, lpKeyState
, 256)))
731 static UINT
VkToScan( UINT Code
, BOOL ExtCode
, PKBDTABLES pkKT
) {
734 for( i
= 0; i
< pkKT
->bMaxVSCtoVK
; i
++ ) {
735 if( pkKT
->pusVSCtoVK
[i
] == Code
) { return i
; }
741 UINT
ScanToVk( UINT Code
, BOOL ExtKey
, PKBDTABLES pkKT
) {
743 DPRINT("ScanToVk: No layout\n");
750 for( i
= 0; pkKT
->pVSCtoVK_E0
[i
].Vsc
; i
++ ) {
751 if( pkKT
->pVSCtoVK_E0
[i
].Vsc
== Code
)
752 return pkKT
->pVSCtoVK_E0
[i
].Vk
& 0xff;
754 for( i
= 0; pkKT
->pVSCtoVK_E1
[i
].Vsc
; i
++ ) {
755 if( pkKT
->pVSCtoVK_E1
[i
].Vsc
== Code
)
756 return pkKT
->pVSCtoVK_E1
[i
].Vk
& 0xff;
761 if( Code
>= pkKT
->bMaxVSCtoVK
) { return 0; }
762 return pkKT
->pusVSCtoVK
[Code
] & 0xff;
767 * Map a virtual key code, or virtual scan code, to a scan code, key code,
768 * or unshifted unicode character.
772 * 0 -- Code is a virtual key code that is converted into a virtual scan code
773 * that does not distinguish between left and right shift keys.
774 * 1 -- Code is a virtual scan code that is converted into a virtual key code
775 * that does not distinguish between left and right shift keys.
776 * 2 -- Code is a virtual key code that is converted into an unshifted unicode
778 * 3 -- Code is a virtual scan code that is converted into a virtual key code
779 * that distinguishes left and right shift keys.
780 * KeyLayout: Keyboard layout handle (currently, unused)
785 static UINT
IntMapVirtualKeyEx( UINT Code
, UINT Type
, PKBDTABLES keyLayout
) {
790 if( Code
== VK_RSHIFT
) Code
= VK_LSHIFT
;
791 if( Code
== VK_RMENU
) Code
= VK_LMENU
;
792 if( Code
== VK_RCONTROL
) Code
= VK_LCONTROL
;
793 ret
= VkToScan( Code
, FALSE
, keyLayout
);
798 DontDistinguishShifts
799 (IntMapVirtualKeyEx( Code
, 3, keyLayout
) );
805 ret
= VkToScan( Code
, FALSE
, keyLayout
);
806 ToUnicodeInner( Code
, ret
, 0, wp
, 2, 0, keyLayout
);
812 ret
= ScanToVk( Code
, FALSE
, keyLayout
);
821 NtUserMapVirtualKeyEx( UINT Code
, UINT Type
, DWORD keyboardId
, HKL dwhkl
) {
822 PKBDTABLES keyLayout
= PsGetWin32Thread() ?
823 PsGetWin32Thread()->KeyboardLayout
: 0;
825 if( !keyLayout
) return 0;
827 return IntMapVirtualKeyEx( Code
, Type
, keyLayout
);
841 BYTE KeyStateBuf
[0x100];
842 PWCHAR OutPwszBuff
= 0;
846 if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf
,
848 sizeof(KeyStateBuf
))) ) {
849 DPRINT1( "Couldn't copy key state from caller.\n" );
852 OutPwszBuff
= ExAllocatePoolWithTag(NonPagedPool
,sizeof(WCHAR
) * cchBuff
, TAG_STRING
);
854 DPRINT1( "ExAllocatePool(%d) failed\n", sizeof(WCHAR
) * cchBuff
);
857 RtlZeroMemory( OutPwszBuff
, sizeof( WCHAR
) * cchBuff
);
859 ret
= ToUnicodeEx( wVirtKey
,
867 MmCopyToCaller(pwszBuff
,OutPwszBuff
,sizeof(WCHAR
)*cchBuff
);
868 ExFreePool(OutPwszBuff
);
873 static int W32kSimpleToupper( int ch
) {
874 if( ch
>= 'a' && ch
<= 'z' ) ch
= ch
- 'a' + 'A';
880 NtUserGetKeyNameText( LONG lParam
, LPWSTR lpString
, int nSize
) {
885 UINT ScanCode
= (lParam
>> 16) & 0xff;
886 BOOL ExtKey
= lParam
& (1<<24) ? TRUE
: FALSE
;
887 PKBDTABLES keyLayout
=
889 PsGetWin32Thread()->KeyboardLayout
: 0;
891 if( !keyLayout
|| nSize
< 1 ) return 0;
893 if( lParam
& (1<<25) ) {
894 CareVk
= VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
895 if( VkCode
== VK_LSHIFT
|| VkCode
== VK_RSHIFT
)
897 if( VkCode
== VK_LCONTROL
|| VkCode
== VK_RCONTROL
)
898 VkCode
= VK_LCONTROL
;
899 if( VkCode
== VK_LMENU
|| VkCode
== VK_RMENU
)
902 VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
905 VSC_LPWSTR
*KeyNames
= 0;
907 if( CareVk
!= VkCode
)
908 ScanCode
= VkToScan( VkCode
, ExtKey
, keyLayout
);
911 KeyNames
= keyLayout
->pKeyNamesExt
;
913 KeyNames
= keyLayout
->pKeyNames
;
915 for( i
= 0; KeyNames
[i
].pwsz
; i
++ ) {
916 if( KeyNames
[i
].vsc
== ScanCode
) {
917 UINT StrLen
= wcslen(KeyNames
[i
].pwsz
);
918 UINT StrMax
= StrLen
> (nSize
- 1) ? (nSize
- 1) : StrLen
;
920 if( NT_SUCCESS( MmCopyToCaller( lpString
,
922 StrMax
* sizeof(WCHAR
) ) ) &&
923 NT_SUCCESS( MmCopyToCaller( lpString
+ StrMax
,
925 sizeof( WCHAR
) ) ) ) {
935 UCName
[0] = W32kSimpleToupper(IntMapVirtualKeyEx( VkCode
, 2, keyLayout
));
939 if( !NT_SUCCESS(MmCopyToCaller( lpString
, UCName
, 2 * sizeof(WCHAR
) )) )
947 * Filter this message according to the current key layout, setting wParam
951 VOID FASTCALL
W32kKeyProcessMessage(LPMSG Msg
, PKBDTABLES KeyboardLayout
) {
952 DWORD ScanCode
= 0, ModifierBits
= 0;
954 DWORD BaseMapping
= 0;
956 static WORD NumpadConversion
[][2] =
957 { { VK_DELETE
, VK_DECIMAL
},
958 { VK_INSERT
, VK_NUMPAD0
},
959 { VK_END
, VK_NUMPAD1
},
960 { VK_DOWN
, VK_NUMPAD2
},
961 { VK_NEXT
, VK_NUMPAD3
},
962 { VK_LEFT
, VK_NUMPAD4
},
963 { VK_CLEAR
, VK_NUMPAD5
},
964 { VK_RIGHT
, VK_NUMPAD6
},
965 { VK_HOME
, VK_NUMPAD7
},
966 { VK_UP
, VK_NUMPAD8
},
967 { VK_PRIOR
, VK_NUMPAD9
},
970 if( !KeyboardLayout
|| !Msg
||
971 (Msg
->message
!= WM_KEYDOWN
&& Msg
->message
!= WM_SYSKEYDOWN
&&
972 Msg
->message
!= WM_KEYUP
&& Msg
->message
!= WM_SYSKEYUP
) )
979 /* arty -- handle numpad -- On real windows, the actual key produced
980 * by the messaging layer is different based on the state of numlock. */
981 ModifierBits
= ModBits(KeyboardLayout
,QueueKeyStateTable
);
983 /* Get the raw scan code, so we can look up whether the key is a numpad
986 * Shift and the LP_EXT_BIT cancel. */
987 ScanCode
= (Msg
->lParam
>> 16) & 0xff;
988 BaseMapping
= Msg
->wParam
=
989 IntMapVirtualKeyEx( ScanCode
, 1, KeyboardLayout
);
990 if( ScanCode
>= KeyboardLayout
->bMaxVSCtoVK
)
993 RawVk
= KeyboardLayout
->pusVSCtoVK
[ScanCode
];
995 if ((ModifierBits
& NUMLOCK_BIT
) &&
996 !(ModifierBits
& GetShiftBit(KeyboardLayout
, VK_SHIFT
)) &&
998 !(Msg
->lParam
& LP_EXT_BIT
))
1000 /* The key in question is a numpad key. Search for a translation. */
1001 for (i
= 0; NumpadConversion
[i
][0]; i
++)
1003 if ((BaseMapping
& 0xff) == NumpadConversion
[i
][0]) /* RawVk? */
1005 Msg
->wParam
= NumpadConversion
[i
][1];
1011 DPRINT("Key: [%04x -> %04x]\n", BaseMapping
, Msg
->wParam
);
1013 /* Now that we have the VK, we can set the keymap appropriately
1014 * This is a better place for this code, as it's guaranteed to be
1015 * run, unlike translate message. */
1016 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
)
1018 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
1019 TRUE
); /* Strike key */
1021 else if (Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1023 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
1024 FALSE
); /* Release key */
1027 /* We need to unset SYSKEYDOWN if the ALT key is an ALT+Gr */
1028 if( QueueKeyStateTable
[VK_RMENU
] & KS_DOWN_BIT
) {
1029 if( Msg
->message
== WM_SYSKEYDOWN
) Msg
->message
= WM_KEYDOWN
;
1030 else Msg
->message
= WM_KEYUP
;
1033 IntUnLockQueueState
;