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 ******************************************************************/
33 DBG_DEFAULT_CHANNEL(UserKbd
);
35 BYTE gKeyStateTable
[0x100];
37 /* FUNCTIONS *****************************************************************/
39 /* Initialization -- Right now, just zero the key state and init the lock */
43 InitKeyboardImpl(VOID
)
45 RtlZeroMemory(&gKeyStateTable
, 0x100);
46 return STATUS_SUCCESS
;
49 /*** Statics used by TranslateMessage ***/
51 /*** Shift state code was out of hand, sorry. --- arty */
53 static UINT
DontDistinguishShifts( UINT ret
)
55 if( ret
== VK_LSHIFT
|| ret
== VK_RSHIFT
)
57 if( ret
== VK_LCONTROL
|| ret
== VK_RCONTROL
)
59 if( ret
== VK_LMENU
|| ret
== VK_RMENU
)
64 static VOID APIENTRY
SetKeyState(DWORD key
, DWORD vk
, DWORD ext
, BOOL down
)
68 /* Special handling for toggles like numpad and caps lock */
69 if (vk
== VK_CAPITAL
|| vk
== VK_NUMLOCK
)
72 gKeyStateTable
[vk
] ^= KS_LOCK_BIT
;
76 vk
= ext
? VK_RSHIFT
: VK_LSHIFT
;
78 vk
= ext
? VK_RCONTROL
: VK_LCONTROL
;
80 vk
= ext
? VK_RMENU
: VK_LMENU
;
83 gKeyStateTable
[vk
] |= KS_DOWN_BIT
;
85 gKeyStateTable
[vk
] &= ~KS_DOWN_BIT
;
87 if (vk
== VK_LSHIFT
|| vk
== VK_RSHIFT
)
89 if ((gKeyStateTable
[VK_LSHIFT
] & KS_DOWN_BIT
) ||
90 (gKeyStateTable
[VK_RSHIFT
] & KS_DOWN_BIT
))
92 gKeyStateTable
[VK_SHIFT
] |= KS_DOWN_BIT
;
96 gKeyStateTable
[VK_SHIFT
] &= ~KS_DOWN_BIT
;
100 if (vk
== VK_LCONTROL
|| vk
== VK_RCONTROL
)
102 if ((gKeyStateTable
[VK_LCONTROL
] & KS_DOWN_BIT
) ||
103 (gKeyStateTable
[VK_RCONTROL
] & KS_DOWN_BIT
))
105 gKeyStateTable
[VK_CONTROL
] |= KS_DOWN_BIT
;
109 gKeyStateTable
[VK_CONTROL
] &= ~KS_DOWN_BIT
;
113 if (vk
== VK_LMENU
|| vk
== VK_RMENU
)
115 if ((gKeyStateTable
[VK_LMENU
] & KS_DOWN_BIT
) ||
116 (gKeyStateTable
[VK_RMENU
] & KS_DOWN_BIT
))
118 gKeyStateTable
[VK_MENU
] |= KS_DOWN_BIT
;
122 gKeyStateTable
[VK_MENU
] &= ~KS_DOWN_BIT
;
127 VOID
DumpKeyState( PBYTE KeyState
)
131 DbgPrint( "KeyState { " );
132 for( i
= 0; i
< 0x100; i
++ )
135 DbgPrint( "%02x(%02x) ", i
, KeyState
[i
] );
140 static BYTE
KeysSet( PKBDTABLES pkKT
, PBYTE KeyState
,
141 int FakeModLeft
, int FakeModRight
)
143 if( !KeyState
|| !pkKT
)
146 /* Search special codes first */
147 if( FakeModLeft
&& KeyState
[FakeModLeft
] )
148 return KeyState
[FakeModLeft
];
149 else if( FakeModRight
&& KeyState
[FakeModRight
] )
150 return KeyState
[FakeModRight
];
155 /* Search the keyboard layout modifiers table for the shift bit. I don't
156 * want to count on the shift bit not moving, because it can be specified
159 static DWORD FASTCALL
GetShiftBit( PKBDTABLES pkKT
, DWORD Vk
)
163 for( i
= 0; pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
; i
++ )
164 if( pkKT
->pCharModifiers
->pVkToBit
[i
].Vk
== Vk
)
165 return pkKT
->pCharModifiers
->pVkToBit
[i
].ModBits
;
170 static DWORD
ModBits( PKBDTABLES pkKT
, PBYTE KeyState
)
177 /* DumpKeyState( KeyState ); */
179 if (KeysSet( pkKT
, KeyState
, VK_LSHIFT
, VK_RSHIFT
) &
181 ModBits
|= GetShiftBit( pkKT
, VK_SHIFT
);
183 if (KeysSet( pkKT
, KeyState
, VK_SHIFT
, 0 ) &
185 ModBits
|= GetShiftBit( pkKT
, VK_SHIFT
);
187 if (KeysSet( pkKT
, KeyState
, VK_LCONTROL
, VK_RCONTROL
) &
189 ModBits
|= GetShiftBit( pkKT
, VK_CONTROL
);
191 if (KeysSet( pkKT
, KeyState
, VK_CONTROL
, 0 ) &
193 ModBits
|= GetShiftBit( pkKT
, VK_CONTROL
);
195 if (KeysSet( pkKT
, KeyState
, VK_LMENU
, VK_RMENU
) &
197 ModBits
|= GetShiftBit( pkKT
, VK_MENU
);
200 if (pkKT
->fLocalFlags
& 0x1)
201 if (KeysSet( pkKT
, KeyState
, VK_RMENU
, 0 ) &
203 ModBits
|= GetShiftBit( pkKT
, VK_CONTROL
);
205 /* Deal with VK_CAPITAL */
206 if (KeysSet( pkKT
, KeyState
, VK_CAPITAL
, 0 ) & KS_LOCK_BIT
)
208 ModBits
|= CAPITAL_BIT
;
211 /* Deal with VK_NUMLOCK */
212 if (KeysSet( pkKT
, KeyState
, VK_NUMLOCK
, 0 ) & KS_LOCK_BIT
)
214 ModBits
|= NUMLOCK_BIT
;
217 TRACE( "Current Mod Bits: %x\n", ModBits
);
222 static BOOL
TryToTranslateChar(WORD wVirtKey
,
226 PWCHAR pwcTranslatedChar
,
227 PKBDTABLES keyLayout
)
229 PVK_TO_WCHAR_TABLE vtwTbl
;
230 PVK_TO_WCHARS10 vkPtr
;
231 size_t size_this_entry
;
233 DWORD CapsMod
= 0, CapsState
= 0;
235 CapsState
= ModBits
& ~MOD_BITS_MASK
;
236 ModBits
= ModBits
& MOD_BITS_MASK
;
238 TRACE ( "TryToTranslate: %04x %x\n", wVirtKey
, ModBits
);
240 if (ModBits
> keyLayout
->pCharModifiers
->wMaxModBits
)
245 for (nMod
= 0; keyLayout
->pVkToWcharTable
[nMod
].nModifications
; nMod
++)
247 vtwTbl
= &keyLayout
->pVkToWcharTable
[nMod
];
248 size_this_entry
= vtwTbl
->cbSize
;
249 vkPtr
= (PVK_TO_WCHARS10
)((BYTE
*)vtwTbl
->pVkToWchars
);
250 while(vkPtr
->VirtualKey
)
252 if( wVirtKey
== (vkPtr
->VirtualKey
& 0xff) )
254 CapsMod
= keyLayout
->pCharModifiers
->ModNumber
256 ((CapsState
& CAPITAL_BIT
) ? vkPtr
->Attributes
: 0)];
258 if( CapsMod
>= keyLayout
->pVkToWcharTable
[nMod
].nModifications
)
263 if( vkPtr
->wch
[CapsMod
] == WCH_NONE
)
268 *pbDead
= vkPtr
->wch
[CapsMod
] == WCH_DEAD
;
269 *pbLigature
= vkPtr
->wch
[CapsMod
] == WCH_LGTR
;
270 *pwcTranslatedChar
= vkPtr
->wch
[CapsMod
];
272 TRACE("%d %04x: CapsMod %08x CapsState %08x Char %04x\n",
274 CapsMod
, CapsState
, *pwcTranslatedChar
);
278 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
279 if( vkPtr
->VirtualKey
!= 0xff )
281 TRACE( "Found dead key with no trailer in the table.\n" );
282 TRACE( "VK: %04x, ADDR: %p\n", wVirtKey
, vkPtr
);
285 *pwcTranslatedChar
= vkPtr
->wch
[CapsMod
];
289 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);
297 ToUnicodeInner(UINT wVirtKey
,
305 WCHAR wcTranslatedChar
;
312 if( TryToTranslateChar( wVirtKey
,
313 ModBits( pkKT
, lpKeyState
),
321 WARN("Not handling ligature (yet)\n" );
326 pwszBuff
[0] = wcTranslatedChar
;
328 return bDead
? -1 : 1;
335 DWORD FASTCALL
UserGetAsyncKeyState(DWORD key
)
341 ret
= ((DWORD
)(gKeyStateTable
[key
] & KS_DOWN_BIT
) << 8 ) |
342 (gKeyStateTable
[key
] & KS_LOCK_BIT
);
344 ret
|= 0xFFFF0000; // If down, windows returns 0xFFFF8000.
348 EngSetLastError(ERROR_INVALID_PARAMETER
);
353 /***********************************************************************
356 WORD FASTCALL
get_key_state(void)
360 if (gpsi
->aiSysMet
[SM_SWAPBUTTON
])
362 if (gKeyStateTable
[VK_RBUTTON
] & KS_DOWN_BIT
) ret
|= MK_LBUTTON
;
363 if (gKeyStateTable
[VK_LBUTTON
] & KS_DOWN_BIT
) ret
|= MK_RBUTTON
;
367 if (gKeyStateTable
[VK_LBUTTON
] & KS_DOWN_BIT
) ret
|= MK_LBUTTON
;
368 if (gKeyStateTable
[VK_RBUTTON
] & KS_DOWN_BIT
) ret
|= MK_RBUTTON
;
370 if (gKeyStateTable
[VK_MBUTTON
] & KS_DOWN_BIT
) ret
|= MK_MBUTTON
;
371 if (gKeyStateTable
[VK_SHIFT
] & KS_DOWN_BIT
) ret
|= MK_SHIFT
;
372 if (gKeyStateTable
[VK_CONTROL
] & KS_DOWN_BIT
) ret
|= MK_CONTROL
;
373 if (gKeyStateTable
[VK_XBUTTON1
] & KS_DOWN_BIT
) ret
|= MK_XBUTTON1
;
374 if (gKeyStateTable
[VK_XBUTTON2
] & KS_DOWN_BIT
) ret
|= MK_XBUTTON2
;
380 NtUserGetAsyncKeyState(
383 DECLARE_RETURN(SHORT
);
385 TRACE("Enter NtUserGetAsyncKeyState\n");
386 UserEnterExclusive();
388 RETURN((SHORT
)UserGetAsyncKeyState(key
));
391 TRACE("Leave NtUserGetAsyncKeyState, ret=%i\n", _ret_
);
399 IntTranslateKbdMessage(LPMSG lpMsg
,
403 static INT dead_char
= 0;
407 PKBDTABLES keyLayout
;
411 pWndMsg
= UserGetWindowObject(lpMsg
->hwnd
);
412 if (!pWndMsg
) // Must have a window!
414 ERR("No Window for Translate.\n");
418 pti
= pWndMsg
->head
.pti
;
419 keyLayout
= pti
->KeyboardLayout
->KBTables
;
423 if (lpMsg
->message
< WM_KEYFIRST
|| lpMsg
->message
> WM_KEYLAST
)
425 if (lpMsg
->message
!= WM_KEYDOWN
&& lpMsg
->message
!= WM_SYSKEYDOWN
)
428 /* All messages have to contain the cursor point. */
429 NewMsg
.pt
= gpsi
->ptCursor
;
431 TRACE("IntTranslateKbdMessage %s\n", lpMsg
->message
== WM_SYSKEYDOWN
? "WM_SYSKEYDOWN" : "WM_KEYDOWN");
433 switch (lpMsg
->wParam
)
436 NewMsg
.message
= (lpMsg
->message
== WM_KEYDOWN
) ? WM_CHAR
: WM_SYSCHAR
;
437 NewMsg
.hwnd
= lpMsg
->hwnd
;
438 NewMsg
.wParam
= HIWORD(lpMsg
->lParam
);
439 NewMsg
.lParam
= LOWORD(lpMsg
->lParam
);
440 MsqPostMessage(pti
->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
444 UState
= ToUnicodeInner( lpMsg
->wParam
,
445 HIWORD(lpMsg
->lParam
) & 0xff,
454 NewMsg
.message
= (lpMsg
->message
== WM_KEYDOWN
) ? WM_CHAR
: WM_SYSCHAR
;
459 TRACE("PREVIOUS DEAD CHAR: %c\n", dead_char
);
461 for( i
= 0; keyLayout
->pDeadKey
[i
].dwBoth
; i
++ )
463 first
= keyLayout
->pDeadKey
[i
].dwBoth
>> 16;
464 second
= keyLayout
->pDeadKey
[i
].dwBoth
;
465 if (first
== dead_char
&& second
== wp
[0])
467 wp
[0] = keyLayout
->pDeadKey
[i
].wchComposed
;
473 TRACE("FINAL CHAR: %c\n", wp
[0]);
478 NewMsg
.hwnd
= lpMsg
->hwnd
;
479 NewMsg
.wParam
= dead_char
;
480 NewMsg
.lParam
= lpMsg
->lParam
;
482 MsqPostMessage(pti
->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
485 NewMsg
.hwnd
= lpMsg
->hwnd
;
486 NewMsg
.wParam
= wp
[0];
487 NewMsg
.lParam
= lpMsg
->lParam
;
488 TRACE( "CHAR='%c' %04x %08x\n", wp
[0], wp
[0], lpMsg
->lParam
);
489 MsqPostMessage(pti
->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
492 else if (UState
== -1)
495 (lpMsg
->message
== WM_KEYDOWN
) ? WM_DEADCHAR
: WM_SYSDEADCHAR
;
496 NewMsg
.hwnd
= lpMsg
->hwnd
;
497 NewMsg
.wParam
= wp
[0];
498 NewMsg
.lParam
= lpMsg
->lParam
;
500 MsqPostMessage(pti
->MessageQueue
, &NewMsg
, FALSE
, QS_KEY
);
503 TRACE("IntTranslateKbdMessage E %s\n", NewMsg
.message
== WM_CHAR
? "WM_CHAR" : "WM_SYSCHAR");
507 static UINT
VkToScan( UINT Code
, BOOL ExtCode
, PKBDTABLES pkKT
)
511 for( i
= 0; i
< pkKT
->bMaxVSCtoVK
; i
++ )
513 if( pkKT
->pusVSCtoVK
[i
] == Code
)
522 UINT
ScanToVk( UINT Code
, BOOL ExtKey
, PKBDTABLES pkKT
)
526 TRACE("ScanToVk: No layout\n");
534 for( i
= 0; pkKT
->pVSCtoVK_E0
[i
].Vsc
; i
++ )
536 if( pkKT
->pVSCtoVK_E0
[i
].Vsc
== Code
)
537 return pkKT
->pVSCtoVK_E0
[i
].Vk
& 0xff;
539 for( i
= 0; pkKT
->pVSCtoVK_E1
[i
].Vsc
; i
++ )
541 if( pkKT
->pVSCtoVK_E1
[i
].Vsc
== Code
)
542 return pkKT
->pVSCtoVK_E1
[i
].Vk
& 0xff;
549 if( Code
>= pkKT
->bMaxVSCtoVK
)
553 return pkKT
->pusVSCtoVK
[Code
] & 0xff;
558 * Map a virtual key code, or virtual scan code, to a scan code, key code,
559 * or unshifted unicode character.
563 * 0 -- Code is a virtual key code that is converted into a virtual scan code
564 * that does not distinguish between left and right shift keys.
565 * 1 -- Code is a virtual scan code that is converted into a virtual key code
566 * that does not distinguish between left and right shift keys.
567 * 2 -- Code is a virtual key code that is converted into an unshifted unicode
569 * 3 -- Code is a virtual scan code that is converted into a virtual key code
570 * that distinguishes left and right shift keys.
571 * KeyLayout: Keyboard layout handle (currently, unused)
576 static UINT
IntMapVirtualKeyEx( UINT Code
, UINT Type
, PKBDTABLES keyLayout
)
582 case MAPVK_VK_TO_VSC
:
583 if( Code
== VK_SHIFT
)
585 if( Code
== VK_MENU
)
587 if( Code
== VK_CONTROL
)
589 ret
= VkToScan( Code
, FALSE
, keyLayout
);
592 case MAPVK_VSC_TO_VK
:
594 DontDistinguishShifts
595 (IntMapVirtualKeyEx( Code
, MAPVK_VSC_TO_VK_EX
, keyLayout
) );
598 case MAPVK_VK_TO_CHAR
:
602 ret
= VkToScan( Code
, FALSE
, keyLayout
);
603 ToUnicodeInner( Code
, ret
, 0, wp
, 2, 0, keyLayout
);
608 case MAPVK_VSC_TO_VK_EX
:
610 ret
= ScanToVk( Code
, FALSE
, keyLayout
);
613 case MAPVK_VK_TO_VSC_EX
:
618 ERR("Wrong type value: %u\n", Type
);
626 NtUserMapVirtualKeyEx( UINT Code
, UINT Type
, DWORD keyboardId
, HKL dwhkl
)
629 PKBDTABLES keyLayout
;
630 DECLARE_RETURN(UINT
);
632 TRACE("Enter NtUserMapVirtualKeyEx\n");
633 UserEnterExclusive();
635 pti
= PsGetCurrentThreadWin32Thread();
636 keyLayout
= pti
? pti
->KeyboardLayout
->KBTables
: 0;
641 RETURN(IntMapVirtualKeyEx( Code
, Type
, keyLayout
));
644 TRACE("Leave NtUserMapVirtualKeyEx, ret=%i\n", _ret_
);
662 BYTE KeyStateBuf
[0x100];
663 PWCHAR OutPwszBuff
= 0;
667 TRACE("Enter NtUserSetKeyboardState\n");
668 UserEnterShared();//fixme: this syscall doesnt seem to need any locking...
671 if (wScanCode
& SC_KEY_UP
)
676 if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf
,
678 sizeof(KeyStateBuf
))) )
680 ERR( "Couldn't copy key state from caller.\n" );
684 /* Virtual code is correct? */
685 if (wVirtKey
< 0x100)
687 OutPwszBuff
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(WCHAR
) * cchBuff
, TAG_STRING
);
690 ERR( "ExAllocatePoolWithTag(%d) failed\n", sizeof(WCHAR
) * cchBuff
);
693 RtlZeroMemory( OutPwszBuff
, sizeof( WCHAR
) * cchBuff
);
695 pti
= PsGetCurrentThreadWin32Thread();
696 ret
= ToUnicodeInner( wVirtKey
,
702 pti
? pti
->KeyboardLayout
->KBTables
: 0 );
704 MmCopyToCaller(pwszBuff
, OutPwszBuff
, sizeof(WCHAR
)*cchBuff
);
705 ExFreePoolWithTag(OutPwszBuff
, TAG_STRING
);
711 TRACE("Leave NtUserSetKeyboardState, ret=%i\n", _ret_
);
716 static int W32kSimpleToupper( int ch
)
718 if( ch
>= 'a' && ch
<= 'z' )
725 NtUserGetKeyNameText( LONG lParam
, LPWSTR lpString
, int nSize
)
732 UINT ScanCode
= (lParam
>> 16) & 0xff;
733 BOOL ExtKey
= lParam
& (1 << 24) ? TRUE
: FALSE
;
734 PKBDTABLES keyLayout
;
735 VSC_LPWSTR
*KeyNames
;
736 DECLARE_RETURN(DWORD
);
738 TRACE("Enter NtUserGetKeyNameText\n");
741 pti
= PsGetCurrentThreadWin32Thread();
742 keyLayout
= pti
? pti
->KeyboardLayout
->KBTables
: 0;
744 if( !keyLayout
|| nSize
< 1 )
747 if( lParam
& (1 << 25) )
749 CareVk
= VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
769 VkCode
= ScanToVk( ScanCode
, ExtKey
, keyLayout
);
774 if( CareVk
!= VkCode
)
775 ScanCode
= VkToScan( VkCode
, ExtKey
, keyLayout
);
778 KeyNames
= keyLayout
->pKeyNamesExt
;
780 KeyNames
= keyLayout
->pKeyNames
;
782 for( i
= 0; KeyNames
[i
].pwsz
; i
++ )
784 if( KeyNames
[i
].vsc
== ScanCode
)
786 UINT StrLen
= wcslen(KeyNames
[i
].pwsz
);
787 UINT StrMax
= StrLen
> (nSize
- 1) ? (nSize
- 1) : StrLen
;
789 if( NT_SUCCESS( MmCopyToCaller( lpString
,
791 StrMax
* sizeof(WCHAR
) ) ) &&
792 NT_SUCCESS( MmCopyToCaller( lpString
+ StrMax
,
794 sizeof( WCHAR
) ) ) )
806 UCName
[0] = W32kSimpleToupper(IntMapVirtualKeyEx( VkCode
, MAPVK_VK_TO_CHAR
, keyLayout
));
810 if( !NT_SUCCESS(MmCopyToCaller( lpString
, UCName
, 2 * sizeof(WCHAR
) )) )
817 TRACE("Leave NtUserGetKeyNameText, ret=%i\n", _ret_
);
823 * Filter this message according to the current key layout, setting wParam
828 W32kKeyProcessMessage(LPMSG Msg
,
829 PKBDTABLES KeyboardLayout
,
832 DWORD ScanCode
= 0, ModifierBits
= 0;
834 DWORD BaseMapping
= 0;
836 static WORD NumpadConversion
[][2] =
837 { { VK_DELETE
, VK_DECIMAL
},
838 { VK_INSERT
, VK_NUMPAD0
},
839 { VK_END
, VK_NUMPAD1
},
840 { VK_DOWN
, VK_NUMPAD2
},
841 { VK_NEXT
, VK_NUMPAD3
},
842 { VK_LEFT
, VK_NUMPAD4
},
843 { VK_CLEAR
, VK_NUMPAD5
},
844 { VK_RIGHT
, VK_NUMPAD6
},
845 { VK_HOME
, VK_NUMPAD7
},
846 { VK_UP
, VK_NUMPAD8
},
847 { VK_PRIOR
, VK_NUMPAD9
},
850 PVSC_VK VscVkTable
= NULL
;
852 if( !KeyboardLayout
|| !Msg
||
853 (Msg
->message
!= WM_KEYDOWN
&& Msg
->message
!= WM_SYSKEYDOWN
&&
854 Msg
->message
!= WM_KEYUP
&& Msg
->message
!= WM_SYSKEYUP
) )
859 /* arty -- handle numpad -- On real windows, the actual key produced
860 * by the messaging layer is different based on the state of numlock. */
861 ModifierBits
= ModBits(KeyboardLayout
, gKeyStateTable
);
863 /* Get the raw scan code, so we can look up whether the key is a numpad
866 * Shift and the LP_EXT_BIT cancel. */
867 ScanCode
= (Msg
->lParam
>> 16) & 0xff;
868 TRACE("ScanCode %04x\n", ScanCode
);
870 BaseMapping
= Msg
->wParam
=
871 IntMapVirtualKeyEx( ScanCode
, MAPVK_VSC_TO_VK
, KeyboardLayout
);
874 if( ScanCode
>= KeyboardLayout
->bMaxVSCtoVK
)
877 RawVk
= KeyboardLayout
->pusVSCtoVK
[ScanCode
];
883 /* ignore shift codes */
884 if( ScanCode
== 0x2A || ScanCode
== 0x36 )
888 VscVkTable
= KeyboardLayout
->pVSCtoVK_E0
;
890 else if( Prefix
== 0xE1 )
892 VscVkTable
= KeyboardLayout
->pVSCtoVK_E1
;
897 ERR("somethings wrong, Prefix=0x%x", Prefix
);
902 while (VscVkTable
->Vsc
)
904 if( VscVkTable
->Vsc
== ScanCode
)
906 RawVk
= VscVkTable
->Vk
;
912 if ((ModifierBits
& NUMLOCK_BIT
) &&
913 !(ModifierBits
& GetShiftBit(KeyboardLayout
, VK_SHIFT
)) &&
915 !(Msg
->lParam
& LP_EXT_BIT
))
917 /* The key in question is a numpad key. Search for a translation. */
918 for (i
= 0; NumpadConversion
[i
][0]; i
++)
920 if ((BaseMapping
& 0xff) == NumpadConversion
[i
][0]) /* RawVk? */
922 Msg
->wParam
= NumpadConversion
[i
][1];
928 TRACE("Key: [%04x -> %04x]\n", BaseMapping
, Msg
->wParam
);
930 /* Now that we have the VK, we can set the keymap appropriately
931 * This is a better place for this code, as it's guaranteed to be
932 * run, unlike translate message. */
933 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
)
935 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
936 TRUE
); /* Strike key */
938 else if (Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
940 SetKeyState( ScanCode
, Msg
->wParam
, Msg
->lParam
& LP_EXT_BIT
,
941 FALSE
); /* Release key */
944 /* We need to unset SYSKEYDOWN if the ALT key is an ALT+Gr */
945 if( gKeyStateTable
[VK_RMENU
] & KS_DOWN_BIT
)
947 if( Msg
->message
== WM_SYSKEYDOWN
)
948 Msg
->message
= WM_KEYDOWN
;
950 Msg
->message
= WM_KEYUP
;
963 case 0: /* Keyboard type */
964 return 4; /* AT-101 */
965 case 1: /* Keyboard Subtype */
966 return 0; /* There are no defined subtypes */
967 case 2: /* Number of F-keys */
968 return 12; /* We're doing an 101 for now, so return 12 F-keys */
970 ERR("Unknown type!\n");
971 return 0; /* The book says 0 here, so 0 */
977 Based on TryToTranslateChar, instead of processing VirtualKey match,
978 look for wChar match.
985 BOOL UsehKL
) // TRUE from KeyboardLayout, FALSE from pkbl = (THREADINFO)->KeyboardLayout
987 PKBDTABLES KeyLayout
;
988 PVK_TO_WCHAR_TABLE vtwTbl
;
989 PVK_TO_WCHARS10 vkPtr
;
990 size_t size_this_entry
;
993 DWORD CapsMod
= 0, CapsState
= 0, Ret
= -1;
995 TRACE("NtUserVkKeyScanEx() wChar %d, KbdLayout 0x%p\n", wChar
, hKeyboardLayout
);
1000 if ( !hKeyboardLayout
|| !(pkbl
= UserHklToKbl(hKeyboardLayout
)))
1003 else // From VkKeyScanAW it is FALSE so KeyboardLayout is white noise.
1005 pkbl
= ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->KeyboardLayout
;
1008 KeyLayout
= pkbl
->KBTables
;
1010 for (nMod
= 0; KeyLayout
->pVkToWcharTable
[nMod
].nModifications
; nMod
++)
1012 vtwTbl
= &KeyLayout
->pVkToWcharTable
[nMod
];
1013 size_this_entry
= vtwTbl
->cbSize
;
1014 vkPtr
= (PVK_TO_WCHARS10
)((BYTE
*)vtwTbl
->pVkToWchars
);
1016 while(vkPtr
->VirtualKey
)
1022 Should have only 8 valid possibilities. Including zero.
1024 for(CapsState
= 0; CapsState
< vtwTbl
->nModifications
; CapsState
++)
1026 if(vkPtr
->wch
[CapsState
] == wChar
)
1028 CapsMod
= KeyLayout
->pCharModifiers
->ModNumber
[CapsState
];
1029 TRACE("nMod %d wC %04x: CapsMod %08x CapsState %08x MaxModBits %08x\n",
1030 nMod
, wChar
, CapsMod
, CapsState
, KeyLayout
->pCharModifiers
->wMaxModBits
);
1031 Ret
= ((CapsMod
<< 8) | (vkPtr
->VirtualKey
& 0xff));
1035 vkPtr
= (PVK_TO_WCHARS10
)(((BYTE
*)vkPtr
) + size_this_entry
);