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.
 
 
 
 
 
 

712 lines
21 KiB

/****************************** Module Header ******************************\
* Module Name: xlate.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* History:
* 12-07-90 GregoryW Created.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* "The great artist is the simplifier."
* - Henri Frederic Amiel (1821-1881)
* Ibid., November 25, 1861
*/
/*
* 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.
*/
WORD GetModifierBits(
PMODIFIERS pModifiers,
LPBYTE afKeyState)
{
PVK_TO_BIT pVkToBit = pModifiers->pVkToBit;
WORD wModBits = 0;
CheckCritIn();
while (pVkToBit->Vk) {
if (TestKeyDownBit(afKeyState, pVkToBit->Vk)) {
wModBits |= pVkToBit->ModBits;
}
pVkToBit++;
}
return wModBits;
}
/*
* Given modifier bits, return the modification number.
*/
WORD GetModificationNumber(
PMODIFIERS pModifiers,
WORD wModBits)
{
CheckCritInShared();
if (wModBits > pModifiers->wMaxModBits) {
return SHFT_INVALID;
}
return pModifiers->ModNumber[wModBits];
}
/*****************************************************************************\
* 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 VKFromVSC(
PKE pke,
BYTE bPrefix,
LPBYTE afKeyState
)
{
USHORT usVKey;
PVSC_VK pVscVk;
PKBDTABLES pKbdTbl;
static BOOL fVkPause;
CheckCritIn();
DBG_UNREFERENCED_PARAMETER(afKeyState);
/*
* Initialize as an unknown VK (unrecognised scancode)
*/
pke->usFlaggedVk = usVKey = VK_UNKNOWN;
/* HACK ALERT
* For Korean 103 keyboard:
* Check this is Korean keyboard layout or not.
*/
if (IS_IME_ENABLED() &&
KOREAN_KBD_LAYOUT(GetActiveHKL())) {
if ((pke->bScanCode == 0x71) || (pke->bScanCode == 0x72)) {
pke->bScanCode |= 0x80;
bPrefix = 0xE0;
} else {
pke->bScanCode &= 0x7F;
}
} else {
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) {
/*
* Set the KBDEXT (extended key) bit in case the scancode is not
* found in the table (eg: FUJITSU POS keyboard #65436)
*/
usVKey |= KBDEXT;
/*
* Ignore the SHIFT keystrokes generated by the hardware
*/
if ((pke->bScanCode == SCANCODE_LSHIFT) ||
(pke->bScanCode == SCANCODE_RSHIFT)) {
TAGMSG1(DBGTAG_KBD, "VKFromVSC: E0, %02x ignored", pke->bScanCode);
return 0;
}
pVscVk = pKbdTbl->pVSCtoVK_E0;
} else if (bPrefix == 0xE1) {
pVscVk = pKbdTbl->pVSCtoVK_E1;
} else {
/*
* Unrecognized prefix (from ScancodeMap?) produces an
* unextended and unrecognized VK.
*/
return 0xFF;
}
while (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(
gpModifiers_VK,
GetModifierBits(gpModifiers_VK, gafRawKeyState));
/*
* Scan gapulCvt_VK[nMod] for matching VK.
*/
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;
}
/***************************************************************************\
* UINT InternalMapVirtualKeyEx(UINT wCode, UINT wType, PKBDTABLES pKbdTbl);
*
* History:
* IanJa 5/13/91 from Win3.1 \\pucus\win31ro!drivers\keyboard\getname.asm
* GregoryW 2/21/95 renamed from _MapVirtualKey and added third parameter.
\***************************************************************************/
UINT InternalMapVirtualKeyEx(
UINT wCode,
UINT wType,
PKBDTABLES pKbdTbl)
{
PVK_TO_WCHARS1 pVK;
PVK_TO_WCHAR_TABLE pVKT;
UINT VkRet = 0;
USHORT usScanCode;
PVSC_VK pVscVk;
PBYTE pVkNumpad;
switch (wType) {
case 0:
/*
* Convert Virtual Key (wCode) to Scan Code
*/
if ((wCode >= VK_SHIFT) && (wCode <= VK_MENU)) {
/*
* Convert ambiguous Shift/Control/Alt keys to left-hand keys
*/
wCode = (UINT)((wCode - VK_SHIFT) * 2 + VK_LSHIFT);
}
/*
* Scan through the table that maps Virtual Scancodes to Virtual Keys
* for non-extended keys.
*/
for (usScanCode = 0; usScanCode < pKbdTbl->bMaxVSCtoVK; usScanCode++) {
if ((UINT)LOBYTE(pKbdTbl->pusVSCtoVK[usScanCode]) == wCode) {
return usScanCode & 0xFF;
}
}
/*
* Scan through the table that maps Virtual Scancodes to Virtual Keys
* for extended keys.
*/
for (pVscVk = pKbdTbl->pVSCtoVK_E0; pVscVk->Vk; pVscVk++) {
if ((UINT)LOBYTE(pVscVk->Vk) == wCode) {
return (UINT)pVscVk->Vsc;
}
}
/*
* There was no match: maybe the Virtual Key can only be generated
* with Numlock on. Scan through aVkNumpad[] to determine scancode.
*/
for (pVkNumpad = aVkNumpad; *pVkNumpad != 0; pVkNumpad++) {
if ((UINT)(*pVkNumpad) == wCode) {
return (UINT)(pVkNumpad - aVkNumpad) + SCANCODE_NUMPAD_FIRST;
}
}
return 0; // No match found!
case 1:
case 3:
/*
* Convert Scan Code (wCode) to Virtual Key, disregarding modifier keys
* and NumLock key etc. Returns 0 for no corresponding Virtual Key
*/
if (wCode < (UINT)(pKbdTbl->bMaxVSCtoVK)) {
VkRet = (UINT)LOBYTE(pKbdTbl->pusVSCtoVK[wCode]);
} else {
/*
* Scan the E0 prefix table for a match
*/
for (pVscVk = pKbdTbl->pVSCtoVK_E0; pVscVk->Vk; pVscVk++) {
if ((UINT)pVscVk->Vsc == wCode) {
VkRet = (UINT)LOBYTE(pVscVk->Vk);
break;
}
}
}
if ((wType == 1) && (VkRet >= VK_LSHIFT) && (VkRet <= VK_RMENU)) {
/*
* Convert left/right Shift/Control/Alt keys to ambiguous keys
* (neither left nor right)
*/
VkRet = (UINT)((VkRet - VK_LSHIFT) / 2 + VK_SHIFT);
}
if (VkRet == 0xFF) {
VkRet = 0;
}
return VkRet;
case 2:
/*
* Bogus Win3.1 functionality: despite SDK documenation, return uppercase for
* VK_A through VK_Z
*/
if ((wCode >= (WORD)'A') && (wCode <= (WORD)'Z')) {
return wCode;
}
// HIWORD is no loner the wchar, due to app compat problems #287134
// We should not return the wchar from pti->wchInjected that cached
// at GetMessage time.
// (delete this commented-out section by end of March 1999 - IanJa)
//
// if (LOWORD(wCode) == VK_PACKET) {
// return HIWORD(wCode);
// }
/*
* Convert Virtual Key (wCode) to ANSI.
* Search each Shift-state table in turn, looking for the Virtual Key.
*/
for (pVKT = pKbdTbl->pVkToWcharTable; pVKT->pVkToWchars != NULL; pVKT++) {
pVK = pVKT->pVkToWchars;
while (pVK->VirtualKey != 0) {
if ((UINT)pVK->VirtualKey == wCode) {
/*
* Match found: return the unshifted character
*/
if (pVK->wch[0] == WCH_DEAD) {
/*
* It is a dead character: the next entry contains its
* value. Set the high bit to indicate dead key
* (undocumented behaviour)
*/
pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize);
return pVK->wch[0] | (UINT)0x80000000;
} else if (pVK->wch[0] == WCH_NONE) {
return 0; // 9013
}
if (pVK->wch[0] == WCH_NONE) {
return 0;
}
return pVK->wch[0];
}
pVK = (PVK_TO_WCHARS1)((PBYTE)pVK + pVKT->cbSize);
}
}
}
/*
* Can't find translation, or wType was invalid
*/
return 0;
}
/***************************************************************************\
* _GetKeyNameText (API)
*
* int _GetKeyNameText(DWORD lParam, LPSTR lpStr, UINT size);
*
* lParam: value from WM_KEYDOWN message, etc.
*
* Byte 3 (bits 16..23) of lParam contains a scan code.
*
* Bit 20 of lParam is the Extended bit (distingushes some keys on
* Enhanced keyboard).
*
* Bit 21 of lParam is a don't care bit (don't distingush between
* left and right control, shift, Enter keys, between edit keys
* in edit area and on numeric pad, etc). The app calling this
* function sets this bit in lParam, if it so desires.
*
* lpStr: Pointer to output string.
*
* iSize: Maximum length of output string, not including null byte.
*
* History:
* IanJa 4/11/91 from Win3.1 \\pucus\win31ro!drivers\keyboard\getname.asm
\***************************************************************************/
int APIENTRY _GetKeyNameText(
LONG lParam,
LPWSTR ccxlpStr,
int cchSize)
{
BYTE Vsc = LOBYTE(HIWORD(lParam));
PVSC_LPWSTR pKN;
PTHREADINFO ptiT = PtiCurrentShared();
PKBDTABLES pKbdTbl;
UINT Vk;
UINT Char;
/*
* NOTE -- lpStr can be a client-side address, so access through it
* must be guarded with try blocks.
*/
if (cchSize < 1)
return 0;
/*
* If bit 25 set (don't care about left vs. right) then:
* 1) convert right-Shift into left-Shift
* 2) clear the extended bit for Ctrl and Alt only (effectively converting
* right-Ctrl & right-Alt into left-Ctrl & right-Alt)
* For Windows '95 compatibility, the DONTCARE_BIT doesn't apply to other
* extended keys (eg: NumPad cursor movement keys, NumPad Enter). Some
* applications (Word '95) depend on this. #37796
*/
if (lParam & DONTCARE_BIT) {
if (Vsc == SCANCODE_RSHIFT) {
Vsc = SCANCODE_LSHIFT;
}
if (lParam & EXTENDED_BIT) {
if ((Vsc == SCANCODE_CTRL) || (Vsc == SCANCODE_ALT)) {
lParam &= ~EXTENDED_BIT;
}
}
lParam &= ~DONTCARE_BIT;
}
if (ptiT->spklActive == (PKL)NULL) {
return 0;
}
pKbdTbl = ptiT->spklActive->spkf->pKbdTbl;
/*
* Scan pKbdTbl->pKeyNames[] or pKeyNamesExt[] for matching Virtual Scan Code
*/
if (lParam & EXTENDED_BIT) {
pKN = pKbdTbl->pKeyNamesExt;
} else {
pKN = pKbdTbl->pKeyNames;
}
if (pKN) {
while (pKN->vsc != 0) {
if (Vsc == pKN->vsc) {
try {
cchSize = wcsncpycch(ccxlpStr, pKN->pwsz, cchSize);
cchSize--;
ccxlpStr[cchSize] = L'\0';
} except(W32ExceptionHandler(TRUE, RIP_ERROR)) {
return 0;
}
return cchSize;
}
pKN++;
}
}
/*
* The name of the key was not found in the table, so we
* now attempt to construct the key name from the character produced by
* the key. Translate Scancode -> Virtual Key -> character.
*/
/*
* Translate Scancode to Virtual Key (ignoring modifier keys etc.)
*/
Vk = InternalMapVirtualKeyEx((UINT)Vsc, 1, pKbdTbl);
if (Vk == 0) {
return 0;
}
/*
* Now translate Virtual Key to character (ignoring modifier keys etc.)
*/
Char = InternalMapVirtualKeyEx((UINT)Vk, 2, pKbdTbl);
if (Char == 0) {
return 0;
}
if (Char & 0x80000000) {
LPWSTR *ppwsz;
ppwsz = pKbdTbl->pKeyNamesDead;
if (ppwsz) {
while (*ppwsz != NULL) {
if (*ppwsz[0] == (WCHAR)Char) {
try {
cchSize = wcsncpycch(ccxlpStr, (*ppwsz)+1, cchSize);
cchSize--;
ccxlpStr[cchSize] = L'\0';
} except(W32ExceptionHandler(TRUE, RIP_ERROR)) {
return 0;
}
return cchSize;
}
ppwsz++;
}
}
}
/*
* Construct a single character name (adding null-terminator if possible)
*/
try {
ccxlpStr[0] = (WCHAR)Char;
if (cchSize >= 2) {
ccxlpStr[1] = L'\0';
}
} except(W32ExceptionHandler(TRUE, RIP_ERROR)) {
return 0;
}
return 1;
}
/***************************************************************************\
* xxxAltGr() - handle special case Right-hand ALT key (Locale dependent)
*
* Note: gbAltGrDown reminds us to send the fake Ctrl key back up if we
* switched to a non-AltGr layout while ALtGr was down: otherwise the Ctrl key
* gets stuck down. (For example: using AltGr with KBDSEL to switch from
* German to US layout).
\***************************************************************************/
BOOL gbAltGrDown = FALSE;
VOID xxxAltGr(
PKE pKe)
{
if ((pKe->usFlaggedVk & 0xFF) != VK_RMENU) {
return;
}
if (!(pKe->usFlaggedVk & KBDBREAK)) {
/*
* If neither CTRL key is down, then fake one going down so that
* the right hand ALT key is converted to CTRL + ALT.
*/
if (!TestRawKeyDown(VK_CONTROL)) {
gbAltGrDown = TRUE;
xxxKeyEvent(VK_LCONTROL, 0x1D | SCANCODE_SIMULATED,
pKe->dwTime, 0,
#ifdef GENERIC_INPUT // LATER: NULL, or pKe->hDevice?
NULL,
NULL,
#endif
FALSE);
}
} else {
/*
* If the physical Left Ctrl key is not really down, fake the
* Left Ctrl key coming back up (undo earlier faked Left Ctrl down)
*/
gbAltGrDown = FALSE;
if (!TestRawKeyDown(VK_LCONTROL)) {
xxxKeyEvent(VK_LCONTROL | KBDBREAK, 0x1D | SCANCODE_SIMULATED,
pKe->dwTime, 0,
#ifdef GENERIC_INPUT
NULL,
NULL,
#endif
FALSE);
}
}
}
/*****************************************************************************\
* xxxShiftLock()
* handle ShiftLock feature, where only hitting Shift turns CapsLock off
*
\*****************************************************************************/
BOOL xxxShiftLock(
PKE pKe)
{
USHORT Vk;
/*
* We only mess with downstrokes: return TRUE to let it pass unmolested.
*/
if (pKe->usFlaggedVk & KBDBREAK) {
return TRUE;
}
Vk = pKe->usFlaggedVk & 0xFF;
/*
* If CapsLock is pressed when CapsLock is already on, lose the keystroke.
*/
if ((Vk == VK_CAPITAL) && TestAsyncKeyStateToggle(VK_CAPITAL)) {
return FALSE;
}
/*
* If a Shift key goes down when CapsLock is on, turn CapsLock off
* by simulating a click on the CapsLock key.
* Let the Shift down through FIRST, since it might be part of an
* input lang toggle (tough luck that this toggle turns off CapsLock!)
*/
if (((Vk == VK_LSHIFT) || (Vk == VK_RSHIFT) || (Vk == VK_SHIFT)) &&
TestAsyncKeyStateToggle(VK_CAPITAL)) {
xxxKeyEvent(pKe->usFlaggedVk, pKe->bScanCode,
pKe->dwTime, 0,
#ifdef GENERIC_INPUT
NULL,
NULL,
#endif
FALSE);
xxxKeyEvent(VK_CAPITAL, 0x3A | SCANCODE_SIMULATED,
pKe->dwTime, 0,
#ifdef GENERIC_INPUT
NULL,
NULL,
#endif
FALSE);
xxxKeyEvent(VK_CAPITAL | KBDBREAK, 0x3A | SCANCODE_SIMULATED,
pKe->dwTime, 0,
#ifdef GENERIC_INPUT
NULL,
NULL,
#endif
FALSE);
return FALSE;
}
return TRUE;
}
/*
* Returning FALSE means the Key Event has been deleted by a special-case
* KeyEvent processor.
* Returning TRUE means the Key Event should be passed on (although it may
* have been altered.
*/
BOOL KEOEMProcs(PKE pKe)
{
int i;
CheckCritIn();
for (i = 0; aKEProcOEM[i] != NULL; i++) {
if (!aKEProcOEM[i](pKe)) {
/*
* Eat the key event
*/
return FALSE;
}
}
/*
* Pass the (possibly altered) key event on.
*/
return TRUE;
}
/*
* Returning FALSE means the Key Event has been deleted by a special-case
* KeyEvent processor.
* Returning TRUE means the Key Event should be passed on (although it may
* have been altered.
*/
BOOL xxxKELocaleProcs(PKE pKe)
{
CheckCritIn();
/*
* AltGr is a layout-specific behavior
* Modifier keys are sent up as necessary in xxxInternalActivateKeyboardLayout
* (#139178), so left-Ctrl won't be left stuck down if we switch from an
* AltGr keyboard to a non-AltGr keybord while the AltGr is held down.
*/
if ((gpKbdTbl->fLocaleFlags & KLLF_ALTGR) || gbAltGrDown) {
xxxAltGr(pKe);
}
/*
* ShiftLock/CapsLock is per-user (global) behavior as well as (for
* backward compatibility) per-layout behavior.
*/
if ((gdwKeyboardAttributes & KLLF_SHIFTLOCK) ||
(gpKbdTbl->fLocaleFlags & KLLF_SHIFTLOCK)) {
if (!xxxShiftLock(pKe)) {
return FALSE;
}
}
/*
* Other special Key Event processors
*/
return TRUE;
}