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
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 */
|
|
|