Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

653 lines
20 KiB

/****************************************************************************/
/* hotkey.c */
/* */
/* RDP Shadow hotkey handling functions. */
/* */
/* Copyright(C) Microsoft Corporation 1997-2000 */
/****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define TRC_FILE "hotkey"
#include <precomp.h>
#pragma hdrstop
#define pTRCWd pWd
#include <adcg.h>
#include <nwdwapi.h>
#include <nwdwint.h>
#include "kbd.h" //TODO: Good Grief!
typedef struct {
DWORD dwVersion;
DWORD dwFlags;
DWORD dwMapCount;
DWORD dwMap[0];
} SCANCODEMAP, *PSCANCODEMAP;
/***************************************************************************\
* How some Virtual Key values change when a SHIFT key is held down.
\***************************************************************************/
#define VK_MULTIPLY 0x6A
#define VK_SNAPSHOT 0x2C
const ULONG aulShiftCvt_VK[] = {
MAKELONG(VK_MULTIPLY, VK_SNAPSHOT),
MAKELONG(0,0)
};
/***************************************************************************\
* How some Virtual Key values change when a CONTROL key is held down.
\***************************************************************************/
#define VK_LSHIFT 0xA0
#define VK_RSHIFT 0xA1
#define VK_LCONTROL 0xA2
#define VK_RCONTROL 0xA3
#define VK_LMENU 0xA4
#define VK_RMENU 0xA5
#define VK_NUMLOCK 0x90
#define VK_SCROLL 0x91
#define VK_PAUSE 0x13
#define VK_CANCEL 0x03
//#define KBDEXT (USHORT)0x0100
const ULONG aulControlCvt_VK[] = {
MAKELONG(VK_NUMLOCK, VK_PAUSE | KBDEXT),
MAKELONG(VK_SCROLL, VK_CANCEL),
MAKELONG(0,0)
};
/***************************************************************************\
* How some Virtual Key values change when an ALT key is held down.
* The SHIFT and ALT keys both alter VK values the same way!!
\***************************************************************************/
#define aulAltCvt_VK aulShiftCvt_VK
/***************************************************************************\
* This table list keys that may affect Virtual Key values when held down.
*
* See kbd.h for a full description.
*
* 101/102key keyboard (type 4):
* Virtual Key values vary only if CTRL is held down.
* 84-86 key keyboards (type 3):
* Virtual Key values vary if one of SHIFT, CTRL or ALT is held down.
\***************************************************************************/
#define VK_SHIFT 0x10
#define VK_CONTROL 0x11
#define VK_MENU 0x12
//#define KBDSHIFT 1
//#define KBDCTRL 2
//#define KBDALT 4
const VK_TO_BIT aVkToBits_VK[] = {
{ VK_SHIFT, KBDSHIFT }, // 0x01
{ VK_CONTROL, KBDCTRL }, // 0x02
{ VK_MENU, KBDALT }, // 0x04
{ 0, 0 }
};
/***************************************************************************\
* Tables defining how some Virtual Key values are modified when other keys
* are held down.
* Translates key combinations into indices for gapulCvt_VK_101[] or for
* gapulCvt_VK_84[] or for
*
* See kbd.h for a full description.
*
\***************************************************************************/
//#define SHFT_INVALID 0x0F
const MODIFIERS Modifiers_VK = {
(PVK_TO_BIT)&aVkToBits_VK[0],
4, // Maximum modifier bitmask/index
{
SHFT_INVALID, // no keys held down (no VKs are modified)
0, // SHIFT held down 84-86 key kbd
1, // CTRL held down 101/102 key kbd
SHFT_INVALID, // CTRL-SHIFT held down (no VKs are modified)
2 // ALT held down 84-86 key kbd
}
};
/***************************************************************************\
* A tables of pointers indexed by the number obtained from Modify_VK.
* If a pointer is non-NULL then the table it points to is searched for
* Virtual Key that should have their values changed.
* There are two versions: one for 84-86 key kbds, one for 101/102 key kbds.
* gapulCvt_VK is initialized with the default (101/102 key kbd).
\***************************************************************************/
const ULONG *const gapulCvt_VK_101[] = {
NULL, // No VKs are changed by SHIFT being held down
aulControlCvt_VK, // Some VKs are changed by CTRL being held down
NULL // No VKs are changed by ALT being held down
};
const ULONG *const gapulCvt_VK_84[] = {
aulShiftCvt_VK, // Some VKs are changed by SHIFT being held down
aulControlCvt_VK, // Some VKs are changed by CTRL being held down
aulAltCvt_VK // Some VKs are changed by ALT being held down
};
/*
* Determine the state of all the Modifier Keys (a Modifier Key
* is any key that may modify values produced by other keys: these are
* commonly SHIFT, CTRL and/or ALT)
* Build a bit-mask (wModBits) to encode which modifier keys are depressed.
*/
#define KEY_BYTE(pb, vk) pb[((BYTE)(vk)) >> 2]
#define KEY_DOWN_BIT(vk) (1 << ((((BYTE)(vk)) & 3) << 1))
#define KEY_TOGGLE_BIT(vk) (1 << (((((BYTE)(vk)) & 3) << 1) + 1))
#define TestKeyDownBit(pb, vk) (KEY_BYTE(pb,vk) & KEY_DOWN_BIT(vk))
#define SetKeyDownBit(pb, vk) (KEY_BYTE(pb,vk) |= KEY_DOWN_BIT(vk))
#define ClearKeyDownBit(pb, vk) (KEY_BYTE(pb,vk) &= ~KEY_DOWN_BIT(vk))
#define TestKeyToggleBit(pb, vk) (KEY_BYTE(pb,vk) & KEY_TOGGLE_BIT(vk))
#define SetKeyToggleBit(pb, vk) (KEY_BYTE(pb,vk) |= KEY_TOGGLE_BIT(vk))
#define ClearKeyToggleBit(pb, vk) (KEY_BYTE(pb,vk) &= ~KEY_TOGGLE_BIT(vk))
#define ToggleKeyToggleBit(pb, vk) (KEY_BYTE(pb,vk) ^= KEY_TOGGLE_BIT(vk))
WORD GetModifierBits(
PMODIFIERS pModifiers,
LPBYTE afKeyState)
{
PVK_TO_BIT pVkToBit = pModifiers->pVkToBit;
WORD wModBits = 0;
while (pVkToBit->Vk) {
if (TestKeyDownBit(afKeyState, pVkToBit->Vk)) {
wModBits |= pVkToBit->ModBits;
}
pVkToBit++;
}
return wModBits;
}
/***************************************************************************\
* MapScancode
*
* Converts a scancode (and it's prefix, if any) to a different scancode
* and prefix.
*
* Parameters:
* pbScanCode = address of Scancode byte, the scancode may be changed
* pbPrefix = address of Prefix byte, The prefix may be changed
*
* Return value:
* TRUE - mapping was found, scancode was altered.
* FALSE - no mapping fouind, scancode was not altered.
*
* Note on scancode map table format:
* A table entry DWORD of 0xE0450075 means scancode 0x45, prefix 0xE0
* gets mapped to scancode 0x75, no prefix
*
* History:
* 96-04-18 IanJa Created.
\***************************************************************************/
BOOL
MapScancode(
PSCANCODEMAP gpScancodeMap,
PBYTE pbScanCode,
PBYTE pbPrefix
)
{
DWORD *pdw;
WORD wT = MAKEWORD(*pbScanCode, *pbPrefix);
ASSERT(gpScancodeMap != NULL);
for (pdw = &(gpScancodeMap->dwMap[0]); *pdw; pdw++) {
if (HIWORD(*pdw) == wT) {
wT = LOWORD(*pdw);
*pbScanCode = LOBYTE(wT);
*pbPrefix = HIBYTE(wT);
return TRUE;
}
}
return FALSE;
}
/*
* Given modifier bits, return the modification number.
*/
WORD GetModificationNumber(
PMODIFIERS pModifiers,
WORD wModBits)
{
if (wModBits > pModifiers->wMaxModBits) {
return SHFT_INVALID;
}
return pModifiers->ModNumber[wModBits];
}
/***************************************************************************\
* UpdatePhysKeyState
*
* A helper routine for KeyboardApcProcedure.
* Based on a VK and a make/break flag, this function will update the physical
* keystate table.
*
* History:
* 10-13-91 IanJa Created.
\***************************************************************************/
void UpdatePhysKeyState(
BYTE Vk,
BOOL fBreak,
LPBYTE gafPhysKeyState )
{
if (fBreak) {
ClearKeyDownBit(gafPhysKeyState, Vk);
} else {
/*
* This is a key make. If the key was not already down, update the
* physical toggle bit.
*/
if (!TestKeyDownBit(gafPhysKeyState, Vk)) {
if (TestKeyToggleBit(gafPhysKeyState, Vk)) {
ClearKeyToggleBit(gafPhysKeyState, Vk);
} else {
SetKeyToggleBit(gafPhysKeyState, Vk);
}
}
/*
* This is a make, so turn on the physical key down bit.
*/
SetKeyDownBit(gafPhysKeyState, Vk);
}
}
/*****************************************************************************\
* VKFromVSC
*
* This function is called from KeyEvent() after each call to VSCFromSC. The
* keyboard input data passed in is translated to a virtual key code.
* This translation is dependent upon the currently depressed modifier keys.
*
* For instance, scan codes representing the number pad keys may be
* translated into VK_NUMPAD codes or cursor movement codes depending
* upon the state of NumLock and the modifier keys.
*
* History:
*
\*****************************************************************************/
BYTE WD_VKFromVSC(
PKBDTABLES pKbdTbl,
PKE pke,
BYTE bPrefix,
LPBYTE gafPhysKeyState,
BOOLEAN KeyboardType101 )
{
USHORT usVKey = 0xFF;
PVSC_VK pVscVk = NULL;
static BOOL fVkPause;
PULONG *gapulCvt_VK;
// DBG_UNREFERENCED_PARAMETER(afKeyState);
if (pke->bScanCode == 0xFF) {
/*
* Kbd overrun (kbd hardware and/or keyboard driver) : Beep!
* (some DELL keyboards send 0xFF if keys are hit hard enough,
* presumably due to keybounce)
*/
// xxxMessageBeep(0);
return 0;
}
pke->bScanCode &= 0x7F;
// if (gptiForeground == NULL) {
// RIPMSG0(RIP_VERBOSE, "VKFromVSC: NULL gptiForeground\n");
// pKbdTbl = gpKbdTbl;
// } else {
// if (gptiForeground->spklActive) {
// pKbdTbl = gptiForeground->spklActive->spkf->pKbdTbl;
// } else {
// RIPMSG0(RIP_VERBOSE, "VKFromVSC: NULL spklActive\n");
// pKbdTbl = gpKbdTbl;
// }
// }
if (bPrefix == 0) {
if (pke->bScanCode < pKbdTbl->bMaxVSCtoVK) {
/*
* direct index into non-prefix table
*/
usVKey = pKbdTbl->pusVSCtoVK[pke->bScanCode];
if (usVKey == 0) {
return 0xFF;
}
} else {
/*
* unexpected scancode
*/
// RIPMSG2(RIP_VERBOSE, "unrecognized scancode 0x%x, prefix %x",
// pke->bScanCode, bPrefix);
return 0xFF;
}
} else {
/*
* Scan the E0 or E1 prefix table for a match
*/
if (bPrefix == 0xE0) {
/*
* Ignore the SHIFT keystrokes generated by the hardware
*/
if ((pke->bScanCode == SCANCODE_LSHIFT) ||
(pke->bScanCode == SCANCODE_RSHIFT)) {
return 0;
}
pVscVk = pKbdTbl->pVSCtoVK_E0;
} else if (bPrefix == 0xE1) {
pVscVk = pKbdTbl->pVSCtoVK_E1;
}
while (pVscVk != NULL && pVscVk->Vk) {
if (pVscVk->Vsc == pke->bScanCode) {
usVKey = pVscVk->Vk;
break;
}
pVscVk++;
}
}
/*
* Scancode set 1 returns PAUSE button as E1 1D 45 (E1 Ctrl NumLock)
* so convert E1 Ctrl to VK_PAUSE, and remember to discard the NumLock
*/
if (fVkPause) {
/*
* This is the "45" part of the Pause scancode sequence.
* Discard this key event: it is a false NumLock
*/
fVkPause = FALSE;
return 0;
}
if (usVKey == VK_PAUSE) {
/*
* This is the "E1 1D" part of the Pause scancode sequence.
* Alter the scancode to the value Windows expects for Pause,
* and remember to discard the "45" scancode that will follow
*/
pke->bScanCode = 0x45;
fVkPause = TRUE;
}
/*
* Convert to a different VK if some modifier keys are depressed.
*/
if (usVKey & KBDMULTIVK) {
WORD nMod;
PULONG pul;
nMod = GetModificationNumber(
(MODIFIERS *)&Modifiers_VK,
GetModifierBits((MODIFIERS *)&Modifiers_VK,
gafPhysKeyState));
/*
* Scan gapulCvt_VK[nMod] for matching VK.
*/
if ( KeyboardType101 )
gapulCvt_VK = (PULONG *)gapulCvt_VK_101;
else
gapulCvt_VK = (PULONG *)gapulCvt_VK_84;
if ((nMod != SHFT_INVALID) && ((pul = gapulCvt_VK[nMod]) != NULL)) {
while (*pul != 0) {
if (LOBYTE(*pul) == LOBYTE(usVKey)) {
pke->usFlaggedVk = (USHORT)HIWORD(*pul);
return (BYTE)pke->usFlaggedVk;
}
pul++;
}
}
}
pke->usFlaggedVk = usVKey;
return (BYTE)usVKey;
}
/***************************************************************************\
* KeyboardHotKeyProcedure
*
* return TRUE if the hotkey is detected, false otherwise
*
* HotkeyVk (input)
* - hotkey to look for
* HotkeyModifiers (input)
* - hotkey to look for
* pkei (input)
* - scan code
* gpScancodeMap (input)
* - scan code map from WIN32K
* pKbdTbl (input)
* - keyboard layout from WIN32K
* KeyboardType101 (input)
* - keyboard type from WIN32K
* gafPhysKeyState (input/output)
* - key states
*
\***************************************************************************/
BOOLEAN KeyboardHotKeyProcedure(
BYTE HotkeyVk,
USHORT HotkeyModifiers,
PKEYBOARD_INPUT_DATA pkei,
PVOID gpScancodeMap,
PVOID pKbdTbl,
BOOLEAN KeyboardType101,
PVOID gafPhysKeyState )
{
BYTE Vk;
BYTE bPrefix;
KE ke;
WORD ModBits;
if ( !pKbdTbl || !gafPhysKeyState ) {
return FALSE;
}
if (pkei->Flags & KEY_E0) {
bPrefix = 0xE0;
} else if (pkei->Flags & KEY_E1) {
bPrefix = 0xE1;
} else {
bPrefix = 0;
}
ke.bScanCode = (BYTE)(pkei->MakeCode & 0x7F);
if (gpScancodeMap) {
MapScancode(gpScancodeMap, &ke.bScanCode, &bPrefix);
}
Vk = WD_VKFromVSC(pKbdTbl, &ke, bPrefix, gafPhysKeyState, KeyboardType101);
if ((Vk == 0) || (Vk == VK__none_)) {
return FALSE;
}
if (pkei->Flags & KEY_BREAK) {
ke.usFlaggedVk |= KBDBREAK;
}
// Vk = (BYTE)ke.usFlaggedVk;
UpdatePhysKeyState(Vk, ke.usFlaggedVk & KBDBREAK, gafPhysKeyState);
/*
* Convert Left/Right Ctrl/Shift/Alt key to "unhanded" key.
* ie: if VK_LCONTROL or VK_RCONTROL, convert to VK_CONTROL etc.
*/
if ((Vk >= VK_LSHIFT) && (Vk <= VK_RMENU)) {
Vk = (BYTE)((Vk - VK_LSHIFT) / 2 + VK_SHIFT);
UpdatePhysKeyState(Vk, ke.usFlaggedVk & KBDBREAK, gafPhysKeyState);
}
/*
* Now check if the shadow hotkey has been hit
*/
if ( Vk == HotkeyVk && !(ke.usFlaggedVk & KBDBREAK) ) {
ModBits = GetModifierBits( (MODIFIERS *)&Modifiers_VK, gafPhysKeyState );
if ( ModBits == HotkeyModifiers )
return( TRUE );
}
return( FALSE );
}
/*******************************************************************************
*
* KeyboardSetKeyState
*
* Initialize keyboard state
*
* ENTRY:
* pgafPhysKeyState (input/output)
* - buffer to allocate or clear
*
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
#define CVKKEYSTATE 256
#define CBKEYSTATE (CVKKEYSTATE >> 2)
NTSTATUS
KeyboardSetKeyState( PTSHARE_WD pWd, PVOID *pgafPhysKeyState )
{
NTSTATUS Status = STATUS_SUCCESS;
if ( *pgafPhysKeyState == NULL ) {
*pgafPhysKeyState = COM_Malloc(CBKEYSTATE);
if ( *pgafPhysKeyState == NULL )
return STATUS_NO_MEMORY;
}
RtlZeroMemory( *pgafPhysKeyState, CBKEYSTATE );
return Status;
}
/*******************************************************************************
*
* KeyboardFixupLayout
*
* Fixup the pointers inside the keyboard layout
*
* ENTRY:
* pLayout (input/output)
* - buffer to fixup
* pOriginal (input)
* - pointer to original layout buffer
* Length (input)
* - length of layout buffer
* pKbdTblOriginal (input)
* - pointer to original KbdTbl table
* ppKbdTbl (output)
* - pointer to location to save ptr to new KbdTbl table
*
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
#define FIXUP_PTR(p, pBase, pOldBase) ((p) ? (p) = (PVOID) ( (PBYTE)pBase + (ULONG) ( (PBYTE)p - (PBYTE)pOldBase ) ) : 0)
//#define CHECK_PTR( p, Limit) { if ( (PVOID)p > Limit ) { ASSERT(FALSE); return STATUS_BUFFER_TOO_SMALL; } }
#define CHECK_PTR( ptr, Limit) \
{ if ( (PBYTE) (ptr) > (PBYTE) (Limit) ) { \
KdPrint(("Bad Ptr, Line %ld: %p > %p \n", __LINE__, ptr, Limit)); \
/* ASSERT(FALSE); */ \
/* return STATUS_BUFFER_TOO_SMALL; */ } }
NTSTATUS
KeyboardFixupLayout( PVOID pKbdLayout, PVOID pOriginal, ULONG Length,
PVOID pKbdTblOrig, PVOID *ppKbdTbl )
{
NTSTATUS Status = STATUS_SUCCESS;
VK_TO_WCHAR_TABLE *pVkToWcharTable;
VSC_LPWSTR *pKeyName;
LPWSTR *lpDeadKey;
PKBDTABLES pKbdTbl;
PVOID pLimit;
if ( Length < sizeof(KBDTABLES) ) {
Status = STATUS_BUFFER_TOO_SMALL;
goto error;
}
pLimit = (PBYTE)pKbdLayout + Length;
pKbdTbl = pKbdTblOrig;
FIXUP_PTR(pKbdTbl, pKbdLayout, pOriginal);
FIXUP_PTR(pKbdTbl->pCharModifiers, pKbdLayout, pOriginal);
CHECK_PTR(pKbdTbl->pCharModifiers, pLimit);
FIXUP_PTR(pKbdTbl->pCharModifiers->pVkToBit, pKbdLayout, pOriginal);
CHECK_PTR(pKbdTbl->pCharModifiers->pVkToBit, pLimit);
if (FIXUP_PTR(pKbdTbl->pVkToWcharTable, pKbdLayout, pOriginal)) {
CHECK_PTR(pKbdTbl->pVkToWcharTable, pLimit);
for (pVkToWcharTable = pKbdTbl->pVkToWcharTable;
pVkToWcharTable->pVkToWchars != NULL; pVkToWcharTable++) {
FIXUP_PTR(pVkToWcharTable->pVkToWchars, pKbdLayout, pOriginal);
CHECK_PTR(pVkToWcharTable->pVkToWchars, pLimit);
}
}
FIXUP_PTR(pKbdTbl->pDeadKey, pKbdLayout, pOriginal);
CHECK_PTR(pKbdTbl->pDeadKey, pLimit);
if (FIXUP_PTR(pKbdTbl->pKeyNames, pKbdLayout, pOriginal)) {
CHECK_PTR(pKbdTbl->pKeyNames, pLimit);
for (pKeyName = pKbdTbl->pKeyNames; pKeyName->vsc != 0; pKeyName++) {
FIXUP_PTR(pKeyName->pwsz, pKbdLayout, pOriginal);
CHECK_PTR(pKeyName->pwsz, pLimit);
}
}
if (FIXUP_PTR(pKbdTbl->pKeyNamesExt, pKbdLayout, pOriginal)) {
CHECK_PTR(pKbdTbl->pKeyNamesExt, pLimit);
for (pKeyName = pKbdTbl->pKeyNamesExt; pKeyName->vsc != 0; pKeyName++) {
FIXUP_PTR(pKeyName->pwsz, pKbdLayout, pOriginal);
CHECK_PTR(pKeyName->pwsz, pLimit);
}
}
if (FIXUP_PTR(pKbdTbl->pKeyNamesDead, pKbdLayout, pOriginal)) {
CHECK_PTR(pKbdTbl->pKeyNamesDead, pLimit);
for (lpDeadKey = pKbdTbl->pKeyNamesDead; *lpDeadKey != NULL;
lpDeadKey++) {
FIXUP_PTR(*lpDeadKey, pKbdLayout, pOriginal);
CHECK_PTR(*lpDeadKey, pLimit);
}
}
FIXUP_PTR(pKbdTbl->pusVSCtoVK, pKbdLayout, pOriginal);
CHECK_PTR(pKbdTbl->pusVSCtoVK, pLimit);
FIXUP_PTR(pKbdTbl->pVSCtoVK_E0, pKbdLayout, pOriginal);
CHECK_PTR(pKbdTbl->pVSCtoVK_E0, pLimit);
FIXUP_PTR(pKbdTbl->pVSCtoVK_E1, pKbdLayout, pOriginal);
CHECK_PTR(pKbdTbl->pVSCtoVK_E1, pLimit);
*ppKbdTbl = pKbdTbl;
error:
return( Status );
}
#ifdef __cplusplus
}
#endif /* __cplusplus */