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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 ******************************************************************/
38 #define CAPITAL_BIT 0x80000000
39 #define NUMLOCK_BIT 0x40000000
40 #define MOD_BITS_MASK 0x3fffffff
41 #define MOD_KCTRL 0x02
43 #define KS_DOWN_MASK 0xc0
44 #define KS_DOWN_BIT 0x80
45 #define KS_LOCK_BIT 0x01
47 #define LP_EXT_BIT (1<<24)
48 /* From kbdxx.c -- Key changes with numlock */
52 BYTE gQueueKeyStateTable
[256];
56 /* FUNCTIONS *****************************************************************/
58 /* Initialization -- Right now, just zero the key state and init the lock */
59 NTSTATUS FASTCALL
InitKeyboardImpl(VOID
)
61 RtlZeroMemory(&gQueueKeyStateTable
,0x100);
62 return STATUS_SUCCESS
;
65 /*** Statics used by TranslateMessage ***/
67 /*** Shift state code was out of hand, sorry. --- arty */
69 static UINT
DontDistinguishShifts( UINT ret
)
71 if( ret
== VK_LSHIFT
|| ret
== VK_RSHIFT
)
73 if( ret
== VK_LCONTROL
|| ret
== VK_RCONTROL
)
75 if( ret
== VK_LMENU
|| ret
== VK_RMENU
)
80 static VOID APIENTRY
SetKeyState(DWORD key
, DWORD vk
, DWORD ext
, BOOL down
)
84 /* Special handling for toggles like numpad and caps lock */
85 if (vk
== VK_CAPITAL
|| vk
== VK_NUMLOCK
)
88 gQueueKeyStateTable
[vk
] ^= KS_LOCK_BIT
;
91 if (ext
&& vk
== VK_LSHIFT
)
93 if (ext
&& vk
== VK_LCONTROL
)
95 if (ext
&& vk
== VK_LMENU
)
99 gQueueKeyStateTable
[vk
] |= KS_DOWN_BIT
;
101 gQueueKeyStateTable
[vk
] &= ~KS_DOWN_MASK
;
103 if (vk
== VK_LSHIFT
|| vk
== VK_RSHIFT
)
105 if ((gQueueKeyStateTable
[VK_LSHIFT
] & KS_DOWN_BIT
) ||
106 (gQueueKeyStateTable
[VK_RSHIFT
] & KS_DOWN_BIT
))
108 gQueueKeyStateTable
[VK_SHIFT
] |= KS_DOWN_BIT
;
112 gQueueKeyStateTable
[VK_SHIFT
] &= ~KS_DOWN_MASK
;
116 if (vk
== VK_LCONTROL
|| vk
== VK_RCONTROL
)
118 if ((gQueueKeyStateTable
[VK_LCONTROL
] & KS_DOWN_BIT
) ||
119 (gQueueKeyStateTable
[VK_RCONTROL
] & KS_DOWN_BIT
))
121 gQueueKeyStateTable
[VK_CONTROL
] |= KS_DOWN_BIT
;
125 gQueueKeyStateTable
[VK_CONTROL
] &= ~KS_DOWN_MASK
;
129 if (vk
== VK_LMENU
|| vk
== VK_RMENU
)
131 if ((gQueueKeyStateTable
[VK_LMENU
] & KS_DOWN_BIT
) ||
132 (gQueueKeyStateTable
[VK_RMENU
] & KS_DOWN_BIT
))
134 gQueueKeyStateTable
[VK_MENU
] |= KS_DOWN_BIT
;
138 gQueueKeyStateTable
[VK_MENU
] &= ~KS_DOWN_MASK
;
143 VOID
DumpKeyState( PBYTE KeyState
)
147 DbgPrint( "KeyState { " );
148 for( i
= 0; i
< 0x100; i
++ )
151 DbgPrint( "%02x(%02x) ", i
, KeyState
[i
] );
156 static BYTE
KeysSet( PKBDTABLES pkKT
, PBYTE KeyState
,
157 int FakeModLeft
, int FakeModRight
)
159 if( !KeyState
|| !pkKT
)
162 /* Search special codes first */
163 if( FakeModLeft
&& KeyState
[FakeModLeft
] )
164 return KeyState
[FakeModLeft
];
165 else if( FakeModRight
&& KeyState
[FakeModRight
] )
166 return KeyState
[FakeModRight
];
171 /* Search the keyboard layout modifiers table for the shift bit. I don't
172 * want to count on the shift bit not moving, because it can be specified
175 static DWORD FASTCALL
GetShiftBit( PKBDTABLES pkKT
, DWORD Vk
)
179 for( i
= 0; pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
; i
++ )
180 if( pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
== Vk
)
181 return pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
186 static DWORD
ModBits( PKBDTABLES pkKT
, PBYTE KeyState
)
193 /* DumpKeyState( KeyState ); */
195 if (KeysSet( pkKT
, KeyState
, VK_LSHIFT
, VK_RSHIFT
) &
197 ModBits
|= GetShiftBit( pkKT
, VK_SHIFT
);
199 if (KeysSet( pkKT
, KeyState
, VK_SHIFT
, 0 ) &
201 ModBits
|= GetShiftBit( pkKT
, VK_SHIFT
);
203 if (KeysSet( pkKT
, KeyState
, VK_LCONTROL
, VK_RCONTROL
) &
205 ModBits
|= GetShiftBit( pkKT
, VK_CONTROL
);
207 if (KeysSet( pkKT
, KeyState
, VK_CONTROL
, 0 ) &
209 ModBits
|= GetShiftBit( pkKT
, VK_CONTROL
);
211 if (KeysSet( pkKT
, KeyState
, VK_LMENU
, VK_RMENU
) &
213 ModBits
|= GetShiftBit( pkKT
, VK_MENU
);
216 if (pkKT
->fLocalFlags
& 0x1)
217 if (KeysSet( pkKT
, KeyState
, VK_RMENU
, 0 ) &
219 ModBits
|= GetShiftBit( pkKT
, VK_CONTROL
);
221 /* Deal with VK_CAPITAL */
222 if (KeysSet( pkKT
, KeyState
, VK_CAPITAL
, 0 ) & KS_LOCK_BIT
)
224 ModBits
|= CAPITAL_BIT
;
227 /* Deal with VK_NUMLOCK */
228 if (KeysSet( pkKT
, KeyState
, VK_NUMLOCK
, 0 ) & KS_LOCK_BIT
)
230 ModBits
|= NUMLOCK_BIT
;
233 DPRINT( "Current Mod Bits: %x\n", ModBits
);
238 static BOOL
TryToTranslateChar(WORD wVirtKey
,
242 PWCHAR pwcTranslatedChar
,
243 PKBDTABLES keyLayout
)
245 PVK_TO_WCHAR_TABLE vtwTbl
;
246 PVK_TO_WCHARS10 vkPtr
;
247 size_t size_this_entry
;
249 DWORD CapsMod
= 0, CapsState
= 0;
251 CapsState
= ModBits
& ~MOD_BITS_MASK
;
252 ModBits
= ModBits
& MOD_BITS_MASK
;
254 DPRINT ( "TryToTranslate: %04x %x\n", wVirtKey
, ModBits
);
256 if (ModBits
> keyLayout
->pCharModifiers
->wMaxModBits
)
261 for (nMod
= 0; keyLayout
->pVkToWcharTable
[nMod
].nModifications
; nMod
++)
263 vtwTbl
= &keyLayout
->pVkToWcharTable
[nMod
];
264 size_this_entry
= vtwTbl
->cbSize
;
265 vkPtr
= (PVK_TO_WCHARS10
)((BYTE
*)vtwTbl
->pVkToWchars
);
266 while(vkPtr
->VirtualKey
)
268 if( wVirtKey
== (vkPtr
->VirtualKey
& 0xff) )
270 CapsMod
= keyLayout
->pCharModifiers
->ModNumber
272 ((CapsState
& CAPITAL_BIT
) ? vkPtr
->Attributes
: 0)];
274 if( CapsMod
>= keyLayout
->pVkToWcharTable
[nMod
].nModifications
)
279 if( vkPtr
->wch
[CapsMod
] == WCH_NONE
)
284 *pbDead
= vkPtr
->wch
[CapsMod
] == WCH_DEAD
;
285 *pbLigature
= vkPtr
->wch
[CapsMod
] == WCH_LGTR
;
286 *pwcTranslatedChar
= vkPtr
->wch
[CapsMod
];
288 DPRINT("%d %04x: CapsMod %08x CapsState %08x Char %04x\n",
290 CapsMod
, CapsState
, *pwcTranslatedChar
);
294 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
295 if( vkPtr
->VirtualKey
!= 0xff )
297 DPRINT( "Found dead key with no trailer in the table.\n" );
298 DPRINT( "VK: %04x, ADDR: %p\n", wVirtKey
, vkPtr
);
301 *pwcTranslatedChar
= vkPtr
->wch
[CapsMod
];
305 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
313 ToUnicodeInner(UINT wVirtKey
,
321 WCHAR wcTranslatedChar
;
328 if( TryToTranslateChar( wVirtKey
,
329 ModBits( pkKT
, lpKeyState
),
337 DPRINT("Not handling ligature (yet)\n" );
342 pwszBuff
[0] = wcTranslatedChar
;
344 return bDead
? -1 : 1;
351 DWORD FASTCALL
UserGetKeyState(DWORD key
)
357 ret
= ((DWORD
)(gQueueKeyStateTable
[key
] & KS_DOWN_BIT
) << 8 ) |
358 (gQueueKeyStateTable
[key
] & KS_LOCK_BIT
);
370 DECLARE_RETURN(DWORD
);
372 DPRINT("Enter NtUserGetKeyState\n");
373 UserEnterExclusive();
375 RETURN(UserGetKeyState(key
));
378 DPRINT("Leave NtUserGetKeyState, ret=%i\n",_ret_
);
385 DWORD FASTCALL
UserGetAsyncKeyState(DWORD key
)
391 ret
= ((DWORD
)(gQueueKeyStateTable
[key
] & KS_DOWN_BIT
) << 8 ) |
392 (gQueueKeyStateTable
[key
] & KS_LOCK_BIT
);
402 NtUserGetAsyncKeyState(
405 DECLARE_RETURN(SHORT
);
407 DPRINT("Enter NtUserGetAsyncKeyState\n");
408 UserEnterExclusive();
410 RETURN((SHORT
)UserGetAsyncKeyState(key
));
413 DPRINT("Leave NtUserGetAsyncKeyState, ret=%i\n",_ret_
);
421 IntTranslateKbdMessage(LPMSG lpMsg
,
425 static INT dead_char
= 0;
429 PKBDTABLES keyLayout
;
433 pti
= PsGetCurrentThreadWin32Thread();
434 keyLayout
= pti
->KeyboardLayout
->KBTables
;
438 if (lpMsg
->message
< WM_KEYFIRST
|| lpMsg
->message
> WM_KEYLAST
)
440 if (lpMsg
->message
!= WM_KEYDOWN
&& lpMsg
->message
!= WM_SYSKEYDOWN
)
443 /* All messages have to contain the cursor point. */
444 IntGetCursorLocation(pti
->Desktop
->WindowStation
,
447 switch (lpMsg
->wParam
)
450 NewMsg
.message
= (lpMsg
->message
== WM_KEYDOWN
) ? WM_CHAR
: WM_SYSCHAR
;
451 NewMsg
.hwnd
= lpMsg
->hwnd
;
452 NewMsg
.wParam
= HIWORD(lpMsg
->lParam
);
453 NewMsg
.lParam
= LOWORD(lpMsg
->lParam
);
454 MsqPostMessage(pti
->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
458 ScanCode
= (lpMsg
->lParam
>> 16) & 0xff;
460 UState
= ToUnicodeInner(lpMsg
->wParam
, HIWORD(lpMsg
->lParam
) & 0xff,
461 gQueueKeyStateTable
, wp
, 2, 0,
466 NewMsg
.message
= (lpMsg
->message
== WM_KEYDOWN
) ? WM_CHAR
: WM_SYSCHAR
;
471 DPRINT("PREVIOUS DEAD CHAR: %c\n", dead_char
);
473 for( i
= 0; keyLayout
->pDeadKey
[i
].dwBoth
; i
++ )
475 first
= keyLayout
->pDeadKey
[i
].dwBoth
>> 16;
476 second
= keyLayout
->pDeadKey
[i
].dwBoth
;
477 if (first
== dead_char
&& second
== wp
[0])
479 wp
[0] = keyLayout
->pDeadKey
[i
].wchComposed
;
485 DPRINT("FINAL CHAR: %c\n", wp
[0]);
490 NewMsg
.hwnd
= lpMsg
->hwnd
;
491 NewMsg
.wParam
= dead_char
;
492 NewMsg
.lParam
= lpMsg
->lParam
;
494 MsqPostMessage(pti
->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
497 NewMsg
.hwnd
= lpMsg
->hwnd
;
498 NewMsg
.wParam
= wp
[0];
499 NewMsg
.lParam
= lpMsg
->lParam
;
500 DPRINT( "CHAR='%c' %04x %08x\n", wp
[0], wp
[0], lpMsg
->lParam
);
501 MsqPostMessage(pti
->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
504 else if (UState
== -1)
507 (lpMsg
->message
== WM_KEYDOWN
) ? WM_DEADCHAR
: WM_SYSDEADCHAR
;
508 NewMsg
.hwnd
= lpMsg
->hwnd
;
509 NewMsg
.wParam
= wp
[0];
510 NewMsg
.lParam
= lpMsg
->lParam
;
512 MsqPostMessage(pti
->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
521 NtUserGetKeyboardState(
525 DECLARE_RETURN(DWORD
);
527 DPRINT("Enter NtUserGetKeyboardState\n");
532 if(!NT_SUCCESS(MmCopyToCaller(lpKeyState
, gQueueKeyStateTable
, 256)))
539 DPRINT("Leave NtUserGetKeyboardState, ret=%i\n",_ret_
);
546 NtUserSetKeyboardState(LPBYTE lpKeyState
)
549 DECLARE_RETURN(DWORD
);
551 DPRINT("Enter NtUserSetKeyboardState\n");
552 UserEnterExclusive();
556 if(! NT_SUCCESS(MmCopyFromCaller(gQueueKeyStateTable
, lpKeyState
, 256)))
563 DPRINT("Leave NtUserSetKeyboardState, ret=%i\n",_ret_
);
568 static UINT
VkToScan( UINT Code
, BOOL ExtCode
, PKBDTABLES pkKT
)
572 for( i
= 0; i
< pkKT
->bMaxVSCtoVK
; i
++ )
574 if( pkKT
->pusVSCtoVK
[i
] == Code
)
583 UINT
ScanToVk( UINT Code
, BOOL ExtKey
, PKBDTABLES pkKT
)
587 DPRINT("ScanToVk: No layout\n");
595 for( i
= 0; pkKT
->pVSCtoVK_E0
[i
].Vsc
; i
++ )
597 if( pkKT
->pVSCtoVK_E0
[i
].Vsc
== Code
)
598 return pkKT
->pVSCtoVK_E0
[i
].Vk
& 0xff;
600 for( i
= 0; pkKT
->pVSCtoVK_E1
[i
].Vsc
; i
++ )
602 if( pkKT
->pVSCtoVK_E1
[i
].Vsc
== Code
)
603 return pkKT
->pVSCtoVK_E1
[i
].Vk
& 0xff;
610 if( Code
>= pkKT
->bMaxVSCtoVK
)
614 return pkKT
->pusVSCtoVK
[Code
] & 0xff;
619 * Map a virtual key code, or virtual scan code, to a scan code, key code,
620 * or unshifted unicode character.
624 * 0 -- Code is a virtual key code that is converted into a virtual scan code
625 * that does not distinguish between left and right shift keys.
626 * 1 -- Code is a virtual scan code that is converted into a virtual key code
627 * that does not distinguish between left and right shift keys.
628 * 2 -- Code is a virtual key code that is converted into an unshifted unicode
630 * 3 -- Code is a virtual scan code that is converted into a virtual key code
631 * that distinguishes left and right shift keys.
632 * KeyLayout: Keyboard layout handle (currently, unused)
637 static UINT
IntMapVirtualKeyEx( UINT Code
, UINT Type
, PKBDTABLES keyLayout
)
644 if( Code
== VK_SHIFT
)
646 if( Code
== VK_MENU
)
648 if( Code
== VK_CONTROL
)
650 ret
= VkToScan( Code
, FALSE
, keyLayout
);
655 DontDistinguishShifts
656 (IntMapVirtualKeyEx( Code
, 3, keyLayout
) );
663 ret
= VkToScan( Code
, FALSE
, keyLayout
);
664 ToUnicodeInner( Code
, ret
, 0, wp
, 2, 0, keyLayout
);
671 ret
= ScanToVk( Code
, FALSE
, keyLayout
);
680 NtUserMapVirtualKeyEx( UINT Code
, UINT Type
, DWORD keyboardId
, HKL dwhkl
)
683 PKBDTABLES keyLayout
;
684 DECLARE_RETURN(UINT
);
686 DPRINT("Enter NtUserMapVirtualKeyEx\n");
687 UserEnterExclusive();
689 pti
= PsGetCurrentThreadWin32Thread();
690 keyLayout
= pti
? pti
->KeyboardLayout
->KBTables
: 0;
695 RETURN(IntMapVirtualKeyEx( Code
, Type
, keyLayout
));
698 DPRINT("Leave NtUserMapVirtualKeyEx, ret=%i\n",_ret_
);
716 BYTE KeyStateBuf
[0x100];
717 PWCHAR OutPwszBuff
= 0;
721 DPRINT("Enter NtUserSetKeyboardState\n");
722 UserEnterShared();//fixme: this syscall doesnt seem to need any locking...
725 if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf
,
727 sizeof(KeyStateBuf
))) )
729 DPRINT1( "Couldn't copy key state from caller.\n" );
733 /* Virtual code is correct and key is pressed currently? */
734 if (wVirtKey
< 0x100 && KeyStateBuf
[wVirtKey
] & KS_DOWN_BIT
)
736 OutPwszBuff
= ExAllocatePoolWithTag(NonPagedPool
,sizeof(WCHAR
) * cchBuff
, TAG_STRING
);
739 DPRINT1( "ExAllocatePool(%d) failed\n", sizeof(WCHAR
) * cchBuff
);
742 RtlZeroMemory( OutPwszBuff
, sizeof( WCHAR
) * cchBuff
);
744 pti
= PsGetCurrentThreadWin32Thread();
745 ret
= ToUnicodeInner( wVirtKey
,
751 pti
? pti
->KeyboardLayout
->KBTables
: 0 );
753 MmCopyToCaller(pwszBuff
,OutPwszBuff
,sizeof(WCHAR
)*cchBuff
);
754 ExFreePoolWithTag(OutPwszBuff
, TAG_STRING
);
762 DPRINT("Leave NtUserSetKeyboardState, ret=%i\n",_ret_
);
767 static int W32kSimpleToupper( int ch
)
769 if( ch
>= 'a' && ch
<= 'z' )
776 NtUserGetKeyNameText( LONG lParam
, LPWSTR lpString
, int nSize
)
783 UINT ScanCode
= (lParam
>> 16) & 0xff;
784 BOOL ExtKey
= lParam
& (1<<24) ? TRUE
: FALSE
;
785 PKBDTABLES keyLayout
;
786 VSC_LPWSTR
*KeyNames
;
787 DECLARE_RETURN(DWORD
);
789 DPRINT("Enter NtUserGetKeyNameText\n");
792 pti
= PsGetCurrentThreadWin32Thread();
793 keyLayout
= pti
? pti
->KeyboardLayout
->KBTables
: 0;
795 if( !keyLayout
|| nSize
< 1 )
798 if( lParam
& (1<<25) )
800 CareVk
= VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
820 VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
825 if( CareVk
!= VkCode
)
826 ScanCode
= VkToScan( VkCode
, ExtKey
, keyLayout
);
829 KeyNames
= keyLayout
->pKeyNamesExt
;
831 KeyNames
= keyLayout
->pKeyNames
;
833 for( i
= 0; KeyNames
[i
].pwsz
; i
++ )
835 if( KeyNames
[i
].vsc
== ScanCode
)
837 UINT StrLen
= wcslen(KeyNames
[i
].pwsz
);
838 UINT StrMax
= StrLen
> (nSize
- 1) ? (nSize
- 1) : StrLen
;
840 if( NT_SUCCESS( MmCopyToCaller( lpString
,
842 StrMax
* sizeof(WCHAR
) ) ) &&
843 NT_SUCCESS( MmCopyToCaller( lpString
+ StrMax
,
845 sizeof( WCHAR
) ) ) )
857 UCName
[0] = W32kSimpleToupper(IntMapVirtualKeyEx( VkCode
, 2, keyLayout
));
861 if( !NT_SUCCESS(MmCopyToCaller( lpString
, UCName
, 2 * sizeof(WCHAR
) )) )
868 DPRINT("Leave NtUserGetKeyNameText, ret=%i\n",_ret_
);
874 * Filter this message according to the current key layout, setting wParam
879 W32kKeyProcessMessage(LPMSG Msg
,
880 PKBDTABLES KeyboardLayout
,
883 DWORD ScanCode
= 0, ModifierBits
= 0;
885 DWORD BaseMapping
= 0;
887 static WORD NumpadConversion
[][2] =
888 { { VK_DELETE
, VK_DECIMAL
},
889 { VK_INSERT
, VK_NUMPAD0
},
890 { VK_END
, VK_NUMPAD1
},
891 { VK_DOWN
, VK_NUMPAD2
},
892 { VK_NEXT
, VK_NUMPAD3
},
893 { VK_LEFT
, VK_NUMPAD4
},
894 { VK_CLEAR
, VK_NUMPAD5
},
895 { VK_RIGHT
, VK_NUMPAD6
},
896 { VK_HOME
, VK_NUMPAD7
},
897 { VK_UP
, VK_NUMPAD8
},
898 { VK_PRIOR
, VK_NUMPAD9
},
900 PVSC_VK VscVkTable
= NULL
;
902 if( !KeyboardLayout
|| !Msg
||
903 (Msg
->message
!= WM_KEYDOWN
&& Msg
->message
!= WM_SYSKEYDOWN
&&
904 Msg
->message
!= WM_KEYUP
&& Msg
->message
!= WM_SYSKEYUP
) )
909 /* arty -- handle numpad -- On real windows, the actual key produced
910 * by the messaging layer is different based on the state of numlock. */
911 ModifierBits
= ModBits(KeyboardLayout
,gQueueKeyStateTable
);
913 /* Get the raw scan code, so we can look up whether the key is a numpad
916 * Shift and the LP_EXT_BIT cancel. */
917 ScanCode
= (Msg
->lParam
>> 16) & 0xff;
918 BaseMapping
= Msg
->wParam
=
919 IntMapVirtualKeyEx( ScanCode
, 1, KeyboardLayout
);
922 if( ScanCode
>= KeyboardLayout
->bMaxVSCtoVK
)
925 RawVk
= KeyboardLayout
->pusVSCtoVK
[ScanCode
];
931 /* ignore shift codes */
932 if( ScanCode
== 0x2A || ScanCode
== 0x36 )
936 VscVkTable
= KeyboardLayout
->pVSCtoVK_E0
;
938 else if( Prefix
== 0xE1 )
940 VscVkTable
= KeyboardLayout
->pVSCtoVK_E1
;
944 while (VscVkTable
->Vsc
)
946 if( VscVkTable
->Vsc
== ScanCode
)
948 RawVk
= VscVkTable
->Vk
;
954 if ((ModifierBits
& NUMLOCK_BIT
) &&
955 !(ModifierBits
& GetShiftBit(KeyboardLayout
, VK_SHIFT
)) &&
957 !(Msg
->lParam
& LP_EXT_BIT
))
959 /* The key in question is a numpad key. Search for a translation. */
960 for (i
= 0; NumpadConversion
[i
][0]; i
++)
962 if ((BaseMapping
& 0xff) == NumpadConversion
[i
][0]) /* RawVk? */
964 Msg
->wParam
= NumpadConversion
[i
][1];
970 DPRINT("Key: [%04x -> %04x]\n", BaseMapping
, Msg
->wParam
);
972 /* Now that we have the VK, we can set the keymap appropriately
973 * This is a better place for this code, as it's guaranteed to be
974 * run, unlike translate message. */
975 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
)
977 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
978 TRUE
); /* Strike key */
980 else if (Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
982 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
983 FALSE
); /* Release key */
986 /* We need to unset SYSKEYDOWN if the ALT key is an ALT+Gr */
987 if( gQueueKeyStateTable
[VK_RMENU
] & KS_DOWN_BIT
)
989 if( Msg
->message
== WM_SYSKEYDOWN
)
990 Msg
->message
= WM_KEYDOWN
;
992 Msg
->message
= WM_KEYUP
;
1000 UserGetKeyboardType(
1005 case 0: /* Keyboard type */
1006 return 4; /* AT-101 */
1007 case 1: /* Keyboard Subtype */
1008 return 0; /* There are no defined subtypes */
1009 case 2: /* Number of F-keys */
1010 return 12; /* We're doing an 101 for now, so return 12 F-keys */
1012 DPRINT1("Unknown type!\n");
1013 return 0; /* The book says 0 here, so 0 */
1019 Based on TryToTranslateChar, instead of processing VirtualKey match,
1020 look for wChar match.
1026 HKL hKeyboardLayout
,
1027 BOOL UsehKL
) // TRUE from KeyboardLayout, FALSE from pkbl = (THREADINFO)->KeyboardLayout
1029 PKBDTABLES KeyLayout
;
1030 PVK_TO_WCHAR_TABLE vtwTbl
;
1031 PVK_TO_WCHARS10 vkPtr
;
1032 size_t size_this_entry
;
1035 DWORD CapsMod
= 0, CapsState
= 0, Ret
= -1;
1037 DPRINT("NtUserVkKeyScanEx() wChar %d, KbdLayout 0x%p\n", wChar
, hKeyboardLayout
);
1042 if ( !hKeyboardLayout
|| !(pkbl
= UserHklToKbl(hKeyboardLayout
)))
1045 else // From VkKeyScanAW it is FALSE so KeyboardLayout is white noise.
1047 pkbl
= ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->KeyboardLayout
;
1050 KeyLayout
= pkbl
->KBTables
;
1052 for (nMod
= 0; KeyLayout
->pVkToWcharTable
[nMod
].nModifications
; nMod
++)
1054 vtwTbl
= &KeyLayout
->pVkToWcharTable
[nMod
];
1055 size_this_entry
= vtwTbl
->cbSize
;
1056 vkPtr
= (PVK_TO_WCHARS10
)((BYTE
*)vtwTbl
->pVkToWchars
);
1058 while(vkPtr
->VirtualKey
)
1064 Should have only 8 valid possibilities. Including zero.
1066 for(CapsState
= 0; CapsState
< vtwTbl
->nModifications
; CapsState
++)
1068 if(vkPtr
->wch
[CapsState
] == wChar
)
1070 CapsMod
= KeyLayout
->pCharModifiers
->ModNumber
[CapsState
];
1071 DPRINT("nMod %d wC %04x: CapsMod %08x CapsState %08x MaxModBits %08x\n",
1072 nMod
, wChar
, CapsMod
, CapsState
, KeyLayout
->pCharModifiers
->wMaxModBits
);
1073 Ret
= ((CapsMod
<< 8)|(vkPtr
->VirtualKey
& 0xff));
1077 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);