2003-05-18 17:16:18 +00:00
|
|
|
/*
|
|
|
|
* ReactOS W32 Subsystem
|
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
2005-01-03 22:00:39 +00:00
|
|
|
/* $Id$
|
2002-01-27 14:47:44 +00:00
|
|
|
*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* PURPOSE: Messages
|
2003-07-05 16:04:01 +00:00
|
|
|
* FILE: subsys/win32k/ntuser/keyboard.c
|
2002-01-27 14:47:44 +00:00
|
|
|
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
|
|
* REVISION HISTORY:
|
|
|
|
* 06-06-2001 CSH Created
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
2004-05-10 17:07:20 +00:00
|
|
|
#include <w32k.h>
|
2002-01-27 14:47:44 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
2003-11-24 00:22:53 +00:00
|
|
|
/* Directory to load key layouts from */
|
2003-10-18 20:41:10 +00:00
|
|
|
#define SYSTEMROOT_DIR L"\\SystemRoot\\System32\\"
|
2003-11-24 00:22:53 +00:00
|
|
|
/* Lock modifiers */
|
|
|
|
#define CAPITAL_BIT 0x80000000
|
|
|
|
#define NUMLOCK_BIT 0x40000000
|
|
|
|
#define MOD_BITS_MASK 0x3fffffff
|
|
|
|
#define MOD_KCTRL 0x02
|
|
|
|
/* Key States */
|
|
|
|
#define KS_DOWN_MASK 0xc0
|
|
|
|
#define KS_DOWN_BIT 0x80
|
|
|
|
#define KS_LOCK_BIT 0x01
|
|
|
|
/* lParam bits */
|
|
|
|
#define LP_EXT_BIT (1<<24)
|
|
|
|
/* From kbdxx.c -- Key changes with numlock */
|
|
|
|
#define KNUMP 0x400
|
|
|
|
|
|
|
|
/* Lock the keyboard state to prevent unusual concurrent access */
|
2003-12-13 06:19:59 +00:00
|
|
|
FAST_MUTEX QueueStateLock;
|
2003-10-18 20:41:10 +00:00
|
|
|
|
2002-01-27 14:47:44 +00:00
|
|
|
BYTE QueueKeyStateTable[256];
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
#define IntLockQueueState \
|
|
|
|
ExAcquireFastMutex(&QueueStateLock)
|
|
|
|
|
|
|
|
#define IntUnLockQueueState \
|
|
|
|
ExReleaseFastMutex(&QueueStateLock)
|
|
|
|
|
2003-07-29 23:03:01 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2003-11-24 00:22:53 +00:00
|
|
|
/* Initialization -- Right now, just zero the key state and init the lock */
|
|
|
|
NTSTATUS FASTCALL InitKeyboardImpl(VOID) {
|
2003-12-13 06:19:59 +00:00
|
|
|
ExInitializeFastMutex(&QueueStateLock);
|
2003-11-24 00:22:53 +00:00
|
|
|
RtlZeroMemory(&QueueKeyStateTable,0x100);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2003-07-29 23:03:01 +00:00
|
|
|
/*** Statics used by TranslateMessage ***/
|
|
|
|
|
2004-02-19 06:59:50 +00:00
|
|
|
/*** Shift state code was out of hand, sorry. --- arty */
|
2004-02-19 03:45:44 +00:00
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
static UINT DontDistinguishShifts( UINT ret ) {
|
2004-02-19 06:59:50 +00:00
|
|
|
if( ret == VK_LSHIFT || ret == VK_RSHIFT ) ret = VK_LSHIFT;
|
|
|
|
if( ret == VK_LCONTROL || ret == VK_RCONTROL ) ret = VK_LCONTROL;
|
|
|
|
if( ret == VK_LMENU || ret == VK_RMENU ) ret = VK_LMENU;
|
2003-10-09 06:13:05 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-11-24 00:22:53 +00:00
|
|
|
static VOID STDCALL SetKeyState(DWORD key, DWORD vk, DWORD ext, BOOL down) {
|
2004-07-04 17:08:40 +00:00
|
|
|
ASSERT(vk <= 0xff);
|
|
|
|
|
2003-11-24 00:22:53 +00:00
|
|
|
/* Special handling for toggles like numpad and caps lock */
|
2004-07-04 17:08:40 +00:00
|
|
|
if (vk == VK_CAPITAL || vk == VK_NUMLOCK) {
|
|
|
|
if (down) QueueKeyStateTable[vk] ^= KS_LOCK_BIT;
|
|
|
|
}
|
2004-02-19 06:59:50 +00:00
|
|
|
|
2004-07-08 12:55:01 +00:00
|
|
|
if (ext && vk == VK_LSHIFT)
|
|
|
|
vk = VK_RSHIFT;
|
|
|
|
if (ext && vk == VK_LCONTROL)
|
|
|
|
vk = VK_RCONTROL;
|
|
|
|
if (ext && vk == VK_LMENU)
|
|
|
|
vk = VK_RMENU;
|
|
|
|
|
2004-07-04 17:08:40 +00:00
|
|
|
if (down)
|
|
|
|
QueueKeyStateTable[vk] |= KS_DOWN_BIT;
|
|
|
|
else
|
|
|
|
QueueKeyStateTable[vk] &= ~KS_DOWN_MASK;
|
2003-11-24 00:22:53 +00:00
|
|
|
|
2004-07-04 17:08:40 +00:00
|
|
|
if (vk == VK_LSHIFT || vk == VK_RSHIFT) {
|
|
|
|
if ((QueueKeyStateTable[VK_LSHIFT] & KS_DOWN_BIT) ||
|
|
|
|
(QueueKeyStateTable[VK_RSHIFT] & KS_DOWN_BIT)) {
|
|
|
|
QueueKeyStateTable[VK_SHIFT] |= KS_DOWN_BIT;
|
|
|
|
} else {
|
|
|
|
QueueKeyStateTable[VK_SHIFT] &= ~KS_DOWN_MASK;
|
|
|
|
}
|
2004-02-19 06:59:50 +00:00
|
|
|
}
|
|
|
|
|
2004-07-04 17:08:40 +00:00
|
|
|
if (vk == VK_LCONTROL || vk == VK_RCONTROL) {
|
|
|
|
if ((QueueKeyStateTable[VK_LCONTROL] & KS_DOWN_BIT) ||
|
|
|
|
(QueueKeyStateTable[VK_RCONTROL] & KS_DOWN_BIT)) {
|
|
|
|
QueueKeyStateTable[VK_CONTROL] |= KS_DOWN_BIT;
|
|
|
|
} else {
|
|
|
|
QueueKeyStateTable[VK_CONTROL] &= ~KS_DOWN_MASK;
|
|
|
|
}
|
2004-02-19 06:59:50 +00:00
|
|
|
}
|
|
|
|
|
2004-07-04 17:08:40 +00:00
|
|
|
if (vk == VK_LMENU || vk == VK_RMENU) {
|
|
|
|
if ((QueueKeyStateTable[VK_LMENU] & KS_DOWN_BIT) ||
|
|
|
|
(QueueKeyStateTable[VK_RMENU] & KS_DOWN_BIT)) {
|
|
|
|
QueueKeyStateTable[VK_MENU] |= KS_DOWN_BIT;
|
|
|
|
} else {
|
|
|
|
QueueKeyStateTable[VK_MENU] &= ~KS_DOWN_MASK;
|
|
|
|
}
|
2004-02-19 06:59:50 +00:00
|
|
|
}
|
2003-07-29 23:03:01 +00:00
|
|
|
}
|
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
VOID DumpKeyState( PBYTE KeyState ) {
|
2003-07-29 23:03:01 +00:00
|
|
|
int i;
|
2003-10-09 06:13:05 +00:00
|
|
|
|
|
|
|
DbgPrint( "KeyState { " );
|
|
|
|
for( i = 0; i < 0x100; i++ ) {
|
|
|
|
if( KeyState[i] ) DbgPrint( "%02x(%02x) ", i, KeyState[i] );
|
|
|
|
}
|
|
|
|
DbgPrint( "};\n" );
|
|
|
|
}
|
|
|
|
|
|
|
|
static BYTE KeysSet( PKBDTABLES pkKT, PBYTE KeyState,
|
2004-02-19 06:59:50 +00:00
|
|
|
int FakeModLeft, int FakeModRight ) {
|
2003-10-09 06:13:05 +00:00
|
|
|
if( !KeyState || !pkKT ) return 0;
|
|
|
|
|
2004-02-19 06:59:50 +00:00
|
|
|
/* Search special codes first */
|
|
|
|
if( FakeModLeft && KeyState[FakeModLeft] )
|
|
|
|
return KeyState[FakeModLeft];
|
|
|
|
else if( FakeModRight && KeyState[FakeModRight] )
|
|
|
|
return KeyState[FakeModRight];
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
return 0;
|
2003-07-29 23:03:01 +00:00
|
|
|
}
|
|
|
|
|
2004-02-19 06:59:50 +00:00
|
|
|
/* Search the keyboard layout modifiers table for the shift bit. I don't
|
|
|
|
* want to count on the shift bit not moving, because it can be specified
|
|
|
|
* in the layout */
|
|
|
|
|
|
|
|
static DWORD FASTCALL GetShiftBit( PKBDTABLES pkKT, DWORD Vk ) {
|
2003-10-09 06:13:05 +00:00
|
|
|
int i;
|
2004-02-19 06:59:50 +00:00
|
|
|
|
|
|
|
for( i = 0; pkKT->pCharModifiers->pVkToBit[i].Vk; i++ )
|
|
|
|
if( pkKT->pCharModifiers->pVkToBit[i].Vk == Vk )
|
|
|
|
return pkKT->pCharModifiers->pVkToBit[i].ModBits;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWORD ModBits( PKBDTABLES pkKT, PBYTE KeyState ) {
|
2003-10-09 06:13:05 +00:00
|
|
|
DWORD ModBits = 0;
|
|
|
|
|
|
|
|
if( !KeyState ) return 0;
|
|
|
|
|
|
|
|
/* DumpKeyState( KeyState ); */
|
|
|
|
|
2004-02-19 06:59:50 +00:00
|
|
|
if (KeysSet( pkKT, KeyState, VK_LSHIFT, VK_RSHIFT ) &
|
|
|
|
KS_DOWN_BIT)
|
|
|
|
ModBits |= GetShiftBit( pkKT, VK_SHIFT );
|
|
|
|
|
|
|
|
if (KeysSet( pkKT, KeyState, VK_LCONTROL, VK_RCONTROL ) &
|
|
|
|
KS_DOWN_BIT )
|
|
|
|
ModBits |= GetShiftBit( pkKT, VK_CONTROL );
|
|
|
|
|
|
|
|
if (KeysSet( pkKT, KeyState, VK_LMENU, VK_RMENU ) &
|
|
|
|
KS_DOWN_BIT )
|
|
|
|
ModBits |= GetShiftBit( pkKT, VK_MENU );
|
|
|
|
|
|
|
|
/* Handle Alt+Gr */
|
|
|
|
if (KeysSet( pkKT, KeyState, VK_RMENU, 0 ) &
|
|
|
|
KS_DOWN_BIT )
|
|
|
|
ModBits |= GetShiftBit( pkKT, VK_CONTROL );
|
|
|
|
|
|
|
|
/* Deal with VK_CAPITAL */
|
|
|
|
if (KeysSet( pkKT, KeyState, VK_CAPITAL, 0 ) & KS_LOCK_BIT)
|
2003-11-24 00:22:53 +00:00
|
|
|
{
|
|
|
|
ModBits |= CAPITAL_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deal with VK_NUMLOCK */
|
2004-02-19 06:59:50 +00:00
|
|
|
if (KeysSet( pkKT, KeyState, VK_NUMLOCK, 0 ) & KS_LOCK_BIT)
|
2003-11-24 00:22:53 +00:00
|
|
|
{
|
|
|
|
ModBits |= NUMLOCK_BIT;
|
|
|
|
}
|
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
DPRINT( "Current Mod Bits: %x\n", ModBits );
|
|
|
|
|
|
|
|
return ModBits;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL TryToTranslateChar(WORD wVirtKey,
|
|
|
|
DWORD ModBits,
|
|
|
|
PBOOL pbDead,
|
|
|
|
PBOOL pbLigature,
|
|
|
|
PWCHAR pwcTranslatedChar,
|
|
|
|
PKBDTABLES keyLayout )
|
|
|
|
{
|
|
|
|
PVK_TO_WCHAR_TABLE vtwTbl;
|
2003-07-29 23:03:01 +00:00
|
|
|
PVK_TO_WCHARS10 vkPtr;
|
2003-10-09 06:13:05 +00:00
|
|
|
size_t size_this_entry;
|
|
|
|
int nMod, shift;
|
2003-11-24 00:22:53 +00:00
|
|
|
DWORD CapsMod = 0, CapsState = 0;
|
|
|
|
|
|
|
|
CapsState = ModBits & ~MOD_BITS_MASK;
|
|
|
|
ModBits = ModBits & MOD_BITS_MASK;
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
DPRINT ( "TryToTranslate: %04x %x\n", wVirtKey, ModBits );
|
|
|
|
|
|
|
|
if (ModBits > keyLayout->pCharModifiers->wMaxModBits)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
shift = keyLayout->pCharModifiers->ModNumber[ModBits];
|
2004-02-19 06:59:50 +00:00
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
for (nMod = 0; keyLayout->pVkToWcharTable[nMod].nModifications; nMod++)
|
|
|
|
{
|
|
|
|
vtwTbl = &keyLayout->pVkToWcharTable[nMod];
|
|
|
|
size_this_entry = vtwTbl->cbSize;
|
|
|
|
vkPtr = (PVK_TO_WCHARS10)((BYTE *)vtwTbl->pVkToWchars);
|
|
|
|
while(vkPtr->VirtualKey)
|
|
|
|
{
|
2003-11-24 00:22:53 +00:00
|
|
|
if( wVirtKey == (vkPtr->VirtualKey & 0xff) )
|
2003-10-09 06:13:05 +00:00
|
|
|
{
|
2003-11-24 00:22:53 +00:00
|
|
|
CapsMod =
|
|
|
|
shift | ((CapsState & CAPITAL_BIT) ? vkPtr->Attributes : 0);
|
2004-02-19 06:59:50 +00:00
|
|
|
|
|
|
|
if( CapsMod > keyLayout->pVkToWcharTable[nMod].nModifications ) {
|
|
|
|
DWORD MaxBit = 1;
|
|
|
|
while( MaxBit <
|
|
|
|
keyLayout->pVkToWcharTable[nMod].nModifications )
|
|
|
|
MaxBit <<= 1;
|
|
|
|
|
|
|
|
CapsMod &= MaxBit - 1; /* Guarantee that CapsMod lies
|
|
|
|
in bounds. */
|
|
|
|
}
|
2003-11-24 00:22:53 +00:00
|
|
|
|
|
|
|
*pbDead = vkPtr->wch[CapsMod] == WCH_DEAD;
|
|
|
|
*pbLigature = vkPtr->wch[CapsMod] == WCH_LGTR;
|
|
|
|
*pwcTranslatedChar = vkPtr->wch[CapsMod];
|
|
|
|
|
2004-02-19 06:59:50 +00:00
|
|
|
DPRINT("%d %04x: CapsMod %08x CapsState %08x shift %08x Char %04x\n",
|
|
|
|
nMod, wVirtKey,
|
|
|
|
CapsMod, CapsState, shift, *pwcTranslatedChar);
|
2003-11-24 00:22:53 +00:00
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
if( *pbDead )
|
|
|
|
{
|
|
|
|
vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry);
|
|
|
|
if( vkPtr->VirtualKey != 0xff )
|
|
|
|
{
|
|
|
|
DPRINT( "Found dead key with no trailer in the table.\n" );
|
|
|
|
DPRINT( "VK: %04x, ADDR: %08x\n", wVirtKey, (int)vkPtr );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
*pwcTranslatedChar = vkPtr->wch[shift];
|
|
|
|
}
|
|
|
|
return TRUE;
|
2003-07-29 23:03:01 +00:00
|
|
|
}
|
2003-10-09 06:13:05 +00:00
|
|
|
vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry);
|
2003-07-29 23:03:01 +00:00
|
|
|
}
|
|
|
|
}
|
2003-10-09 06:13:05 +00:00
|
|
|
return FALSE;
|
2003-07-29 23:03:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static
|
2002-01-27 14:47:44 +00:00
|
|
|
int STDCALL
|
2003-07-29 23:03:01 +00:00
|
|
|
ToUnicodeInner(UINT wVirtKey,
|
|
|
|
UINT wScanCode,
|
|
|
|
PBYTE lpKeyState,
|
|
|
|
LPWSTR pwszBuff,
|
|
|
|
int cchBuff,
|
|
|
|
UINT wFlags,
|
|
|
|
PKBDTABLES pkKT)
|
2002-01-27 14:47:44 +00:00
|
|
|
{
|
2003-10-09 06:13:05 +00:00
|
|
|
WCHAR wcTranslatedChar;
|
|
|
|
BOOL bDead;
|
|
|
|
BOOL bLigature;
|
|
|
|
|
|
|
|
if( !pkKT ) return 0;
|
|
|
|
|
|
|
|
if( TryToTranslateChar( wVirtKey,
|
|
|
|
ModBits( pkKT, lpKeyState ),
|
|
|
|
&bDead,
|
|
|
|
&bLigature,
|
|
|
|
&wcTranslatedChar,
|
|
|
|
pkKT ) )
|
|
|
|
{
|
|
|
|
if( bLigature )
|
|
|
|
{
|
|
|
|
DPRINT("Not handling ligature (yet)\n" );
|
|
|
|
return 0;
|
|
|
|
}
|
2003-07-29 23:03:01 +00:00
|
|
|
|
|
|
|
if( cchBuff > 0 ) pwszBuff[0] = wcTranslatedChar;
|
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
return bDead ? -1 : 1;
|
2003-07-29 23:03:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
|
|
STDCALL
|
|
|
|
NtUserGetKeyState(
|
|
|
|
DWORD key)
|
|
|
|
{
|
2003-11-24 00:22:53 +00:00
|
|
|
DWORD ret = 0;
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockQueueState;
|
2003-10-09 06:13:05 +00:00
|
|
|
if( key < 0x100 ) {
|
2003-11-24 00:22:53 +00:00
|
|
|
ret = ((DWORD)(QueueKeyStateTable[key] & KS_DOWN_BIT) << 8 ) |
|
|
|
|
(QueueKeyStateTable[key] & KS_LOCK_BIT);
|
2003-10-09 06:13:05 +00:00
|
|
|
}
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockQueueState;
|
2003-11-24 00:22:53 +00:00
|
|
|
return ret;
|
2003-10-09 06:13:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int STDCALL ToUnicodeEx( UINT wVirtKey,
|
|
|
|
UINT wScanCode,
|
|
|
|
PBYTE lpKeyState,
|
|
|
|
LPWSTR pwszBuff,
|
|
|
|
int cchBuff,
|
|
|
|
UINT wFlags,
|
|
|
|
HKL dwhkl ) {
|
2003-11-24 00:22:53 +00:00
|
|
|
int ToUnicodeResult = 0;
|
|
|
|
|
2005-01-03 22:00:39 +00:00
|
|
|
IntLockQueueState;
|
|
|
|
ToUnicodeResult = ToUnicodeInner( wVirtKey,
|
|
|
|
wScanCode,
|
|
|
|
lpKeyState,
|
|
|
|
pwszBuff,
|
|
|
|
cchBuff,
|
|
|
|
wFlags,
|
|
|
|
PsGetWin32Thread() ?
|
|
|
|
PsGetWin32Thread()->KeyboardLayout : 0 );
|
|
|
|
IntUnLockQueueState;
|
2003-11-24 00:22:53 +00:00
|
|
|
|
|
|
|
return ToUnicodeResult;
|
2003-07-29 23:03:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int STDCALL ToUnicode( UINT wVirtKey,
|
|
|
|
UINT wScanCode,
|
|
|
|
PBYTE lpKeyState,
|
|
|
|
LPWSTR pwszBuff,
|
|
|
|
int cchBuff,
|
|
|
|
UINT wFlags ) {
|
2003-10-09 06:13:05 +00:00
|
|
|
return ToUnicodeEx( wVirtKey,
|
|
|
|
wScanCode,
|
|
|
|
QueueKeyStateTable,
|
|
|
|
pwszBuff,
|
|
|
|
cchBuff,
|
|
|
|
wFlags,
|
|
|
|
0 );
|
2003-07-29 23:03:01 +00:00
|
|
|
}
|
|
|
|
|
2003-10-18 20:41:10 +00:00
|
|
|
/*
|
|
|
|
* Utility to copy and append two unicode strings.
|
|
|
|
*
|
|
|
|
* IN OUT PUNICODE_STRING ResultFirst -> First string and result
|
|
|
|
* IN PUNICODE_STRING Second -> Second string to append
|
|
|
|
* IN BOOL Deallocate -> TRUE: Deallocate First string before
|
|
|
|
* overwriting.
|
|
|
|
*
|
|
|
|
* Returns NTSTATUS.
|
|
|
|
*/
|
|
|
|
|
2004-02-19 03:45:44 +00:00
|
|
|
NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
|
|
|
|
PUNICODE_STRING Second,
|
|
|
|
BOOL Deallocate) {
|
|
|
|
NTSTATUS Status;
|
|
|
|
PWSTR new_string =
|
2004-02-19 21:12:11 +00:00
|
|
|
ExAllocatePoolWithTag(PagedPool,
|
|
|
|
(ResultFirst->Length + Second->Length + sizeof(WCHAR)),
|
|
|
|
TAG_STRING);
|
2004-02-19 03:45:44 +00:00
|
|
|
if( !new_string ) {
|
|
|
|
return STATUS_NO_MEMORY;
|
|
|
|
}
|
|
|
|
memcpy( new_string, ResultFirst->Buffer,
|
|
|
|
ResultFirst->Length );
|
|
|
|
memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
|
|
|
|
Second->Buffer,
|
|
|
|
Second->Length );
|
|
|
|
if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
|
|
|
|
ResultFirst->Length += Second->Length;
|
|
|
|
ResultFirst->MaximumLength = ResultFirst->Length;
|
|
|
|
new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
|
|
|
|
Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
|
|
|
|
STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
|
|
ExFreePool(new_string);
|
|
|
|
return Status;
|
2003-10-18 20:41:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Utility function to read a value from the registry more easily.
|
|
|
|
*
|
|
|
|
* IN PUNICODE_STRING KeyName -> Name of key to open
|
|
|
|
* IN PUNICODE_STRING ValueName -> Name of value to open
|
|
|
|
* OUT PUNICODE_STRING ReturnedValue -> String contained in registry
|
|
|
|
*
|
|
|
|
* Returns NTSTATUS
|
|
|
|
*/
|
|
|
|
|
2004-02-19 03:45:44 +00:00
|
|
|
static NTSTATUS NTAPI ReadRegistryValue( PUNICODE_STRING KeyName,
|
|
|
|
PUNICODE_STRING ValueName,
|
|
|
|
PUNICODE_STRING ReturnedValue ) {
|
|
|
|
NTSTATUS Status;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
OBJECT_ATTRIBUTES KeyAttributes;
|
|
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
|
|
|
|
ULONG Length = 0;
|
|
|
|
ULONG ResLength = 0;
|
|
|
|
UNICODE_STRING Temp;
|
|
|
|
|
|
|
|
InitializeObjectAttributes(&KeyAttributes, KeyName, OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL, NULL);
|
|
|
|
Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &KeyAttributes);
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = ZwQueryValueKey(KeyHandle, ValueName, KeyValuePartialInformation,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
&ResLength);
|
|
|
|
|
|
|
|
if( Status != STATUS_BUFFER_TOO_SMALL ) {
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
ResLength += sizeof( *KeyValuePartialInfo );
|
|
|
|
KeyValuePartialInfo =
|
2004-02-19 21:12:11 +00:00
|
|
|
ExAllocatePoolWithTag(PagedPool, ResLength, TAG_STRING);
|
2004-02-19 03:45:44 +00:00
|
|
|
Length = ResLength;
|
|
|
|
|
|
|
|
if( !KeyValuePartialInfo ) {
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
return STATUS_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = ZwQueryValueKey(KeyHandle, ValueName, KeyValuePartialInformation,
|
|
|
|
(PVOID)KeyValuePartialInfo,
|
|
|
|
Length,
|
|
|
|
&ResLength);
|
|
|
|
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
ExFreePool(KeyValuePartialInfo);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Temp.Length = Temp.MaximumLength = KeyValuePartialInfo->DataLength;
|
|
|
|
Temp.Buffer = (PWCHAR)KeyValuePartialInfo->Data;
|
|
|
|
|
|
|
|
/* At this point, KeyValuePartialInfo->Data contains the key data */
|
|
|
|
RtlInitUnicodeString(ReturnedValue,L"");
|
|
|
|
AppendUnicodeString(ReturnedValue,&Temp,FALSE);
|
|
|
|
|
2003-10-18 20:41:10 +00:00
|
|
|
ExFreePool(KeyValuePartialInfo);
|
2004-02-19 03:45:44 +00:00
|
|
|
NtClose(KeyHandle);
|
|
|
|
|
2003-10-18 20:41:10 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2003-07-29 23:03:01 +00:00
|
|
|
typedef PVOID (*KbdLayerDescriptor)(VOID);
|
|
|
|
NTSTATUS STDCALL LdrGetProcedureAddress(PVOID module,
|
|
|
|
PANSI_STRING import_name,
|
|
|
|
DWORD flags,
|
|
|
|
PVOID *func_addr);
|
|
|
|
|
2004-11-15 14:40:14 +00:00
|
|
|
void InitKbdLayout( PVOID *pkKeyboardLayout )
|
|
|
|
{
|
|
|
|
WCHAR LocaleBuffer[16];
|
2003-10-18 20:41:10 +00:00
|
|
|
UNICODE_STRING LayoutKeyName;
|
|
|
|
UNICODE_STRING LayoutValueName;
|
|
|
|
UNICODE_STRING DefaultLocale;
|
|
|
|
UNICODE_STRING LayoutFile;
|
|
|
|
UNICODE_STRING FullLayoutPath;
|
2004-11-15 14:40:14 +00:00
|
|
|
LCID LocaleId;
|
2003-10-18 20:41:10 +00:00
|
|
|
PWCHAR KeyboardLayoutWSTR;
|
2003-07-29 23:03:01 +00:00
|
|
|
HMODULE kbModule = 0;
|
2003-10-18 20:41:10 +00:00
|
|
|
NTSTATUS Status;
|
2003-07-29 23:03:01 +00:00
|
|
|
ANSI_STRING kbdProcedureName;
|
|
|
|
KbdLayerDescriptor layerDescGetFn;
|
|
|
|
|
2003-10-18 20:41:10 +00:00
|
|
|
#define XX_STATUS(x) if (!NT_SUCCESS(Status = (x))) continue;
|
|
|
|
|
|
|
|
do {
|
2004-11-15 14:40:14 +00:00
|
|
|
Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Could not get default locale (%08lx).\n", Status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-11-15 16:36:28 +00:00
|
|
|
DPRINT("DefaultLocale = %lx\n", LocaleId);
|
2004-11-15 14:40:14 +00:00
|
|
|
swprintf(LocaleBuffer, L"%08lx", LocaleId);
|
2004-11-15 16:36:28 +00:00
|
|
|
DPRINT("DefaultLocale = %S\n", LocaleBuffer);
|
2004-11-15 14:40:14 +00:00
|
|
|
RtlInitUnicodeString(&DefaultLocale, LocaleBuffer);
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2003-10-18 21:29:26 +00:00
|
|
|
RtlInitUnicodeString(&LayoutKeyName,
|
|
|
|
L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet"
|
|
|
|
L"\\Control\\KeyboardLayouts\\");
|
2003-10-18 20:41:10 +00:00
|
|
|
|
2004-02-19 03:45:44 +00:00
|
|
|
AppendUnicodeString(&LayoutKeyName,&DefaultLocale,FALSE);
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2003-10-18 21:29:26 +00:00
|
|
|
RtlInitUnicodeString(&LayoutValueName,L"Layout File");
|
2003-10-18 20:41:10 +00:00
|
|
|
|
2003-10-18 21:29:26 +00:00
|
|
|
Status = ReadRegistryValue(&LayoutKeyName,&LayoutValueName,&LayoutFile);
|
|
|
|
RtlInitUnicodeString(&FullLayoutPath,SYSTEMROOT_DIR);
|
2003-10-18 20:41:10 +00:00
|
|
|
|
2003-10-18 21:29:26 +00:00
|
|
|
if( !NT_SUCCESS(Status) ) {
|
2003-11-24 16:19:58 +00:00
|
|
|
DPRINT1("Got default locale but not layout file. (%08x)\n",
|
2003-10-18 21:29:26 +00:00
|
|
|
Status);
|
|
|
|
RtlFreeUnicodeString(&LayoutFile);
|
|
|
|
} else {
|
|
|
|
DPRINT("Read registry and got %wZ\n", &LayoutFile);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&LayoutKeyName);
|
2003-10-18 20:41:10 +00:00
|
|
|
|
2004-02-19 03:45:44 +00:00
|
|
|
AppendUnicodeString(&FullLayoutPath,&LayoutFile,FALSE);
|
2003-10-18 20:41:10 +00:00
|
|
|
|
2003-10-18 21:29:26 +00:00
|
|
|
DPRINT("Loading Keyboard DLL %wZ\n", &FullLayoutPath);
|
2003-10-18 20:41:10 +00:00
|
|
|
|
2003-10-18 21:29:26 +00:00
|
|
|
RtlFreeUnicodeString(&LayoutFile);
|
2003-10-18 20:41:10 +00:00
|
|
|
|
2004-03-15 19:06:35 +00:00
|
|
|
KeyboardLayoutWSTR =
|
|
|
|
ExAllocatePoolWithTag(PagedPool,
|
|
|
|
FullLayoutPath.Length + sizeof(WCHAR),
|
|
|
|
TAG_STRING);
|
2003-10-18 21:29:26 +00:00
|
|
|
|
|
|
|
if( !KeyboardLayoutWSTR ) {
|
2003-11-24 16:19:58 +00:00
|
|
|
DPRINT1("Couldn't allocate a string for the keyboard layout name.\n");
|
2003-10-18 21:29:26 +00:00
|
|
|
RtlFreeUnicodeString(&FullLayoutPath);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
memcpy(KeyboardLayoutWSTR,FullLayoutPath.Buffer,
|
2004-03-15 19:06:35 +00:00
|
|
|
FullLayoutPath.Length + sizeof(WCHAR));
|
|
|
|
KeyboardLayoutWSTR[FullLayoutPath.Length / sizeof(WCHAR)] = 0;
|
2003-10-18 21:29:26 +00:00
|
|
|
|
|
|
|
kbModule = EngLoadImage(KeyboardLayoutWSTR);
|
|
|
|
DPRINT( "Load Keyboard Layout: %S\n", KeyboardLayoutWSTR );
|
|
|
|
|
|
|
|
if( !kbModule )
|
2003-11-24 16:19:58 +00:00
|
|
|
DPRINT1( "Load Keyboard Layout: No %wZ\n", &FullLayoutPath );
|
2003-10-18 21:29:26 +00:00
|
|
|
}
|
2003-10-18 20:41:10 +00:00
|
|
|
|
|
|
|
RtlFreeUnicodeString(&FullLayoutPath);
|
|
|
|
}
|
|
|
|
|
2003-10-18 21:48:18 +00:00
|
|
|
if( !kbModule )
|
|
|
|
{
|
2003-11-24 16:19:58 +00:00
|
|
|
DPRINT1("Trying to load US Keyboard Layout\n");
|
2003-10-18 21:48:18 +00:00
|
|
|
kbModule = EngLoadImage(L"\\SystemRoot\\system32\\kbdus.dll");
|
|
|
|
|
|
|
|
if (!kbModule)
|
|
|
|
{
|
2003-11-24 16:19:58 +00:00
|
|
|
DPRINT1("Failed to load any Keyboard Layout\n");
|
2003-10-18 21:48:18 +00:00
|
|
|
return;
|
|
|
|
}
|
2003-10-18 20:41:10 +00:00
|
|
|
}
|
2003-10-18 21:29:26 +00:00
|
|
|
|
2003-10-18 20:41:10 +00:00
|
|
|
RtlInitAnsiString( &kbdProcedureName, "KbdLayerDescriptor" );
|
|
|
|
|
|
|
|
LdrGetProcedureAddress((PVOID)kbModule,
|
|
|
|
&kbdProcedureName,
|
|
|
|
0,
|
|
|
|
(PVOID*)&layerDescGetFn);
|
|
|
|
|
|
|
|
if( layerDescGetFn ) {
|
|
|
|
*pkKeyboardLayout = layerDescGetFn();
|
|
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
if( !*pkKeyboardLayout ) {
|
2003-11-24 16:19:58 +00:00
|
|
|
DPRINT1("Failed to load the keyboard layout.\n");
|
2003-07-29 23:03:01 +00:00
|
|
|
}
|
2003-10-18 20:41:10 +00:00
|
|
|
|
|
|
|
#undef XX_STATUS
|
2002-01-27 14:47:44 +00:00
|
|
|
}
|
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
PKBDTABLES W32kGetDefaultKeyLayout() {
|
2003-10-18 20:41:10 +00:00
|
|
|
PKBDTABLES pkKeyboardLayout = 0;
|
|
|
|
InitKbdLayout( (PVOID) &pkKeyboardLayout );
|
2003-10-09 06:13:05 +00:00
|
|
|
return pkKeyboardLayout;
|
|
|
|
}
|
|
|
|
|
2003-12-28 14:21:03 +00:00
|
|
|
BOOL FASTCALL
|
|
|
|
IntTranslateKbdMessage(LPMSG lpMsg,
|
|
|
|
HKL dwhkl)
|
2002-01-27 14:47:44 +00:00
|
|
|
{
|
2003-07-29 23:03:01 +00:00
|
|
|
static INT dead_char = 0;
|
|
|
|
LONG UState = 0;
|
|
|
|
WCHAR wp[2] = { 0 };
|
|
|
|
MSG NewMsg = { 0 };
|
2003-10-09 06:13:05 +00:00
|
|
|
PKBDTABLES keyLayout;
|
2003-11-24 00:22:53 +00:00
|
|
|
BOOL Result = FALSE;
|
|
|
|
DWORD ScanCode = 0;
|
2002-01-27 14:47:44 +00:00
|
|
|
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
keyLayout = PsGetWin32Thread()->KeyboardLayout;
|
2003-11-24 00:22:53 +00:00
|
|
|
if( !keyLayout )
|
|
|
|
return FALSE;
|
2003-10-09 06:13:05 +00:00
|
|
|
|
2003-12-28 14:21:03 +00:00
|
|
|
if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN)
|
2003-11-24 00:22:53 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2003-12-28 14:21:03 +00:00
|
|
|
ScanCode = (lpMsg->lParam >> 16) & 0xff;
|
2002-01-27 14:47:44 +00:00
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockQueueState;
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2003-12-28 14:21:03 +00:00
|
|
|
UState = ToUnicodeInner(lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff,
|
2003-10-09 06:13:05 +00:00
|
|
|
QueueKeyStateTable, wp, 2, 0,
|
|
|
|
keyLayout );
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2002-01-27 14:47:44 +00:00
|
|
|
if (UState == 1)
|
|
|
|
{
|
2003-12-28 14:21:03 +00:00
|
|
|
NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
|
2002-01-27 14:47:44 +00:00
|
|
|
if (dead_char)
|
|
|
|
{
|
2003-08-13 20:24:05 +00:00
|
|
|
ULONG i;
|
2003-11-24 00:22:53 +00:00
|
|
|
WCHAR first, second;
|
|
|
|
DPRINT("PREVIOUS DEAD CHAR: %c\n", dead_char);
|
|
|
|
|
|
|
|
for( i = 0; keyLayout->pDeadKey[i].dwBoth; i++ )
|
2002-01-27 14:47:44 +00:00
|
|
|
{
|
2003-11-24 00:22:53 +00:00
|
|
|
first = keyLayout->pDeadKey[i].dwBoth >> 16;
|
|
|
|
second = keyLayout->pDeadKey[i].dwBoth;
|
|
|
|
if (first == dead_char && second == wp[0])
|
|
|
|
{
|
|
|
|
wp[0] = keyLayout->pDeadKey[i].wchComposed;
|
|
|
|
dead_char = 0;
|
|
|
|
break;
|
|
|
|
}
|
2002-01-27 14:47:44 +00:00
|
|
|
}
|
2003-11-24 00:22:53 +00:00
|
|
|
|
|
|
|
DPRINT("FINAL CHAR: %c\n", wp[0]);
|
|
|
|
}
|
|
|
|
if (dead_char)
|
|
|
|
{
|
2003-12-28 14:21:03 +00:00
|
|
|
NewMsg.hwnd = lpMsg->hwnd;
|
2003-11-24 00:22:53 +00:00
|
|
|
NewMsg.wParam = dead_char;
|
2003-12-28 14:21:03 +00:00
|
|
|
NewMsg.lParam = lpMsg->lParam;
|
2003-11-24 00:22:53 +00:00
|
|
|
dead_char = 0;
|
2004-12-25 22:59:10 +00:00
|
|
|
MsqPostMessage(PsGetWin32Thread()->MessageQueue, &NewMsg, FALSE, QS_KEY);
|
2003-11-24 00:22:53 +00:00
|
|
|
}
|
|
|
|
|
2003-12-28 14:21:03 +00:00
|
|
|
NewMsg.hwnd = lpMsg->hwnd;
|
2003-07-29 23:03:01 +00:00
|
|
|
NewMsg.wParam = wp[0];
|
2003-12-28 14:21:03 +00:00
|
|
|
NewMsg.lParam = lpMsg->lParam;
|
|
|
|
DPRINT( "CHAR='%c' %04x %08x\n", wp[0], wp[0], lpMsg->lParam );
|
2004-12-25 22:59:10 +00:00
|
|
|
MsqPostMessage(PsGetWin32Thread()->MessageQueue, &NewMsg, FALSE, QS_KEY);
|
2003-11-24 00:22:53 +00:00
|
|
|
Result = TRUE;
|
2002-01-27 14:47:44 +00:00
|
|
|
}
|
|
|
|
else if (UState == -1)
|
|
|
|
{
|
|
|
|
NewMsg.message =
|
2003-12-28 14:21:03 +00:00
|
|
|
(lpMsg->message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
|
|
|
|
NewMsg.hwnd = lpMsg->hwnd;
|
2002-01-27 14:47:44 +00:00
|
|
|
NewMsg.wParam = wp[0];
|
2003-12-28 14:21:03 +00:00
|
|
|
NewMsg.lParam = lpMsg->lParam;
|
2002-01-27 14:47:44 +00:00
|
|
|
dead_char = wp[0];
|
2004-12-25 22:59:10 +00:00
|
|
|
MsqPostMessage(PsGetWin32Thread()->MessageQueue, &NewMsg, FALSE, QS_KEY);
|
2003-11-24 00:22:53 +00:00
|
|
|
Result = TRUE;
|
2002-01-27 14:47:44 +00:00
|
|
|
}
|
2003-11-24 00:22:53 +00:00
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockQueueState;
|
2003-11-24 00:22:53 +00:00
|
|
|
return Result;
|
2002-01-27 14:47:44 +00:00
|
|
|
}
|
2003-07-05 16:04:01 +00:00
|
|
|
|
2003-07-20 05:32:19 +00:00
|
|
|
DWORD
|
|
|
|
STDCALL
|
|
|
|
NtUserGetKeyboardState(
|
|
|
|
LPBYTE lpKeyState)
|
|
|
|
{
|
2003-11-24 00:22:53 +00:00
|
|
|
BOOL Result = TRUE;
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockQueueState;
|
2003-07-20 05:32:19 +00:00
|
|
|
if (lpKeyState) {
|
|
|
|
if(!NT_SUCCESS(MmCopyToCaller(lpKeyState, QueueKeyStateTable, 256)))
|
2003-11-24 00:22:53 +00:00
|
|
|
Result = FALSE;
|
2003-07-20 05:32:19 +00:00
|
|
|
}
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockQueueState;
|
2003-11-24 00:22:53 +00:00
|
|
|
return Result;
|
2003-07-20 05:32:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
|
|
STDCALL
|
|
|
|
NtUserSetKeyboardState(
|
|
|
|
LPBYTE lpKeyState)
|
|
|
|
{
|
2003-11-24 00:22:53 +00:00
|
|
|
BOOL Result = TRUE;
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockQueueState;
|
2003-11-24 00:22:53 +00:00
|
|
|
if (lpKeyState) {
|
|
|
|
if(! NT_SUCCESS(MmCopyFromCaller(QueueKeyStateTable, lpKeyState, 256)))
|
|
|
|
Result = FALSE;
|
|
|
|
}
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockQueueState;
|
2003-11-24 00:22:53 +00:00
|
|
|
|
|
|
|
return Result;
|
2003-07-20 05:32:19 +00:00
|
|
|
}
|
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
static UINT VkToScan( UINT Code, BOOL ExtCode, PKBDTABLES pkKT ) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for( i = 0; i < pkKT->bMaxVSCtoVK; i++ ) {
|
|
|
|
if( pkKT->pusVSCtoVK[i] == Code ) { return i; }
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT ScanToVk( UINT Code, BOOL ExtKey, PKBDTABLES pkKT ) {
|
2003-11-24 00:22:53 +00:00
|
|
|
if( !pkKT ) {
|
|
|
|
DPRINT("ScanToVk: No layout\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
if( ExtKey ) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for( i = 0; pkKT->pVSCtoVK_E0[i].Vsc; i++ ) {
|
|
|
|
if( pkKT->pVSCtoVK_E0[i].Vsc == Code )
|
|
|
|
return pkKT->pVSCtoVK_E0[i].Vk & 0xff;
|
|
|
|
}
|
|
|
|
for( i = 0; pkKT->pVSCtoVK_E1[i].Vsc; i++ ) {
|
|
|
|
if( pkKT->pVSCtoVK_E1[i].Vsc == Code )
|
|
|
|
return pkKT->pVSCtoVK_E1[i].Vk & 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
if( Code >= pkKT->bMaxVSCtoVK ) { return 0; }
|
|
|
|
return pkKT->pusVSCtoVK[Code] & 0xff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map a virtual key code, or virtual scan code, to a scan code, key code,
|
|
|
|
* or unshifted unicode character.
|
|
|
|
*
|
|
|
|
* Code: See Below
|
|
|
|
* Type:
|
|
|
|
* 0 -- Code is a virtual key code that is converted into a virtual scan code
|
|
|
|
* that does not distinguish between left and right shift keys.
|
|
|
|
* 1 -- Code is a virtual scan code that is converted into a virtual key code
|
|
|
|
* that does not distinguish between left and right shift keys.
|
|
|
|
* 2 -- Code is a virtual key code that is converted into an unshifted unicode
|
|
|
|
* character.
|
|
|
|
* 3 -- Code is a virtual scan code that is converted into a virtual key code
|
|
|
|
* that distinguishes left and right shift keys.
|
|
|
|
* KeyLayout: Keyboard layout handle (currently, unused)
|
|
|
|
*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
2003-11-24 00:22:53 +00:00
|
|
|
static UINT IntMapVirtualKeyEx( UINT Code, UINT Type, PKBDTABLES keyLayout ) {
|
2003-10-09 06:13:05 +00:00
|
|
|
UINT ret = 0;
|
|
|
|
|
|
|
|
switch( Type ) {
|
|
|
|
case 0:
|
|
|
|
if( Code == VK_RSHIFT ) Code = VK_LSHIFT;
|
|
|
|
if( Code == VK_RMENU ) Code = VK_LMENU;
|
|
|
|
if( Code == VK_RCONTROL ) Code = VK_LCONTROL;
|
|
|
|
ret = VkToScan( Code, FALSE, keyLayout );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
ret =
|
|
|
|
DontDistinguishShifts
|
2003-11-24 00:22:53 +00:00
|
|
|
(IntMapVirtualKeyEx( Code, 3, keyLayout ) );
|
2003-10-09 06:13:05 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: {
|
|
|
|
WCHAR wp[2];
|
|
|
|
|
|
|
|
ret = VkToScan( Code, FALSE, keyLayout );
|
|
|
|
ToUnicodeInner( Code, ret, 0, wp, 2, 0, keyLayout );
|
|
|
|
ret = wp[0];
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case 3:
|
2004-02-19 06:59:50 +00:00
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
ret = ScanToVk( Code, FALSE, keyLayout );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-11-24 00:22:53 +00:00
|
|
|
UINT
|
|
|
|
STDCALL
|
|
|
|
NtUserMapVirtualKeyEx( UINT Code, UINT Type, DWORD keyboardId, HKL dwhkl ) {
|
|
|
|
PKBDTABLES keyLayout = PsGetWin32Thread() ?
|
|
|
|
PsGetWin32Thread()->KeyboardLayout : 0;
|
|
|
|
|
|
|
|
if( !keyLayout ) return 0;
|
|
|
|
|
|
|
|
return IntMapVirtualKeyEx( Code, Type, keyLayout );
|
|
|
|
}
|
|
|
|
|
2003-10-09 06:13:05 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
STDCALL
|
|
|
|
NtUserToUnicodeEx(
|
|
|
|
UINT wVirtKey,
|
|
|
|
UINT wScanCode,
|
|
|
|
PBYTE lpKeyState,
|
|
|
|
LPWSTR pwszBuff,
|
|
|
|
int cchBuff,
|
|
|
|
UINT wFlags,
|
|
|
|
HKL dwhkl ) {
|
|
|
|
BYTE KeyStateBuf[0x100];
|
|
|
|
PWCHAR OutPwszBuff = 0;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf,
|
|
|
|
lpKeyState,
|
|
|
|
sizeof(KeyStateBuf))) ) {
|
2003-11-24 16:19:58 +00:00
|
|
|
DPRINT1( "Couldn't copy key state from caller.\n" );
|
2003-10-09 06:13:05 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2004-02-19 21:12:11 +00:00
|
|
|
OutPwszBuff = ExAllocatePoolWithTag(NonPagedPool,sizeof(WCHAR) * cchBuff, TAG_STRING);
|
2003-10-09 06:13:05 +00:00
|
|
|
if( !OutPwszBuff ) {
|
2003-11-24 16:19:58 +00:00
|
|
|
DPRINT1( "ExAllocatePool(%d) failed\n", sizeof(WCHAR) * cchBuff);
|
2003-10-09 06:13:05 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
RtlZeroMemory( OutPwszBuff, sizeof( WCHAR ) * cchBuff );
|
|
|
|
|
|
|
|
ret = ToUnicodeEx( wVirtKey,
|
|
|
|
wScanCode,
|
|
|
|
KeyStateBuf,
|
|
|
|
OutPwszBuff,
|
|
|
|
cchBuff,
|
|
|
|
wFlags,
|
|
|
|
dwhkl );
|
|
|
|
|
|
|
|
MmCopyToCaller(pwszBuff,OutPwszBuff,sizeof(WCHAR)*cchBuff);
|
|
|
|
ExFreePool(OutPwszBuff);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int W32kSimpleToupper( int ch ) {
|
|
|
|
if( ch >= 'a' && ch <= 'z' ) ch = ch - 'a' + 'A';
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
|
|
STDCALL
|
|
|
|
NtUserGetKeyNameText( LONG lParam, LPWSTR lpString, int nSize ) {
|
|
|
|
int i;
|
|
|
|
DWORD ret = 0;
|
|
|
|
UINT CareVk = 0;
|
|
|
|
UINT VkCode = 0;
|
|
|
|
UINT ScanCode = (lParam >> 16) & 0xff;
|
|
|
|
BOOL ExtKey = lParam & (1<<24) ? TRUE : FALSE;
|
|
|
|
PKBDTABLES keyLayout =
|
|
|
|
PsGetWin32Thread() ?
|
|
|
|
PsGetWin32Thread()->KeyboardLayout : 0;
|
|
|
|
|
|
|
|
if( !keyLayout || nSize < 1 ) return 0;
|
|
|
|
|
|
|
|
if( lParam & (1<<25) ) {
|
|
|
|
CareVk = VkCode = ScanToVk( ScanCode, ExtKey, keyLayout );
|
|
|
|
if( VkCode == VK_LSHIFT || VkCode == VK_RSHIFT )
|
|
|
|
VkCode = VK_LSHIFT;
|
|
|
|
if( VkCode == VK_LCONTROL || VkCode == VK_RCONTROL )
|
|
|
|
VkCode = VK_LCONTROL;
|
|
|
|
if( VkCode == VK_LMENU || VkCode == VK_RMENU )
|
|
|
|
VkCode = VK_LMENU;
|
|
|
|
} else {
|
|
|
|
VkCode = ScanToVk( ScanCode, ExtKey, keyLayout );
|
|
|
|
}
|
|
|
|
|
|
|
|
VSC_LPWSTR *KeyNames = 0;
|
|
|
|
|
|
|
|
if( CareVk != VkCode )
|
|
|
|
ScanCode = VkToScan( VkCode, ExtKey, keyLayout );
|
|
|
|
|
|
|
|
if( ExtKey )
|
|
|
|
KeyNames = keyLayout->pKeyNamesExt;
|
|
|
|
else
|
|
|
|
KeyNames = keyLayout->pKeyNames;
|
|
|
|
|
|
|
|
for( i = 0; KeyNames[i].pwsz; i++ ) {
|
|
|
|
if( KeyNames[i].vsc == ScanCode ) {
|
|
|
|
UINT StrLen = wcslen(KeyNames[i].pwsz);
|
|
|
|
UINT StrMax = StrLen > (nSize - 1) ? (nSize - 1) : StrLen;
|
|
|
|
WCHAR null_wc = 0;
|
|
|
|
if( NT_SUCCESS( MmCopyToCaller( lpString,
|
|
|
|
KeyNames[i].pwsz,
|
|
|
|
StrMax * sizeof(WCHAR) ) ) &&
|
|
|
|
NT_SUCCESS( MmCopyToCaller( lpString + StrMax,
|
|
|
|
&null_wc,
|
|
|
|
sizeof( WCHAR ) ) ) ) {
|
|
|
|
ret = StrMax;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ret == 0 ) {
|
|
|
|
WCHAR UCName[2];
|
|
|
|
|
2003-11-24 00:22:53 +00:00
|
|
|
UCName[0] = W32kSimpleToupper(IntMapVirtualKeyEx( VkCode, 2, keyLayout ));
|
2003-10-09 06:13:05 +00:00
|
|
|
UCName[1] = 0;
|
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
if( !NT_SUCCESS(MmCopyToCaller( lpString, UCName, 2 * sizeof(WCHAR) )) )
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Filter this message according to the current key layout, setting wParam
|
|
|
|
* appropriately.
|
|
|
|
*/
|
|
|
|
|
|
|
|
VOID FASTCALL W32kKeyProcessMessage(LPMSG Msg, PKBDTABLES KeyboardLayout) {
|
2003-11-24 00:22:53 +00:00
|
|
|
DWORD ScanCode = 0, ModifierBits = 0;
|
|
|
|
DWORD i = 0;
|
2003-11-25 01:09:06 +00:00
|
|
|
DWORD BaseMapping = 0;
|
2003-11-24 00:22:53 +00:00
|
|
|
DWORD RawVk = 0;
|
|
|
|
static WORD NumpadConversion[][2] =
|
|
|
|
{ { VK_DELETE, VK_DECIMAL },
|
|
|
|
{ VK_INSERT, VK_NUMPAD0 },
|
|
|
|
{ VK_END, VK_NUMPAD1 },
|
|
|
|
{ VK_DOWN, VK_NUMPAD2 },
|
|
|
|
{ VK_NEXT, VK_NUMPAD3 },
|
|
|
|
{ VK_LEFT, VK_NUMPAD4 },
|
|
|
|
{ VK_CLEAR, VK_NUMPAD5 },
|
|
|
|
{ VK_RIGHT, VK_NUMPAD6 },
|
|
|
|
{ VK_HOME, VK_NUMPAD7 },
|
|
|
|
{ VK_UP, VK_NUMPAD8 },
|
|
|
|
{ VK_PRIOR, VK_NUMPAD9 },
|
|
|
|
{ 0,0 } };
|
|
|
|
|
|
|
|
if( !KeyboardLayout || !Msg ||
|
|
|
|
(Msg->message != WM_KEYDOWN && Msg->message != WM_SYSKEYDOWN &&
|
|
|
|
Msg->message != WM_KEYUP && Msg->message != WM_SYSKEYUP) )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockQueueState;
|
2003-11-24 00:22:53 +00:00
|
|
|
|
|
|
|
/* arty -- handle numpad -- On real windows, the actual key produced
|
|
|
|
* by the messaging layer is different based on the state of numlock. */
|
|
|
|
ModifierBits = ModBits(KeyboardLayout,QueueKeyStateTable);
|
|
|
|
|
|
|
|
/* Get the raw scan code, so we can look up whether the key is a numpad
|
2004-02-19 03:45:44 +00:00
|
|
|
* key
|
|
|
|
*
|
|
|
|
* Shift and the LP_EXT_BIT cancel. */
|
2003-11-24 00:22:53 +00:00
|
|
|
ScanCode = (Msg->lParam >> 16) & 0xff;
|
2003-11-25 01:09:06 +00:00
|
|
|
BaseMapping = Msg->wParam =
|
|
|
|
IntMapVirtualKeyEx( ScanCode, 1, KeyboardLayout );
|
2004-07-04 17:08:40 +00:00
|
|
|
if( ScanCode >= KeyboardLayout->bMaxVSCtoVK )
|
|
|
|
RawVk = 0;
|
|
|
|
else
|
|
|
|
RawVk = KeyboardLayout->pusVSCtoVK[ScanCode];
|
2003-11-24 00:22:53 +00:00
|
|
|
|
2003-11-25 01:09:06 +00:00
|
|
|
if ((ModifierBits & NUMLOCK_BIT) &&
|
2004-02-19 06:59:50 +00:00
|
|
|
!(ModifierBits & GetShiftBit(KeyboardLayout, VK_SHIFT)) &&
|
2004-02-19 03:45:44 +00:00
|
|
|
(RawVk & KNUMP) &&
|
|
|
|
!(Msg->lParam & LP_EXT_BIT))
|
2003-11-24 00:22:53 +00:00
|
|
|
{
|
|
|
|
/* The key in question is a numpad key. Search for a translation. */
|
|
|
|
for (i = 0; NumpadConversion[i][0]; i++)
|
|
|
|
{
|
2004-02-19 03:45:44 +00:00
|
|
|
if ((BaseMapping & 0xff) == NumpadConversion[i][0]) /* RawVk? */
|
2003-11-24 00:22:53 +00:00
|
|
|
{
|
|
|
|
Msg->wParam = NumpadConversion[i][1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-25 22:28:00 +00:00
|
|
|
DPRINT("Key: [%04x -> %04x]\n", BaseMapping, Msg->wParam);
|
2003-11-25 01:09:06 +00:00
|
|
|
|
2003-11-24 00:22:53 +00:00
|
|
|
/* Now that we have the VK, we can set the keymap appropriately
|
|
|
|
* This is a better place for this code, as it's guaranteed to be
|
|
|
|
* run, unlike translate message. */
|
|
|
|
if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN)
|
|
|
|
{
|
|
|
|
SetKeyState( ScanCode, Msg->wParam, Msg->lParam & LP_EXT_BIT,
|
|
|
|
TRUE ); /* Strike key */
|
|
|
|
}
|
|
|
|
else if (Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP)
|
|
|
|
{
|
|
|
|
SetKeyState( ScanCode, Msg->wParam, Msg->lParam & LP_EXT_BIT,
|
|
|
|
FALSE ); /* Release key */
|
|
|
|
}
|
2003-07-20 05:32:19 +00:00
|
|
|
|
2004-02-19 06:59:50 +00:00
|
|
|
/* We need to unset SYSKEYDOWN if the ALT key is an ALT+Gr */
|
|
|
|
if( QueueKeyStateTable[VK_RMENU] & KS_DOWN_BIT ) {
|
|
|
|
if( Msg->message == WM_SYSKEYDOWN ) Msg->message = WM_KEYDOWN;
|
|
|
|
else Msg->message = WM_KEYUP;
|
|
|
|
}
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockQueueState;
|
2003-11-24 00:22:53 +00:00
|
|
|
}
|
2003-05-18 17:16:18 +00:00
|
|
|
/* EOF */
|