-/*
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
- * PURPOSE: Messages
+ * PURPOSE: Keyboard functions
* FILE: subsys/win32k/ntuser/keyboard.c
- * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
- * REVISION HISTORY:
- * 06-06-2001 CSH Created
+ * PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * Rafal Harabien (rafalh@reactos.org)
*/
-/* INCLUDES ******************************************************************/
-
#include <win32k.h>
+DBG_DEFAULT_CHANNEL(UserKbd);
-#define NDEBUG
-#include <debug.h>
-
-
-/* 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
-/* Scan Codes */
-#define SC_KEY_UP 0x8000
-/* lParam bits */
-#define LP_EXT_BIT (1<<24)
-/* From kbdxx.c -- Key changes with numlock */
-#define KNUMP 0x400
-
-
-BYTE gQueueKeyStateTable[256];
-
-
+BYTE gafAsyncKeyState[0x100];
+static PKEYBOARD_INDICATOR_TRANSLATION gpKeyboardIndicatorTrans = NULL;
/* FUNCTIONS *****************************************************************/
-/* Initialization -- Right now, just zero the key state and init the lock */
+/*
+ * InitKeyboardImpl
+ *
+ * Initialization -- Right now, just zero the key state
+ */
INIT_FUNCTION
NTSTATUS
NTAPI
InitKeyboardImpl(VOID)
{
- RtlZeroMemory(&gQueueKeyStateTable,0x100);
- return STATUS_SUCCESS;
+ RtlZeroMemory(&gafAsyncKeyState, sizeof(gafAsyncKeyState));
+ return STATUS_SUCCESS;
}
-/*** Statics used by TranslateMessage ***/
+/*
+ * IntKeyboardGetIndicatorTrans
+ *
+ * Asks the keyboard driver to send a small table that shows which
+ * lights should connect with which scancodes
+ */
+static
+NTSTATUS APIENTRY
+IntKeyboardGetIndicatorTrans(HANDLE hKeyboardDevice,
+ PKEYBOARD_INDICATOR_TRANSLATION *ppIndicatorTrans)
+{
+ NTSTATUS Status;
+ DWORD dwSize = 0;
+ IO_STATUS_BLOCK Block;
+ PKEYBOARD_INDICATOR_TRANSLATION pRet;
-/*** Shift state code was out of hand, sorry. --- arty */
+ dwSize = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
-static UINT DontDistinguishShifts( UINT ret )
-{
- if( ret == VK_LSHIFT || ret == VK_RSHIFT )
- ret = VK_SHIFT;
- if( ret == VK_LCONTROL || ret == VK_RCONTROL )
- ret = VK_CONTROL;
- if( ret == VK_LMENU || ret == VK_RMENU )
- ret = VK_MENU;
- return ret;
+ pRet = ExAllocatePoolWithTag(PagedPool,
+ dwSize,
+ USERTAG_KBDTABLE);
+
+ while (pRet)
+ {
+ Status = NtDeviceIoControlFile(hKeyboardDevice,
+ NULL,
+ NULL,
+ NULL,
+ &Block,
+ IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
+ NULL, 0,
+ pRet, dwSize);
+
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ break;
+
+ ExFreePoolWithTag(pRet, USERTAG_KBDTABLE);
+
+ dwSize += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
+
+ pRet = ExAllocatePoolWithTag(PagedPool,
+ dwSize,
+ USERTAG_KBDTABLE);
+ }
+
+ if (!pRet)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(pRet, USERTAG_KBDTABLE);
+ return Status;
+ }
+
+ *ppIndicatorTrans = pRet;
+ return Status;
}
-static VOID APIENTRY SetKeyState(DWORD key, DWORD vk, DWORD ext, BOOL down)
+/*
+ * IntKeyboardUpdateLeds
+ *
+ * Sends the keyboard commands to turn on/off the lights
+ */
+static
+NTSTATUS APIENTRY
+IntKeyboardUpdateLeds(HANDLE hKeyboardDevice,
+ WORD wScanCode,
+ BOOL bEnabled,
+ PKEYBOARD_INDICATOR_TRANSLATION pIndicatorTrans)
{
- ASSERT(vk <= 0xff);
-
- /* Special handling for toggles like numpad and caps lock */
- if (vk == VK_CAPITAL || vk == VK_NUMLOCK)
- {
- if (down)
- gQueueKeyStateTable[vk] ^= KS_LOCK_BIT;
- }
-
- if (vk == VK_SHIFT)
- vk = ext ? VK_RSHIFT : VK_LSHIFT;
- if (vk == VK_CONTROL)
- vk = ext ? VK_RCONTROL : VK_LCONTROL;
- if (vk == VK_MENU)
- vk = ext ? VK_RMENU : VK_LMENU;
-
- if (down)
- gQueueKeyStateTable[vk] |= KS_DOWN_BIT;
- else
- gQueueKeyStateTable[vk] &= ~KS_DOWN_MASK;
-
- if (vk == VK_LSHIFT || vk == VK_RSHIFT)
- {
- if ((gQueueKeyStateTable[VK_LSHIFT] & KS_DOWN_BIT) ||
- (gQueueKeyStateTable[VK_RSHIFT] & KS_DOWN_BIT))
- {
- gQueueKeyStateTable[VK_SHIFT] |= KS_DOWN_BIT;
- }
- else
- {
- gQueueKeyStateTable[VK_SHIFT] &= ~KS_DOWN_MASK;
- }
- }
-
- if (vk == VK_LCONTROL || vk == VK_RCONTROL)
- {
- if ((gQueueKeyStateTable[VK_LCONTROL] & KS_DOWN_BIT) ||
- (gQueueKeyStateTable[VK_RCONTROL] & KS_DOWN_BIT))
- {
- gQueueKeyStateTable[VK_CONTROL] |= KS_DOWN_BIT;
- }
- else
- {
- gQueueKeyStateTable[VK_CONTROL] &= ~KS_DOWN_MASK;
- }
- }
-
- if (vk == VK_LMENU || vk == VK_RMENU)
- {
- if ((gQueueKeyStateTable[VK_LMENU] & KS_DOWN_BIT) ||
- (gQueueKeyStateTable[VK_RMENU] & KS_DOWN_BIT))
- {
- gQueueKeyStateTable[VK_MENU] |= KS_DOWN_BIT;
- }
- else
- {
- gQueueKeyStateTable[VK_MENU] &= ~KS_DOWN_MASK;
- }
- }
+ NTSTATUS Status;
+ UINT i;
+ static KEYBOARD_INDICATOR_PARAMETERS Indicators;
+ IO_STATUS_BLOCK Block;
+
+ if (!pIndicatorTrans)
+ return STATUS_NOT_SUPPORTED;
+
+ for (i = 0; i < pIndicatorTrans->NumberOfIndicatorKeys; i++)
+ {
+ if (pIndicatorTrans->IndicatorList[i].MakeCode == wScanCode)
+ {
+ if (bEnabled)
+ Indicators.LedFlags |= pIndicatorTrans->IndicatorList[i].IndicatorFlags;
+ else
+ Indicators.LedFlags = ~pIndicatorTrans->IndicatorList[i].IndicatorFlags;
+
+ /* Update the lights on the hardware */
+ Status = NtDeviceIoControlFile(hKeyboardDevice,
+ NULL,
+ NULL,
+ NULL,
+ &Block,
+ IOCTL_KEYBOARD_SET_INDICATORS,
+ &Indicators, sizeof(Indicators),
+ NULL, 0);
+
+ return Status;
+ }
+ }
+
+ return STATUS_SUCCESS;
}
-VOID DumpKeyState( PBYTE KeyState )
+/*
+ * IntSimplifyVk
+ *
+ * Changes virtual keys which distinguish between left and right hand, to keys which don't distinguish
+ */
+static
+WORD
+IntSimplifyVk(WORD wVk)
{
- int i;
-
- DbgPrint( "KeyState { " );
- for( i = 0; i < 0x100; i++ )
- {
- if( KeyState[i] )
- DbgPrint( "%02x(%02x) ", i, KeyState[i] );
- }
- DbgPrint( "};\n" );
+ switch (wVk)
+ {
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ return VK_SHIFT;
+
+ case VK_LCONTROL:
+ case VK_RCONTROL:
+ return VK_CONTROL;
+
+ case VK_LMENU:
+ case VK_RMENU:
+ return VK_MENU;
+
+ default:
+ return wVk;
+ }
}
-static BYTE KeysSet( PKBDTABLES pkKT, PBYTE KeyState,
- int FakeModLeft, int FakeModRight )
+/*
+ * IntFixVk
+ *
+ * Changes virtual keys which don't not distinguish between left and right hand to proper keys
+ */
+static
+WORD
+IntFixVk(WORD wVk, BOOL bExt)
{
- if( !KeyState || !pkKT )
- return 0;
+ switch (wVk)
+ {
+ case VK_SHIFT:
+ return bExt ? VK_RSHIFT : VK_LSHIFT;
- /* Search special codes first */
- if( FakeModLeft && KeyState[FakeModLeft] )
- return KeyState[FakeModLeft];
- else if( FakeModRight && KeyState[FakeModRight] )
- return KeyState[FakeModRight];
+ case VK_CONTROL:
+ return bExt ? VK_RCONTROL : VK_LCONTROL;
- return 0;
-}
+ case VK_MENU:
+ return bExt ? VK_RMENU : VK_LMENU;
-/* 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 */
+ default:
+ return wVk;
+ }
+}
-static DWORD FASTCALL GetShiftBit( PKBDTABLES pkKT, DWORD Vk )
+/*
+ * IntGetVkOtherSide
+ *
+ * Gets other side of vk: right -> left, left -> right
+ */
+static
+WORD
+IntGetVkOtherSide(WORD wVk)
{
- int i;
+ switch (wVk)
+ {
+ case VK_LSHIFT: return VK_RSHIFT;
+ case VK_RSHIFT: return VK_LSHIFT;
- for( i = 0; pkKT->pCharModifiers->pVkToBit[i].Vk; i++ )
- if( pkKT->pCharModifiers->pVkToBit[i].Vk == Vk )
- return pkKT->pCharModifiers->pVkToBit[i].ModBits;
+ case VK_LCONTROL: return VK_RCONTROL;
+ case VK_RCONTROL: return VK_LCONTROL;
- return 0;
+ case VK_LMENU: return VK_RMENU;
+ case VK_RMENU: return VK_LMENU;
+
+ default: return wVk;
+ }
}
-static DWORD ModBits( PKBDTABLES pkKT, PBYTE KeyState )
+/*
+ * IntTranslateNumpadKey
+ *
+ * Translates numpad keys when numlock is enabled
+ */
+static
+WORD
+IntTranslateNumpadKey(WORD wVk)
{
- DWORD ModBits = 0;
+ switch (wVk)
+ {
+ case VK_INSERT: return VK_NUMPAD0;
+ case VK_END: return VK_NUMPAD1;
+ case VK_DOWN: return VK_NUMPAD2;
+ case VK_NEXT: return VK_NUMPAD3;
+ case VK_LEFT: return VK_NUMPAD4;
+ case VK_CLEAR: return VK_NUMPAD5;
+ case VK_RIGHT: return VK_NUMPAD6;
+ case VK_HOME: return VK_NUMPAD7;
+ case VK_UP: return VK_NUMPAD8;
+ case VK_PRIOR: return VK_NUMPAD9;
+ case VK_DELETE: return VK_DECIMAL;
+ default: return wVk;
+ }
+}
+
+/*
+ * IntGetModifiers
+ *
+ * Returns a value that indicates if the key is a modifier key, and
+ * which one.
+ */
+static
+UINT FASTCALL
+IntGetModifiers(PBYTE pKeyState)
+{
+ UINT fModifiers = 0;
+
+ if (pKeyState[VK_SHIFT] & KS_DOWN_BIT)
+ fModifiers |= MOD_SHIFT;
+
+ if (pKeyState[VK_CONTROL] & KS_DOWN_BIT)
+ fModifiers |= MOD_CONTROL;
- if( !KeyState )
- return 0;
+ if (pKeyState[VK_MENU] & KS_DOWN_BIT)
+ fModifiers |= MOD_ALT;
- /* DumpKeyState( KeyState ); */
+ if ((pKeyState[VK_LWIN] | pKeyState[VK_RWIN]) & KS_DOWN_BIT)
+ fModifiers |= MOD_WIN;
- if (KeysSet( pkKT, KeyState, VK_LSHIFT, VK_RSHIFT ) &
- KS_DOWN_BIT)
- ModBits |= GetShiftBit( pkKT, VK_SHIFT );
+ return fModifiers;
+}
- if (KeysSet( pkKT, KeyState, VK_SHIFT, 0 ) &
- KS_DOWN_BIT)
- ModBits |= GetShiftBit( pkKT, VK_SHIFT );
+/*
+ * IntGetShiftBit
+ *
+ * Search the keyboard layout modifiers table for the shift bit
+ */
+static
+DWORD FASTCALL
+IntGetShiftBit(PKBDTABLES pKbdTbl, WORD wVk)
+{
+ unsigned i;
- if (KeysSet( pkKT, KeyState, VK_LCONTROL, VK_RCONTROL ) &
- KS_DOWN_BIT )
- ModBits |= GetShiftBit( pkKT, VK_CONTROL );
+ for (i = 0; pKbdTbl->pCharModifiers->pVkToBit[i].Vk; i++)
+ if (pKbdTbl->pCharModifiers->pVkToBit[i].Vk == wVk)
+ return pKbdTbl->pCharModifiers->pVkToBit[i].ModBits;
- if (KeysSet( pkKT, KeyState, VK_CONTROL, 0 ) &
- KS_DOWN_BIT )
- ModBits |= GetShiftBit( pkKT, VK_CONTROL );
+ return 0;
+}
- if (KeysSet( pkKT, KeyState, VK_LMENU, VK_RMENU ) &
- KS_DOWN_BIT )
- ModBits |= GetShiftBit( pkKT, VK_MENU );
+/*
+ * IntGetModBits
+ *
+ * Gets layout specific modification bits, for example KBDSHIFT, KBDCTRL, KBDALT
+ */
+static
+DWORD
+IntGetModBits(PKBDTABLES pKbdTbl, PBYTE pKeyState)
+{
+ DWORD i, dwModBits = 0;
- /* Handle Alt+Gr */
- if (pkKT->fLocalFlags & 0x1)
- if (KeysSet( pkKT, KeyState, VK_RMENU, 0 ) &
- KS_DOWN_BIT)
- ModBits |= GetShiftBit( pkKT, VK_CONTROL );
+ /* DumpKeyState( KeyState ); */
- /* Deal with VK_CAPITAL */
- if (KeysSet( pkKT, KeyState, VK_CAPITAL, 0 ) & KS_LOCK_BIT)
- {
- ModBits |= CAPITAL_BIT;
- }
+ for (i = 0; pKbdTbl->pCharModifiers->pVkToBit[i].Vk; i++)
+ if (pKeyState[pKbdTbl->pCharModifiers->pVkToBit[i].Vk] & KS_DOWN_BIT)
+ dwModBits |= pKbdTbl->pCharModifiers->pVkToBit[i].ModBits;
- /* Deal with VK_NUMLOCK */
- if (KeysSet( pkKT, KeyState, VK_NUMLOCK, 0 ) & KS_LOCK_BIT)
- {
- ModBits |= NUMLOCK_BIT;
- }
+ /* Handle Alt+Gr */
+ if ((pKbdTbl->fLocaleFlags & KLLF_ALTGR) && (pKeyState[VK_RMENU] & KS_DOWN_BIT))
+ dwModBits |= IntGetShiftBit(pKbdTbl, VK_CONTROL); /* Don't use KBDCTRL here */
- DPRINT( "Current Mod Bits: %x\n", ModBits );
+ TRACE("Current Mod Bits: %lx\n", dwModBits);
- return ModBits;
+ return dwModBits;
}
-static BOOL TryToTranslateChar(WORD wVirtKey,
- DWORD ModBits,
- PBOOL pbDead,
- PBOOL pbLigature,
- PWCHAR pwcTranslatedChar,
- PKBDTABLES keyLayout )
+/*
+ * IntTranslateChar
+ *
+ * Translates virtual key to character
+ */
+static
+BOOL
+IntTranslateChar(WORD wVirtKey,
+ PBYTE pKeyState,
+ PBOOL pbDead,
+ PBOOL pbLigature,
+ PWCHAR pwcTranslatedChar,
+ PKBDTABLES pKbdTbl)
{
- PVK_TO_WCHAR_TABLE vtwTbl;
- PVK_TO_WCHARS10 vkPtr;
- size_t size_this_entry;
- int nMod;
- DWORD CapsMod = 0, CapsState = 0;
-
- CapsState = ModBits & ~MOD_BITS_MASK;
- ModBits = ModBits & MOD_BITS_MASK;
-
- DPRINT ( "TryToTranslate: %04x %x\n", wVirtKey, ModBits );
-
- if (ModBits > keyLayout->pCharModifiers->wMaxModBits)
- {
- return FALSE;
- }
-
- 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)
- {
- if( wVirtKey == (vkPtr->VirtualKey & 0xff) )
- {
- CapsMod = keyLayout->pCharModifiers->ModNumber
- [ModBits ^
- ((CapsState & CAPITAL_BIT) ? vkPtr->Attributes : 0)];
-
- if( CapsMod >= keyLayout->pVkToWcharTable[nMod].nModifications )
- {
- return FALSE;
- }
+ PVK_TO_WCHAR_TABLE pVkToVchTbl;
+ PVK_TO_WCHARS10 pVkToVch;
+ DWORD i, dwModBits, dwVkModBits, dwModNumber = 0;
+ WCHAR wch;
+ BOOL bAltGr;
+ WORD wCaplokAttr;
- if( vkPtr->wch[CapsMod] == WCH_NONE )
- {
- return FALSE;
- }
+ dwModBits = pKeyState ? IntGetModBits(pKbdTbl, pKeyState) : 0;
+ bAltGr = pKeyState && (pKbdTbl->fLocaleFlags & KLLF_ALTGR) && (pKeyState[VK_RMENU] & KS_DOWN_BIT);
+ wCaplokAttr = bAltGr ? CAPLOKALTGR : CAPLOK;
- *pbDead = vkPtr->wch[CapsMod] == WCH_DEAD;
- *pbLigature = vkPtr->wch[CapsMod] == WCH_LGTR;
- *pwcTranslatedChar = vkPtr->wch[CapsMod];
+ TRACE("TryToTranslate: %04x %x\n", wVirtKey, dwModBits);
- DPRINT("%d %04x: CapsMod %08x CapsState %08x Char %04x\n",
- nMod, wVirtKey,
- CapsMod, CapsState, *pwcTranslatedChar);
+ if (dwModBits > pKbdTbl->pCharModifiers->wMaxModBits)
+ {
+ TRACE("dwModBits %x > wMaxModBits %x\n", dwModBits, pKbdTbl->pCharModifiers->wMaxModBits);
+ return FALSE;
+ }
- if( *pbDead )
+ for (i = 0; pKbdTbl->pVkToWcharTable[i].pVkToWchars; i++)
+ {
+ pVkToVchTbl = &pKbdTbl->pVkToWcharTable[i];
+ pVkToVch = (PVK_TO_WCHARS10)(pVkToVchTbl->pVkToWchars);
+ while (pVkToVch->VirtualKey)
+ {
+ if (wVirtKey == (pVkToVch->VirtualKey & 0xFF))
{
- 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: %p\n", wVirtKey, vkPtr );
- return FALSE;
- }
- *pwcTranslatedChar = vkPtr->wch[CapsMod];
+ dwVkModBits = dwModBits;
+
+ /* If CapsLock is enabled for this key and locked, add SHIFT bit */
+ if ((pVkToVch->Attributes & wCaplokAttr) &&
+ pKeyState &&
+ (pKeyState[VK_CAPITAL] & KS_LOCK_BIT))
+ {
+ /* Note: we use special value here instead of getting VK_SHIFT mod bit - it's verified */
+ dwVkModBits ^= KBDSHIFT;
+ }
+
+ /* If ALT without CTRL has ben used, remove ALT flag */
+ if ((dwVkModBits & (KBDALT|KBDCTRL)) == KBDALT)
+ dwVkModBits &= ~KBDALT;
+
+ if (dwVkModBits > pKbdTbl->pCharModifiers->wMaxModBits)
+ break;
+
+ /* Get modification number */
+ dwModNumber = pKbdTbl->pCharModifiers->ModNumber[dwVkModBits];
+ if (dwModNumber >= pVkToVchTbl->nModifications)
+ {
+ TRACE("dwModNumber %u >= nModifications %u\n", dwModNumber, pVkToVchTbl->nModifications);
+ break;
+ }
+
+ /* Read character */
+ wch = pVkToVch->wch[dwModNumber];
+ if (wch == WCH_NONE)
+ break;
+
+ *pbDead = (wch == WCH_DEAD);
+ *pbLigature = (wch == WCH_LGTR);
+ *pwcTranslatedChar = wch;
+
+ TRACE("%d %04x: dwModNumber %08x Char %04x\n",
+ i, wVirtKey, dwModNumber, wch);
+
+ if (*pbDead)
+ {
+ /* After WCH_DEAD, real character is located */
+ pVkToVch = (PVK_TO_WCHARS10)(((BYTE *)pVkToVch) + pVkToVchTbl->cbSize);
+ if (pVkToVch->VirtualKey != 0xFF)
+ {
+ WARN("Found dead key with no trailer in the table.\n");
+ WARN("VK: %04x, ADDR: %p\n", wVirtKey, pVkToVch);
+ break;
+ }
+ *pwcTranslatedChar = pVkToVch->wch[dwModNumber];
+ }
+ return TRUE;
}
- return TRUE;
- }
- vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry);
- }
- }
- return FALSE;
+ pVkToVch = (PVK_TO_WCHARS10)(((BYTE *)pVkToVch) + pVkToVchTbl->cbSize);
+ }
+ }
+
+ /* If nothing has been found in layout, check if this is ASCII control character.
+ Note: we could add it to layout table, but windows does not have it there */
+ if (wVirtKey >= 'A' && wVirtKey <= 'Z' &&
+ (pKeyState[VK_CONTROL] & KS_DOWN_BIT) &&
+ !(pKeyState[VK_MENU] & KS_DOWN_BIT))
+ {
+ *pwcTranslatedChar = (wVirtKey - 'A') + 1; /* ASCII control character */
+ *pbDead = FALSE;
+ *pbLigature = FALSE;
+ return TRUE;
+ }
+
+ return FALSE;
}
+/*
+ * IntToUnicodeEx
+ *
+ * Translates virtual key to characters
+ */
static
int APIENTRY
-ToUnicodeInner(UINT wVirtKey,
+IntToUnicodeEx(UINT wVirtKey,
UINT wScanCode,
- PBYTE lpKeyState,
+ PBYTE pKeyState,
LPWSTR pwszBuff,
int cchBuff,
UINT wFlags,
- PKBDTABLES pkKT)
+ PKBDTABLES pKbdTbl)
{
- 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;
- }
-
- if( cchBuff > 0 )
- pwszBuff[0] = wcTranslatedChar;
-
- return bDead ? -1 : 1;
- }
-
- return 0;
-}
+ WCHAR wchTranslatedChar;
+ BOOL bDead, bLigature;
+ static WCHAR wchDead = 0;
+ int iRet = 0;
+
+ ASSERT(pKbdTbl);
+
+ if (!IntTranslateChar(wVirtKey,
+ pKeyState,
+ &bDead,
+ &bLigature,
+ &wchTranslatedChar,
+ pKbdTbl))
+ {
+ return 0;
+ }
+ if (bLigature)
+ {
+ WARN("Not handling ligature (yet)\n" );
+ return 0;
+ }
-DWORD FASTCALL UserGetKeyState(DWORD key)
-{
- DWORD ret = 0;
+ /* If we got dead char in previous call check dead keys in keyboard layout */
+ if (wchDead)
+ {
+ UINT i;
+ WCHAR wchFirst, wchSecond;
+ TRACE("Previous dead char: %lc (%x)\n", wchDead, wchDead);
+
+ for (i = 0; pKbdTbl->pDeadKey[i].dwBoth; i++)
+ {
+ wchFirst = pKbdTbl->pDeadKey[i].dwBoth >> 16;
+ wchSecond = pKbdTbl->pDeadKey[i].dwBoth & 0xFFFF;
+ if (wchFirst == wchDead && wchSecond == wchTranslatedChar)
+ {
+ wchTranslatedChar = pKbdTbl->pDeadKey[i].wchComposed;
+ wchDead = 0;
+ bDead = FALSE;
+ break;
+ }
+ }
- if( key < 0x100 )
- {
- ret = ((DWORD)(gQueueKeyStateTable[key] & KS_DOWN_BIT) << 8 ) |
- (gQueueKeyStateTable[key] & KS_LOCK_BIT);
- }
+ TRACE("Final char: %lc (%x)\n", wchTranslatedChar, wchTranslatedChar);
+ }
- return ret;
-}
+ /* dead char has not been not found */
+ if (wchDead)
+ {
+ /* Treat both characters normally */
+ if (cchBuff > iRet)
+ pwszBuff[iRet++] = wchDead;
+ bDead = FALSE;
+ }
+ /* add character to the buffer */
+ if (cchBuff > iRet)
+ pwszBuff[iRet++] = wchTranslatedChar;
-SHORT
-APIENTRY
-NtUserGetKeyState(
- INT key)
+ /* Save dead character */
+ wchDead = bDead ? wchTranslatedChar : 0;
+
+ return bDead ? -iRet : iRet;
+}
+
+/*
+ * IntVkToVsc
+ *
+ * Translates virtual key to scan code
+ */
+static
+WORD FASTCALL
+IntVkToVsc(WORD wVk, PKBDTABLES pKbdTbl)
{
- DECLARE_RETURN(DWORD);
+ unsigned i;
- DPRINT("Enter NtUserGetKeyState\n");
- UserEnterExclusive();
+ ASSERT(pKbdTbl);
- RETURN(UserGetKeyState(key));
+ /* Check standard keys first */
+ for (i = 0; i < pKbdTbl->bMaxVSCtoVK; i++)
+ {
+ if ((pKbdTbl->pusVSCtoVK[i] & 0xFF) == wVk)
+ return i;
+ }
-CLEANUP:
- DPRINT("Leave NtUserGetKeyState, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
+ /* Check extended keys now */
+ for (i = 0; pKbdTbl->pVSCtoVK_E0[i].Vsc; i++)
+ {
+ if ((pKbdTbl->pVSCtoVK_E0[i].Vk & 0xFF) == wVk)
+ return 0xE000 | pKbdTbl->pVSCtoVK_E0[i].Vsc;
+ }
+
+ for (i = 0; pKbdTbl->pVSCtoVK_E1[i].Vsc; i++)
+ {
+ if ((pKbdTbl->pVSCtoVK_E1[i].Vk & 0xFF) == wVk)
+ return 0xE100 | pKbdTbl->pVSCtoVK_E1[i].Vsc;
+ }
+
+ /* Virtual key has not been found */
+ return 0;
}
+/*
+ * IntVscToVk
+ *
+ * Translates prefixed scancode to virtual key
+ */
+static
+WORD FASTCALL
+IntVscToVk(WORD wScanCode, PKBDTABLES pKbdTbl)
+{
+ unsigned i;
+ WORD wVk = 0;
+ ASSERT(pKbdTbl);
-DWORD FASTCALL UserGetAsyncKeyState(DWORD key)
+ if ((wScanCode & 0xFF00) == 0xE000)
+ {
+ for (i = 0; pKbdTbl->pVSCtoVK_E0[i].Vsc; i++)
+ {
+ if (pKbdTbl->pVSCtoVK_E0[i].Vsc == (wScanCode & 0xFF))
+ {
+ wVk = pKbdTbl->pVSCtoVK_E0[i].Vk;
+ }
+ }
+ }
+ else if ((wScanCode & 0xFF00) == 0xE100)
+ {
+ for (i = 0; pKbdTbl->pVSCtoVK_E1[i].Vsc; i++)
+ {
+ if (pKbdTbl->pVSCtoVK_E1[i].Vsc == (wScanCode & 0xFF))
+ {
+ wVk = pKbdTbl->pVSCtoVK_E1[i].Vk;
+ }
+ }
+ }
+ else if (wScanCode < pKbdTbl->bMaxVSCtoVK)
+ {
+ wVk = pKbdTbl->pusVSCtoVK[wScanCode];
+ }
+
+ /* 0xFF nad 0x00 are invalid VKs */
+ return wVk != 0xFF ? wVk : 0;
+}
+
+/*
+ * IntVkToChar
+ *
+ * Translates virtual key to character, ignoring shift state
+ */
+static
+WCHAR FASTCALL
+IntVkToChar(WORD wVk, PKBDTABLES pKbdTbl)
{
- DWORD ret = 0;
+ WCHAR wch;
+ BOOL bDead, bLigature;
+
+ ASSERT(pKbdTbl);
+
+ if (IntTranslateChar(wVk,
+ NULL,
+ &bDead,
+ &bLigature,
+ &wch,
+ pKbdTbl))
+ {
+ return wch;
+ }
+
+ return 0;
+}
- if( key < 0x100 )
- {
- ret = ((DWORD)(gQueueKeyStateTable[key] & KS_DOWN_BIT) << 8 ) |
- (gQueueKeyStateTable[key] & KS_LOCK_BIT);
- }
+#if 0
+static
+VOID
+DumpKeyState(PBYTE pKeyState)
+{
+ unsigned i;
- return ret;
+ DbgPrint("KeyState { ");
+ for (i = 0; i < 0x100; i++)
+ {
+ if (pKeyState[i])
+ DbgPrint("%02x(%02x) ", i, pKeyState[i]);
+ }
+ DbgPrint("};\n");
}
+#endif
-/***********************************************************************
- * get_key_state
+/*
+ * IntGetAsyncKeyState
+ *
+ * Gets key state from global table
*/
-WORD FASTCALL get_key_state(void)
+static
+WORD FASTCALL
+IntGetAsyncKeyState(DWORD dwKey)
{
- WORD ret = 0;
+ WORD dwRet = 0;
- if (gpsi->aiSysMet[SM_SWAPBUTTON])
+ if (dwKey < 0x100)
{
- if (UserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_LBUTTON;
- if (UserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_RBUTTON;
+ if (gafAsyncKeyState[dwKey] & KS_DOWN_BIT)
+ dwRet |= 0xFFFF8000; // If down, windows returns 0xFFFF8000.
+ if (gafAsyncKeyState[dwKey] & KS_LOCK_BIT)
+ dwRet |= 0x1;
}
else
{
- if (UserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_LBUTTON;
- if (UserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_RBUTTON;
+ EngSetLastError(ERROR_INVALID_PARAMETER);
}
- if (UserGetAsyncKeyState(VK_MBUTTON) & 0x80) ret |= MK_MBUTTON;
- if (UserGetAsyncKeyState(VK_SHIFT) & 0x80) ret |= MK_SHIFT;
- if (UserGetAsyncKeyState(VK_CONTROL) & 0x80) ret |= MK_CONTROL;
- if (UserGetAsyncKeyState(VK_XBUTTON1) & 0x80) ret |= MK_XBUTTON1;
- if (UserGetAsyncKeyState(VK_XBUTTON2) & 0x80) ret |= MK_XBUTTON2;
- return ret;
+ return dwRet;
}
SHORT
APIENTRY
-NtUserGetAsyncKeyState(
- INT key)
+NtUserGetAsyncKeyState(INT Key)
{
- DECLARE_RETURN(SHORT);
+ DECLARE_RETURN(SHORT);
- DPRINT("Enter NtUserGetAsyncKeyState\n");
- UserEnterExclusive();
+ TRACE("Enter NtUserGetAsyncKeyState\n");
+ UserEnterExclusive();
- RETURN((SHORT)UserGetAsyncKeyState(key));
+ RETURN(IntGetAsyncKeyState(Key));
CLEANUP:
- DPRINT("Leave NtUserGetAsyncKeyState, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
+ TRACE("Leave NtUserGetAsyncKeyState, ret=%i\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
}
+/*
+ * IntKeyboardSendWinKeyMsg
+ *
+ * Sends syscommand to shell, when WIN key is pressed
+ */
+static
+VOID NTAPI
+IntKeyboardSendWinKeyMsg()
+{
+ PWND pWnd;
+ MSG Msg;
+ if (!(pWnd = UserGetWindowObject(InputWindowStation->ShellWindow)))
+ {
+ ERR("Couldn't find window to send Windows key message!\n");
+ return;
+ }
-BOOL FASTCALL
-IntTranslateKbdMessage(LPMSG lpMsg,
- UINT flags)
+ Msg.hwnd = InputWindowStation->ShellWindow;
+ Msg.message = WM_SYSCOMMAND;
+ Msg.wParam = SC_TASKLIST;
+ Msg.lParam = 0;
+
+ /* The QS_HOTKEY is just a guess */
+ MsqPostMessage(pWnd->head.pti->MessageQueue, &Msg, FALSE, QS_HOTKEY);
+}
+
+/*
+ * co_IntKeyboardSendAltKeyMsg
+ *
+ * Sends syscommand enabling window menu
+ */
+static
+VOID NTAPI
+co_IntKeyboardSendAltKeyMsg()
+{
+ FIXME("co_IntKeyboardSendAltKeyMsg\n");
+ //co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0); // This sends everything into a msg loop!
+}
+
+/*
+ * UserSendKeyboardInput
+ *
+ * Process keyboard input from input devices and SendInput API
+ */
+BOOL NTAPI
+UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
{
- PTHREADINFO pti;
- static INT dead_char = 0;
- LONG UState = 0;
- WCHAR wp[2] = { 0 };
- MSG NewMsg = { 0 };
- PKBDTABLES keyLayout;
- BOOL Result = FALSE;
-
- pti = PsGetCurrentThreadWin32Thread();
- keyLayout = pti->KeyboardLayout->KBTables;
- if( !keyLayout )
- return FALSE;
-
- if (lpMsg->message < WM_KEYFIRST || lpMsg->message > WM_KEYLAST)
- return FALSE;
- if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN)
- return FALSE;
-
- /* All messages have to contain the cursor point. */
- NewMsg.pt = gpsi->ptCursor;
-
- switch (lpMsg->wParam)
+ WORD wScanCode, wVk, wSimpleVk, wVkOtherSide, wSysKey;
+ PKBL pKbl = NULL;
+ PKBDTABLES pKbdTbl;
+ PUSER_MESSAGE_QUEUE pFocusQueue;
+ struct _ETHREAD *pFocusThread;
+ UINT fModifiers;
+ BYTE PrevKeyState = 0;
+ HWND hWnd;
+ int HotkeyId;
+ struct _ETHREAD *Thread;
+ LARGE_INTEGER LargeTickCount;
+ BOOL bExt = pKbdInput->dwFlags & KEYEVENTF_EXTENDEDKEY;
+ BOOL bKeyUp = pKbdInput->dwFlags & KEYEVENTF_KEYUP;
+
+ /* Find the target thread whose locale is in effect */
+ pFocusQueue = IntGetFocusMessageQueue();
+
+ if (pFocusQueue)
{
- case VK_PACKET:
- NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
- NewMsg.hwnd = lpMsg->hwnd;
- NewMsg.wParam = HIWORD(lpMsg->lParam);
- NewMsg.lParam = LOWORD(lpMsg->lParam);
- MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
- return TRUE;
+ pFocusThread = pFocusQueue->Thread;
+ if (pFocusThread && pFocusThread->Tcb.Win32Thread)
+ pKbl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout;
+ }
+
+ if (!pKbl)
+ pKbl = W32kGetDefaultKeyLayout();
+ if (!pKbl)
+ {
+ ERR("No keyboard layout!\n");
+ return FALSE;
}
- UState = ToUnicodeInner(lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff,
- gQueueKeyStateTable, wp, 2, 0,
- keyLayout );
-
- if (UState == 1)
- {
- NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
- if (dead_char)
- {
- ULONG i;
- WCHAR first, second;
- DPRINT("PREVIOUS DEAD CHAR: %c\n", dead_char);
-
- for( i = 0; keyLayout->pDeadKey[i].dwBoth; i++ )
- {
- first = keyLayout->pDeadKey[i].dwBoth >> 16;
- second = keyLayout->pDeadKey[i].dwBoth;
- if (first == dead_char && second == wp[0])
+ pKbdTbl = pKbl->KBTables;
+
+ /* Note: wScan field is always used */
+ wScanCode = pKbdInput->wScan & 0x7F;
+
+ if (pKbdInput->dwFlags & KEYEVENTF_UNICODE)
+ {
+ /* Generate WM_KEYDOWN msg with wParam == VK_PACKET and
+ high order word of lParam == pKbdInput->wScan */
+ wVk = VK_PACKET;
+ }
+ else
+ {
+ if (bExt)
+ wScanCode |= 0xE000;
+
+ if (pKbdInput->dwFlags & KEYEVENTF_SCANCODE)
+ {
+ /* Don't ignore invalid scan codes */
+ wVk = IntVscToVk(wScanCode, pKbdTbl);
+ if (!wVk) /* use 0xFF if vsc is invalid */
+ wVk = 0xFF;
+ }
+ else
+ {
+ wVk = pKbdInput->wVk & 0xFF;
+
+ /* LSHIFT + EXT = RSHIFT */
+ wVk = IntSimplifyVk(wVk);
+ wVk = IntFixVk(wVk, bExt);
+ }
+ }
+
+ if (!(pKbdInput->dwFlags & KEYEVENTF_UNICODE))
+ {
+ /* Get virtual key without shifts (VK_(L|R)* -> VK_*) */
+ wSimpleVk = IntSimplifyVk(wVk);
+ wVkOtherSide = IntGetVkOtherSide(wVk);
+ PrevKeyState = gafAsyncKeyState[wSimpleVk];
+
+ /* Update global keyboard state. Begin from lock bit */
+ if (!bKeyUp && !(PrevKeyState & KS_DOWN_BIT))
+ gafAsyncKeyState[wVk] ^= KS_LOCK_BIT;
+
+ /* Update down bit */
+ if (bKeyUp)
+ gafAsyncKeyState[wVk] &= ~KS_DOWN_BIT;
+ else
+ gafAsyncKeyState[wVk] |= KS_DOWN_BIT;
+
+ /* Update key without shifts */
+ gafAsyncKeyState[wSimpleVk] = gafAsyncKeyState[wVk] | gafAsyncKeyState[wVkOtherSide];
+
+ if (!bKeyUp)
+ {
+ /* Update keyboard LEDs */
+ if (!gpKeyboardIndicatorTrans)
+ IntKeyboardGetIndicatorTrans(ghKeyboardDevice, &gpKeyboardIndicatorTrans);
+ if (gpKeyboardIndicatorTrans)
+ IntKeyboardUpdateLeds(ghKeyboardDevice,
+ wScanCode,
+ gafAsyncKeyState[wSimpleVk] & KS_LOCK_BIT,
+ gpKeyboardIndicatorTrans);
+ }
+
+ /* Truncate scan code */
+ wScanCode &= 0x7F;
+
+ /* Support VK_*WIN and VK_*MENU keys */
+ if (bKeyUp)
+ {
+ if (wVk == VK_LWIN || wVk == VK_RWIN)
+ IntKeyboardSendWinKeyMsg();
+ else if(wSimpleVk == VK_MENU && !(gafAsyncKeyState[VK_CONTROL] & KS_DOWN_BIT))
+ co_IntKeyboardSendAltKeyMsg();
+ }
+
+ /* Check if it is a hotkey */
+ fModifiers = IntGetModifiers(gafAsyncKeyState);
+ if (GetHotKey(fModifiers, wSimpleVk, &Thread, &hWnd, &HotkeyId))
+ {
+ if (!bKeyUp)
{
- wp[0] = keyLayout->pDeadKey[i].wchComposed;
- dead_char = 0;
- break;
+ TRACE("Hot key pressed (hWnd %lx, id %d)\n", hWnd, HotkeyId);
+ MsqPostHotKeyMessage(Thread,
+ hWnd,
+ (WPARAM)HotkeyId,
+ MAKELPARAM((WORD)fModifiers, wSimpleVk));
}
- }
-
- DPRINT("FINAL CHAR: %c\n", wp[0]);
- }
-
- if (dead_char)
- {
- NewMsg.hwnd = lpMsg->hwnd;
- NewMsg.wParam = dead_char;
- NewMsg.lParam = lpMsg->lParam;
- dead_char = 0;
- MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
- }
-
- NewMsg.hwnd = lpMsg->hwnd;
- NewMsg.wParam = wp[0];
- NewMsg.lParam = lpMsg->lParam;
- DPRINT( "CHAR='%c' %04x %08x\n", wp[0], wp[0], lpMsg->lParam );
- MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
- Result = TRUE;
- }
- else if (UState == -1)
- {
- NewMsg.message =
- (lpMsg->message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
- NewMsg.hwnd = lpMsg->hwnd;
- NewMsg.wParam = wp[0];
- NewMsg.lParam = lpMsg->lParam;
- dead_char = wp[0];
- MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
- Result = TRUE;
- }
-
- return Result;
+
+ return TRUE; /* Don't send any message */
+ }
+ }
+
+ /* If we have a focus queue, post a keyboard message */
+ if (pFocusQueue)
+ {
+ MSG Msg;
+
+ /* If it is F10 or ALT is down and CTRL is up, it's a system key */
+ wSysKey = (pKbdTbl->fLocaleFlags & KLLF_ALTGR) ? VK_LMENU : VK_MENU;
+ if (wVk == VK_F10 ||
+ //uVkNoShift == VK_MENU || // FIXME: If only LALT is pressed WM_SYSKEYUP is generated instead of WM_KEYUP
+ ((gafAsyncKeyState[wSysKey] & KS_DOWN_BIT) && // FIXME
+ !(gafAsyncKeyState[VK_CONTROL] & KS_DOWN_BIT)))
+ {
+ if (bKeyUp)
+ Msg.message = WM_SYSKEYUP;
+ else
+ Msg.message = WM_SYSKEYDOWN;
+ }
+ else
+ {
+ if (bKeyUp)
+ Msg.message = WM_KEYUP;
+ else
+ Msg.message = WM_KEYDOWN;
+ }
+ Msg.hwnd = pFocusQueue->FocusWindow;
+ Msg.lParam = MAKELPARAM(1, wScanCode);
+ /* If it is VK_PACKET, high word of wParam is used for wchar */
+ if (!(pKbdInput->dwFlags & KEYEVENTF_UNICODE))
+ {
+ if (bExt)
+ Msg.lParam |= LP_EXT_BIT;
+ if (gafAsyncKeyState[VK_MENU] & KS_DOWN_BIT)
+ Msg.lParam |= LP_CONTEXT_BIT;
+ if (PrevKeyState & KS_DOWN_BIT)
+ Msg.lParam |= LP_PREV_STATE_BIT;
+ if (bKeyUp)
+ Msg.lParam |= LP_TRANSITION_BIT;
+ }
+
+ Msg.wParam = wVk; // its "simplified" later
+ Msg.pt = gpsi->ptCursor;
+ if (pKbdInput->time)
+ Msg.time = pKbdInput->time;
+ else
+ {
+ KeQueryTickCount(&LargeTickCount);
+ Msg.time = MsqCalculateMessageTime(&LargeTickCount);
+ }
+
+ /* Post a keyboard message */
+ TRACE("Posting keyboard msg %u wParam 0x%x lParam 0x%x\n", Msg.message, Msg.wParam, Msg.lParam);
+ co_MsqPostKeyboardMessage(Msg.message, Msg.wParam, Msg.lParam, bInjected);
+ }
+
+ return TRUE;
}
-DWORD
-APIENTRY
-NtUserGetKeyboardState(
- LPBYTE lpKeyState)
+/*
+ * UserProcessKeyboardInput
+ *
+ * Process raw keyboard input data
+ */
+VOID NTAPI
+UserProcessKeyboardInput(
+ PKEYBOARD_INPUT_DATA pKbdInputData)
{
- BOOL Result = TRUE;
- DECLARE_RETURN(DWORD);
+ WORD wScanCode, wVk;
+ PKBL pKbl = NULL;
+ PKBDTABLES pKbdTbl;
+ PUSER_MESSAGE_QUEUE pFocusQueue;
+ struct _ETHREAD *pFocusThread;
+
+ /* Calculate scan code with prefix */
+ wScanCode = pKbdInputData->MakeCode & 0x7F;
+ if (pKbdInputData->Flags & KEY_E0)
+ wScanCode |= 0xE000;
+ if (pKbdInputData->Flags & KEY_E1)
+ wScanCode |= 0xE100;
+
+ /* Find the target thread whose locale is in effect */
+ pFocusQueue = IntGetFocusMessageQueue();
+
+ if (pFocusQueue)
+ {
+ pFocusThread = pFocusQueue->Thread;
+ if (pFocusThread && pFocusThread->Tcb.Win32Thread)
+ pKbl = ((PTHREADINFO)pFocusThread->Tcb.Win32Thread)->KeyboardLayout;
+ }
- DPRINT("Enter NtUserGetKeyboardState\n");
- UserEnterShared();
+ if (!pKbl)
+ pKbl = W32kGetDefaultKeyLayout();
+ if (!pKbl)
+ return;
- if (lpKeyState)
- {
- if(!NT_SUCCESS(MmCopyToCaller(lpKeyState, gQueueKeyStateTable, 256)))
- Result = FALSE;
- }
+ pKbdTbl = pKbl->KBTables;
- RETURN(Result);
+ /* Convert scan code to virtual key.
+ Note: we could call UserSendKeyboardInput using scan code,
+ but it wouldn't interpret E1 key(s) properly */
+ wVk = IntVscToVk(wScanCode, pKbdTbl);
+ TRACE("UserProcessKeyboardInput: %x (break: %u) -> %x\n",
+ wScanCode, (pKbdInputData->Flags & KEY_BREAK) ? 1 : 0, wVk);
-CLEANUP:
- DPRINT("Leave NtUserGetKeyboardState, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
+ if (wVk)
+ {
+ KEYBDINPUT KbdInput;
+
+ /* Support numlock */
+ if ((wVk & KBDNUMPAD) && (gafAsyncKeyState[VK_NUMLOCK] & KS_LOCK_BIT))
+ {
+ wVk = IntTranslateNumpadKey(wVk & 0xFF);
+ }
+
+ /* Send keyboard input */
+ KbdInput.wVk = wVk & 0xFF;
+ KbdInput.wScan = wScanCode & 0x7F;
+ KbdInput.dwFlags = 0;
+ if (pKbdInputData->Flags & KEY_BREAK)
+ KbdInput.dwFlags |= KEYEVENTF_KEYUP;
+ if (wVk & KBDEXT)
+ KbdInput.dwFlags |= KEYEVENTF_EXTENDEDKEY;
+ KbdInput.time = 0;
+ KbdInput.dwExtraInfo = pKbdInputData->ExtraInformation;
+ UserSendKeyboardInput(&KbdInput, FALSE);
+
+ /* E1 keys don't have break code */
+ if (pKbdInputData->Flags & KEY_E1)
+ {
+ /* Send key up event */
+ KbdInput.dwFlags |= KEYEVENTF_KEYUP;
+ UserSendKeyboardInput(&KbdInput, FALSE);
+ }
+ }
}
-BOOL
-APIENTRY
-NtUserSetKeyboardState(LPBYTE lpKeyState)
+/*
+ * IntTranslateKbdMessage
+ *
+ * Addes WM_(SYS)CHAR messages to message queue if message
+ * describes key which produce character.
+ */
+BOOL FASTCALL
+IntTranslateKbdMessage(LPMSG lpMsg,
+ UINT flags)
{
- BOOL Result = TRUE;
- DECLARE_RETURN(DWORD);
+ PTHREADINFO pti;
+ INT cch = 0, i;
+ WCHAR wch[3] = { 0 };
+ MSG NewMsg = { 0 };
+ PKBDTABLES pKbdTbl;
+ PWND pWnd;
+ LARGE_INTEGER LargeTickCount;
+ BOOL bResult = FALSE;
+
+ pWnd = UserGetWindowObject(lpMsg->hwnd);
+ if (!pWnd) // Must have a window!
+ {
+ ERR("No Window for Translate.\n");
+ return FALSE;
+ }
- DPRINT("Enter NtUserSetKeyboardState\n");
- UserEnterExclusive();
+ pti = pWnd->head.pti;
+ pKbdTbl = pti->KeyboardLayout->KBTables;
+ if (!pKbdTbl)
+ return FALSE;
- if (lpKeyState)
- {
- if(! NT_SUCCESS(MmCopyFromCaller(gQueueKeyStateTable, lpKeyState, 256)))
- Result = FALSE;
- }
+ if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN)
+ return FALSE;
- RETURN(Result);
+ /* Init pt, hwnd and time msg fields */
+ NewMsg.pt = gpsi->ptCursor;
+ NewMsg.hwnd = lpMsg->hwnd;
+ KeQueryTickCount(&LargeTickCount);
+ NewMsg.time = MsqCalculateMessageTime(&LargeTickCount);
-CLEANUP:
- DPRINT("Leave NtUserSetKeyboardState, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
-}
+ TRACE("Enter IntTranslateKbdMessage msg %s, vk %x\n",
+ lpMsg->message == WM_SYSKEYDOWN ? "WM_SYSKEYDOWN" : "WM_KEYDOWN", lpMsg->wParam);
-static UINT VkToScan( UINT Code, BOOL ExtCode, PKBDTABLES pkKT )
-{
- int i;
+ if (lpMsg->wParam == VK_PACKET)
+ {
+ NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
+ NewMsg.wParam = HIWORD(lpMsg->lParam);
+ NewMsg.lParam = LOWORD(lpMsg->lParam);
+ MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
+ return TRUE;
+ }
- for( i = 0; i < pkKT->bMaxVSCtoVK; i++ )
- {
- if( pkKT->pusVSCtoVK[i] == Code )
- {
- return i;
- }
- }
+ cch = IntToUnicodeEx(lpMsg->wParam,
+ HIWORD(lpMsg->lParam) & 0xFF,
+ pti->MessageQueue->KeyState,
+ wch,
+ sizeof(wch) / sizeof(wch[0]),
+ 0,
+ pKbdTbl);
- return 0;
-}
+ if (cch)
+ {
+ if (cch > 0) /* Normal characters */
+ NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
+ else /* Dead character */
+ {
+ cch = -cch;
+ NewMsg.message =
+ (lpMsg->message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
+ }
+ NewMsg.lParam = lpMsg->lParam;
+
+ /* Send all characters */
+ for (i = 0; i < cch; ++i)
+ {
+ TRACE("Msg: %x '%lc' (%04x) %08x\n", NewMsg.message, wch[i], wch[i], NewMsg.lParam);
+ if (pWnd->Unicode)
+ NewMsg.wParam = wch[i];
+ else
+ {
+ CHAR ch;
+ if (!NT_SUCCESS(RtlUnicodeToMultiByteN(&ch, sizeof(ch), NULL, &wch[i], sizeof(wch[i]))))
+ WARN("RtlUnicodeToMultiByteN failed!\n");
+ NewMsg.wParam = ch;
+ }
+ MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
+ }
+ bResult = TRUE;
+ }
-UINT ScanToVk( UINT Code, BOOL ExtKey, PKBDTABLES pkKT )
-{
- if( !pkKT )
- {
- DPRINT("ScanToVk: No layout\n");
- return 0;
- }
-
- 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;
- }
+ TRACE("Leave IntTranslateKbdMessage ret %u, cch %d, msg %x, wch %x\n",
+ bResult, cch, NewMsg.message, NewMsg.wParam);
+ return bResult;
}
/*
* 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)
+ * KeyLayout: Keyboard layout handle
*
* @implemented
*/
-
-static UINT IntMapVirtualKeyEx( UINT Code, UINT Type, PKBDTABLES keyLayout )
+static UINT
+IntMapVirtualKeyEx(UINT uCode, UINT Type, PKBDTABLES pKbdTbl)
{
- UINT ret = 0;
-
- switch( Type )
- {
- case 0:
- if( Code == VK_SHIFT )
- Code = VK_LSHIFT;
- if( Code == VK_MENU )
- Code = VK_LMENU;
- if( Code == VK_CONTROL )
- Code = VK_LCONTROL;
- ret = VkToScan( Code, FALSE, keyLayout );
- break;
-
- case 1:
- ret =
- DontDistinguishShifts
- (IntMapVirtualKeyEx( Code, 3, keyLayout ) );
- break;
-
- case 2:
- {
- WCHAR wp[2] = {0};
-
- ret = VkToScan( Code, FALSE, keyLayout );
- ToUnicodeInner( Code, ret, 0, wp, 2, 0, keyLayout );
- ret = wp[0];
- }
- break;
-
- case 3:
-
- ret = ScanToVk( Code, FALSE, keyLayout );
- break;
- }
-
- return ret;
+ UINT uRet = 0;
+
+ switch (Type)
+ {
+ case MAPVK_VK_TO_VSC:
+ uCode = IntFixVk(uCode, FALSE);
+ uRet = IntVkToVsc(uCode, pKbdTbl);
+ if (uRet > 0xFF) // fail for scancodes with prefix (e0, e1)
+ uRet = 0;
+ break;
+
+ case MAPVK_VSC_TO_VK:
+ uRet = IntVscToVk(uCode, pKbdTbl) & 0xFF;
+ uRet = IntSimplifyVk(uRet);
+ break;
+
+ case MAPVK_VK_TO_CHAR:
+ uRet = (UINT)IntVkToChar(uCode, pKbdTbl);
+ break;
+
+ case MAPVK_VSC_TO_VK_EX:
+ uRet = IntVscToVk(uCode, pKbdTbl) & 0xFF;
+ break;
+
+ case MAPVK_VK_TO_VSC_EX:
+ uRet = IntVkToVsc(uCode, pKbdTbl);
+ break;
+
+ default:
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ ERR("Wrong type value: %u\n", Type);
+ }
+
+ return uRet;
}
+/*
+ * NtUserMapVirtualKeyEx
+ *
+ * Map a virtual key code, or virtual scan code, to a scan code, key code,
+ * or unshifted unicode character. See IntMapVirtualKeyEx.
+ */
UINT
APIENTRY
-NtUserMapVirtualKeyEx( UINT Code, UINT Type, DWORD keyboardId, HKL dwhkl )
+NtUserMapVirtualKeyEx(UINT uCode, UINT uType, DWORD keyboardId, HKL dwhkl)
{
- PTHREADINFO pti;
- PKBDTABLES keyLayout;
- DECLARE_RETURN(UINT);
+ PKBDTABLES pKbdTbl = NULL;
+ DECLARE_RETURN(UINT);
- DPRINT("Enter NtUserMapVirtualKeyEx\n");
- UserEnterExclusive();
+ TRACE("Enter NtUserMapVirtualKeyEx\n");
+ UserEnterExclusive();
- pti = PsGetCurrentThreadWin32Thread();
- keyLayout = pti ? pti->KeyboardLayout->KBTables : 0;
+ if (!dwhkl)
+ {
+ PTHREADINFO pti;
- if( !keyLayout )
- RETURN(0);
+ pti = PsGetCurrentThreadWin32Thread();
+ if (pti && pti->KeyboardLayout)
+ pKbdTbl = pti->KeyboardLayout->KBTables;
+ }
+ else
+ {
+ PKBL pKbl;
+
+ pKbl = UserHklToKbl(dwhkl);
+ if (pKbl)
+ pKbdTbl = pKbl->KBTables;
+ }
- RETURN(IntMapVirtualKeyEx( Code, Type, keyLayout ));
+ if (!pKbdTbl)
+ RETURN(0);
+
+ RETURN(IntMapVirtualKeyEx(uCode, uType, pKbdTbl));
CLEANUP:
- DPRINT("Leave NtUserMapVirtualKeyEx, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
+ TRACE("Leave NtUserMapVirtualKeyEx, ret=%i\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
}
-
+/*
+ * NtUserToUnicodeEx
+ *
+ * Translates virtual key to characters
+ */
int
APIENTRY
NtUserToUnicodeEx(
- UINT wVirtKey,
- UINT wScanCode,
- PBYTE lpKeyState,
- LPWSTR pwszBuff,
- int cchBuff,
- UINT wFlags,
- HKL dwhkl )
+ UINT wVirtKey,
+ UINT wScanCode,
+ PBYTE pKeyStateUnsafe,
+ LPWSTR pwszBuffUnsafe,
+ int cchBuff,
+ UINT wFlags,
+ HKL dwhkl)
{
- PTHREADINFO pti;
- BYTE KeyStateBuf[0x100];
- PWCHAR OutPwszBuff = 0;
- int ret = 0;
- DECLARE_RETURN(int);
-
- DPRINT("Enter NtUserSetKeyboardState\n");
- UserEnterShared();//fixme: this syscall doesnt seem to need any locking...
-
- /* Key up? */
- if (wScanCode & SC_KEY_UP)
- {
- RETURN(0);
- }
-
- if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf,
- lpKeyState,
- sizeof(KeyStateBuf))) )
- {
- DPRINT1( "Couldn't copy key state from caller.\n" );
- RETURN(0);
- }
-
- /* Virtual code is correct? */
- if (wVirtKey < 0x100)
- {
- OutPwszBuff = ExAllocatePoolWithTag(NonPagedPool,sizeof(WCHAR) * cchBuff, TAG_STRING);
- if( !OutPwszBuff )
- {
- DPRINT1( "ExAllocatePoolWithTag(%d) failed\n", sizeof(WCHAR) * cchBuff);
- RETURN(0);
- }
- RtlZeroMemory( OutPwszBuff, sizeof( WCHAR ) * cchBuff );
-
- pti = PsGetCurrentThreadWin32Thread();
- ret = ToUnicodeInner( wVirtKey,
- wScanCode,
- KeyStateBuf,
- OutPwszBuff,
- cchBuff,
- wFlags,
- pti ? pti->KeyboardLayout->KBTables : 0 );
-
- MmCopyToCaller(pwszBuff,OutPwszBuff,sizeof(WCHAR)*cchBuff);
- ExFreePoolWithTag(OutPwszBuff, TAG_STRING);
- }
-
- RETURN(ret);
+ PTHREADINFO pti;
+ BYTE KeyState[0x100];
+ PWCHAR pwszBuff = NULL;
+ int iRet = 0;
+ PKBL pKbl = NULL;
+ DECLARE_RETURN(int);
+
+ TRACE("Enter NtUserSetKeyboardState\n");
+ UserEnterShared();
+
+ /* Key up? */
+ if (wScanCode & SC_KEY_UP)
+ {
+ RETURN(0);
+ }
-CLEANUP:
- DPRINT("Leave NtUserSetKeyboardState, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
-}
+ if (!NT_SUCCESS(MmCopyFromCaller(KeyState,
+ pKeyStateUnsafe,
+ sizeof(KeyState))))
+ {
+ ERR("Couldn't copy key state from caller.\n");
+ RETURN(0);
+ }
-static int W32kSimpleToupper( int ch )
-{
- if( ch >= 'a' && ch <= 'z' )
- ch = ch - 'a' + 'A';
- return ch;
+ /* Virtual code is correct? */
+ if (wVirtKey < 0x100)
+ {
+ pwszBuff = ExAllocatePoolWithTag(NonPagedPool, sizeof(WCHAR) * cchBuff, TAG_STRING);
+ if (!pwszBuff)
+ {
+ ERR("ExAllocatePoolWithTag(%d) failed\n", sizeof(WCHAR) * cchBuff);
+ RETURN(0);
+ }
+ RtlZeroMemory(pwszBuff, sizeof(WCHAR) * cchBuff);
+
+ if (dwhkl)
+ pKbl = UserHklToKbl(dwhkl);
+
+ if (!pKbl)
+ {
+ pti = PsGetCurrentThreadWin32Thread();
+ pKbl = pti->KeyboardLayout;
+ }
+
+ iRet = IntToUnicodeEx(wVirtKey,
+ wScanCode,
+ KeyState,
+ pwszBuff,
+ cchBuff,
+ wFlags,
+ pKbl ? pKbl->KBTables : NULL);
+
+ MmCopyToCaller(pwszBuffUnsafe, pwszBuff, cchBuff * sizeof(WCHAR));
+ ExFreePoolWithTag(pwszBuff, TAG_STRING);
+ }
+
+ RETURN(iRet);
+
+CLEANUP:
+ TRACE("Leave NtUserSetKeyboardState, ret=%i\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
}
+/*
+ * NtUserGetKeyNameText
+ *
+ * Gets key name from keyboard layout
+ */
DWORD
APIENTRY
-NtUserGetKeyNameText( LONG lParam, LPWSTR lpString, int nSize )
+NtUserGetKeyNameText(LONG lParam, LPWSTR lpString, int cchSize)
{
- PTHREADINFO pti;
- 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;
- VSC_LPWSTR *KeyNames;
- DECLARE_RETURN(DWORD);
-
- DPRINT("Enter NtUserGetKeyNameText\n");
- UserEnterShared();
-
- pti = PsGetCurrentThreadWin32Thread();
- keyLayout = pti ? pti->KeyboardLayout->KBTables : 0;
-
- if( !keyLayout || nSize < 1 )
- RETURN(0);
-
- if( lParam & (1<<25) )
- {
- CareVk = VkCode = ScanToVk( ScanCode, ExtKey, keyLayout );
- switch (VkCode)
- {
- case VK_RSHIFT:
- ScanCode |= 0x100;
- case VK_LSHIFT:
- VkCode = VK_SHIFT;
- break;
- case VK_LCONTROL:
- case VK_RCONTROL:
- VkCode = VK_CONTROL;
- break;
- case VK_LMENU:
- case VK_RMENU:
- VkCode = VK_MENU;
- break;
- }
- }
- else
- {
- VkCode = ScanToVk( ScanCode, ExtKey, keyLayout );
- }
-
- 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;
- }
- }
- }
+ PTHREADINFO pti;
+ DWORD i, cchKeyName, dwRet = 0;
+ WORD wScanCode = (lParam >> 16) & 0xFF;
+ BOOL bExtKey = (lParam & LP_EXT_BIT) ? TRUE : FALSE;
+ PKBDTABLES pKbdTbl;
+ VSC_LPWSTR *pKeyNames = NULL;
+ CONST WCHAR *pKeyName = NULL;
+ WCHAR KeyNameBuf[2];
+ DECLARE_RETURN(DWORD);
+
+ TRACE("Enter NtUserGetKeyNameText\n");
+ UserEnterShared();
+
+ /* Get current keyboard layout */
+ pti = PsGetCurrentThreadWin32Thread();
+ pKbdTbl = pti ? pti->KeyboardLayout->KBTables : 0;
+
+ if (!pKbdTbl || cchSize < 1)
+ RETURN(0);
+
+ /* "Do not care" flag */
+ if(lParam & LP_DO_NOT_CARE_BIT)
+ {
+ /* Note: we could do vsc -> vk -> vsc conversion, instead of using
+ hardcoded scan codes, but it's not what Windows does */
+ if (wScanCode == SCANCODE_RSHIFT && !bExtKey)
+ wScanCode = SCANCODE_LSHIFT;
+ else if (wScanCode == SCANCODE_CTRL || wScanCode == SCANCODE_ALT)
+ bExtKey = FALSE;
+ }
- if( ret == 0 )
- {
- WCHAR UCName[2];
+ if (bExtKey)
+ pKeyNames = pKbdTbl->pKeyNamesExt;
+ else
+ pKeyNames = pKbdTbl->pKeyNames;
- UCName[0] = W32kSimpleToupper(IntMapVirtualKeyEx( VkCode, 2, keyLayout ));
- UCName[1] = 0;
- ret = 1;
+ for (i = 0; pKeyNames[i].pwsz; i++)
+ {
+ if (pKeyNames[i].vsc == wScanCode)
+ {
+ pKeyName = pKeyNames[i].pwsz;
+ break;
+ }
+ }
+
+ if (!pKeyName)
+ {
+ WORD wVk = IntVscToVk(wScanCode, pKbdTbl);
+
+ if (wVk)
+ {
+ KeyNameBuf[0] = IntVkToChar(wVk, pKbdTbl);
+ KeyNameBuf[1] = 0;
+ if (KeyNameBuf[0])
+ pKeyName = KeyNameBuf;
+ }
+ }
- if( !NT_SUCCESS(MmCopyToCaller( lpString, UCName, 2 * sizeof(WCHAR) )) )
- RETURN(0);
- }
+ if (pKeyName)
+ {
+ cchKeyName = wcslen(pKeyName);
+ if (cchKeyName > cchSize - 1)
+ cchKeyName = cchSize - 1; // don't count '\0'
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(lpString, (cchKeyName + 1) * sizeof(WCHAR), 1);
+ RtlCopyMemory(lpString, pKeyName, cchKeyName * sizeof(WCHAR));
+ lpString[cchKeyName] = UNICODE_NULL;
+ dwRet = cchKeyName;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ }
- RETURN(ret);
+ RETURN(dwRet);
CLEANUP:
- DPRINT("Leave NtUserGetKeyNameText, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
+ TRACE("Leave NtUserGetKeyNameText, ret=%i\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
}
/*
- * Filter this message according to the current key layout, setting wParam
- * appropriately.
+ * UserGetKeyboardType
+ *
+ * Returns some keyboard specific information
*/
-
-VOID FASTCALL
-W32kKeyProcessMessage(LPMSG Msg,
- PKBDTABLES KeyboardLayout,
- BYTE Prefix)
-{
- DWORD ScanCode = 0, ModifierBits = 0;
- DWORD i = 0;
- DWORD BaseMapping = 0;
- 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 } };
- PVSC_VK VscVkTable = NULL;
-
- if( !KeyboardLayout || !Msg ||
- (Msg->message != WM_KEYDOWN && Msg->message != WM_SYSKEYDOWN &&
- Msg->message != WM_KEYUP && Msg->message != WM_SYSKEYUP) )
- {
- return;
- }
-
- /* 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,gQueueKeyStateTable);
-
- /* Get the raw scan code, so we can look up whether the key is a numpad
- * key
- *
- * Shift and the LP_EXT_BIT cancel. */
- ScanCode = (Msg->lParam >> 16) & 0xff;
- BaseMapping = Msg->wParam =
- IntMapVirtualKeyEx( ScanCode, 1, KeyboardLayout );
- if( Prefix == 0 )
- {
- if( ScanCode >= KeyboardLayout->bMaxVSCtoVK )
- RawVk = 0xff;
- else
- RawVk = KeyboardLayout->pusVSCtoVK[ScanCode];
- }
- else
- {
- if( Prefix == 0xE0 )
- {
- /* ignore shift codes */
- if( ScanCode == 0x2A || ScanCode == 0x36 )
- {
- return;
- }
- VscVkTable = KeyboardLayout->pVSCtoVK_E0;
- }
- else if( Prefix == 0xE1 )
- {
- VscVkTable = KeyboardLayout->pVSCtoVK_E1;
- }
-
- if (!VscVkTable)
- {
- DPRINT1("somethings wrong, Prefix=0x%x", Prefix);
- return;
- }
-
- RawVk = 0xff;
- while (VscVkTable->Vsc)
- {
- if( VscVkTable->Vsc == ScanCode )
- {
- RawVk = VscVkTable->Vk;
- }
- VscVkTable++;
- }
- }
-
- if ((ModifierBits & NUMLOCK_BIT) &&
- !(ModifierBits & GetShiftBit(KeyboardLayout, VK_SHIFT)) &&
- (RawVk & KNUMP) &&
- !(Msg->lParam & LP_EXT_BIT))
- {
- /* The key in question is a numpad key. Search for a translation. */
- for (i = 0; NumpadConversion[i][0]; i++)
- {
- if ((BaseMapping & 0xff) == NumpadConversion[i][0]) /* RawVk? */
- {
- Msg->wParam = NumpadConversion[i][1];
- break;
- }
- }
- }
-
- DPRINT("Key: [%04x -> %04x]\n", BaseMapping, Msg->wParam);
-
- /* 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 */
- }
-
- /* We need to unset SYSKEYDOWN if the ALT key is an ALT+Gr */
- if( gQueueKeyStateTable[VK_RMENU] & KS_DOWN_BIT )
- {
- if( Msg->message == WM_SYSKEYDOWN )
- Msg->message = WM_KEYDOWN;
- else
- Msg->message = WM_KEYUP;
- }
-
-}
-
-
-
DWORD FASTCALL
UserGetKeyboardType(
- DWORD TypeFlag)
+ DWORD dwTypeFlag)
{
- switch(TypeFlag)
- {
- case 0: /* Keyboard type */
- return 4; /* AT-101 */
- case 1: /* Keyboard Subtype */
- return 0; /* There are no defined subtypes */
- case 2: /* Number of F-keys */
- return 12; /* We're doing an 101 for now, so return 12 F-keys */
- default:
- DPRINT1("Unknown type!\n");
- return 0; /* The book says 0 here, so 0 */
- }
+ switch (dwTypeFlag)
+ {
+ case 0: /* Keyboard type */
+ return 4; /* AT-101 */
+ case 1: /* Keyboard Subtype */
+ return 0; /* There are no defined subtypes */
+ case 2: /* Number of F-keys */
+ return 12; /* We're doing an 101 for now, so return 12 F-keys */
+ default:
+ ERR("Unknown type!\n");
+ return 0; /* Note: we don't have to set last error here */
+ }
}
-
/*
- Based on TryToTranslateChar, instead of processing VirtualKey match,
- look for wChar match.
+ * NtUserVkKeyScanEx
+ *
+ * Based on IntTranslateChar, instead of processing VirtualKey match,
+ * look for wChar match.
*/
DWORD
APIENTRY
NtUserVkKeyScanEx(
- WCHAR wChar,
- HKL hKeyboardLayout,
- BOOL UsehKL ) // TRUE from KeyboardLayout, FALSE from pkbl = (THREADINFO)->KeyboardLayout
+ WCHAR wch,
+ HKL dwhkl,
+ BOOL bUsehKL)
{
- PKBDTABLES KeyLayout;
- PVK_TO_WCHAR_TABLE vtwTbl;
- PVK_TO_WCHARS10 vkPtr;
- size_t size_this_entry;
- int nMod;
- PKBL pkbl = NULL;
- DWORD CapsMod = 0, CapsState = 0, Ret = -1;
-
- DPRINT("NtUserVkKeyScanEx() wChar %d, KbdLayout 0x%p\n", wChar, hKeyboardLayout);
- UserEnterShared();
-
- if (UsehKL)
- {
- if ( !hKeyboardLayout || !(pkbl = UserHklToKbl(hKeyboardLayout)))
- goto Exit;
- }
- else // From VkKeyScanAW it is FALSE so KeyboardLayout is white noise.
- {
- pkbl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout;
- }
-
- KeyLayout = pkbl->KBTables;
-
- 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)
- {
- /*
- 0x01 Shift key
- 0x02 Ctrl key
- 0x04 Alt key
- Should have only 8 valid possibilities. Including zero.
- */
- for(CapsState = 0; CapsState < vtwTbl->nModifications; CapsState++)
- {
- if(vkPtr->wch[CapsState] == wChar)
+ PKBDTABLES pKbdTbl;
+ PVK_TO_WCHAR_TABLE pVkToWchTbl;
+ PVK_TO_WCHARS10 pVkToWch;
+ PKBL pKbl = NULL;
+ DWORD i, dwModBits = 0, dwModNumber = 0, Ret = (DWORD)-1;
+
+ TRACE("NtUserVkKeyScanEx() wch %d, KbdLayout 0x%p\n", wch, dwhkl);
+ UserEnterShared();
+
+ if (bUsehKL)
+ {
+ // Use given keyboard layout
+ if (dwhkl)
+ pKbl = UserHklToKbl(dwhkl);
+ }
+ else
+ {
+ // Use thread keyboard layout
+ pKbl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout;
+ }
+
+ if (!pKbl)
+ goto Exit;
+
+ pKbdTbl = pKbl->KBTables;
+
+ // Interate through all VkToWchar tables while pVkToWchars is not NULL
+ for (i = 0; pKbdTbl->pVkToWcharTable[i].pVkToWchars; i++)
+ {
+ pVkToWchTbl = &pKbdTbl->pVkToWcharTable[i];
+ pVkToWch = (PVK_TO_WCHARS10)(pVkToWchTbl->pVkToWchars);
+
+ // Interate through all virtual keys
+ while (pVkToWch->VirtualKey)
+ {
+ for (dwModNumber = 0; dwModNumber < pVkToWchTbl->nModifications; dwModNumber++)
{
- CapsMod = KeyLayout->pCharModifiers->ModNumber[CapsState];
- DPRINT("nMod %d wC %04x: CapsMod %08x CapsState %08x MaxModBits %08x\n",
- nMod, wChar, CapsMod, CapsState, KeyLayout->pCharModifiers->wMaxModBits);
- Ret = ((CapsMod << 8)|(vkPtr->VirtualKey & 0xff));
- goto Exit;
+ if (pVkToWch->wch[dwModNumber] == wch)
+ {
+ dwModBits = pKbdTbl->pCharModifiers->ModNumber[dwModNumber];
+ TRACE("i %d wC %04x: dwModBits %08x dwModNumber %08x MaxModBits %08x\n",
+ i, wch, dwModBits, dwModNumber, pKbdTbl->pCharModifiers->wMaxModBits);
+ Ret = (dwModBits << 8) | (pVkToWch->VirtualKey & 0xFF);
+ goto Exit;
+ }
}
- }
- vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry);
- }
- }
+ pVkToWch = (PVK_TO_WCHARS10)(((BYTE *)pVkToWch) + pVkToWchTbl->cbSize);
+ }
+ }
Exit:
- UserLeave();
- return Ret;
+ UserLeave();
+ return Ret;
}
+/*
+ * UserGetMouseButtonsState
+ *
+ * Returns bitfield used in mouse messages
+ */
+WORD FASTCALL
+UserGetMouseButtonsState(VOID)
+{
+ WORD ret = 0;
+
+ if (gpsi->aiSysMet[SM_SWAPBUTTON])
+ {
+ if (gafAsyncKeyState[VK_RBUTTON] & KS_DOWN_BIT) ret |= MK_LBUTTON;
+ if (gafAsyncKeyState[VK_LBUTTON] & KS_DOWN_BIT) ret |= MK_RBUTTON;
+ }
+ else
+ {
+ if (gafAsyncKeyState[VK_LBUTTON] & KS_DOWN_BIT) ret |= MK_LBUTTON;
+ if (gafAsyncKeyState[VK_RBUTTON] & KS_DOWN_BIT) ret |= MK_RBUTTON;
+ }
+ if (gafAsyncKeyState[VK_MBUTTON] & KS_DOWN_BIT) ret |= MK_MBUTTON;
+ if (gafAsyncKeyState[VK_SHIFT] & KS_DOWN_BIT) ret |= MK_SHIFT;
+ if (gafAsyncKeyState[VK_CONTROL] & KS_DOWN_BIT) ret |= MK_CONTROL;
+ if (gafAsyncKeyState[VK_XBUTTON1] & KS_DOWN_BIT) ret |= MK_XBUTTON1;
+ if (gafAsyncKeyState[VK_XBUTTON2] & KS_DOWN_BIT) ret |= MK_XBUTTON2;
+ return ret;
+}
/* EOF */