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