📄 laymgr.cpp
字号:
}
//----------------------------------------------------------------------------
//
// VKeyToScanCode
//
// Maps a virtual key to an XT scan code. The LR specific virtual keys are
// mapped to LR specific scan codes.
//
//----------------------------------------------------------------------------
static
UINT32
VKeyToScanCode(
UINT32 vkey,
const VKEY_TO_SCANCODE *pVkToScanCodeTable
)
{
PREFAST_DEBUGCHK(pVkToScanCodeTable != NULL);
DEBUGCHK(IsLocked());
UINT8 uiVKey = (UINT8) vkey;
VKEY_TO_SCANCODE VkToScanCodeEntry = pVkToScanCodeTable[uiVKey];
UINT32 uiScanCode = VkToScanCodeEntry.uiVkToSc;
if (VkToScanCodeEntry.uiType == SC_E0) {
uiScanCode |= 0xe000;
}
else if (VkToScanCodeEntry.uiType == SC_E11D) {
uiScanCode |= 0xe11d00;
}
return uiScanCode;
}
//----------------------------------------------------------------------------
//
// VKeyToUnicodeInfo
//
// Set up the descriptive VKey to Unicode structure.
//
//----------------------------------------------------------------------------
static
void
VKeyToUnicodeInfo(
KBDI_VKEY_TO_UNICODE_INFO *pInfo
)
{
pInfo->cbToUnicodeState = 0;
// Since we do not know which layouts will be used, we must return the
// maximum.
pInfo->cMaxToUnicodeCharacters = MAX_TO_UNICODE_CHARACTERS;
}
//----------------------------------------------------------------------------
//
// GetModifierBits
//
// Converts KeyStateFlags to the modifier bit value
//
//----------------------------------------------------------------------------
static
WORD
GetModifierBits(
const MODIFIERS *pModifiers,
const MODIFIER_TO_SHIFT *pModToShift,
KEY_STATE_FLAGS KeyStateFlags
)
{
WORD wBits = 0;
PREFAST_DEBUGCHK(pModifiers != NULL);
PREFAST_DEBUGCHK(pModToShift != NULL);
while (pModToShift->bModifier != 0)
{
VK_TO_BIT const *pVkToBit = pModifiers->pVkToBit;
DEBUGCHK(pVkToBit != NULL);
while (pVkToBit->Vk != 0) {
if ( ((pModToShift->bModifier & pVkToBit->ModBits) != 0) &&
((pModToShift->ShiftFlag & KeyStateFlags) != 0) )
{
wBits |= pModToShift->bModifier;
}
++pVkToBit;
}
++pModToShift;
}
return wBits;
}
//----------------------------------------------------------------------------
//
// GetModificationNumber
//
// Converts a modifier bit number to a table index
//
//----------------------------------------------------------------------------
static
WORD
GetModificationNumber(
const MODIFIERS *pModifiers,
WORD wModBits
)
{
PREFAST_DEBUGCHK(pModifiers != NULL);
WORD wModNum = SHFT_INVALID;
if (wModBits <= pModifiers->wMaxModBits) {
DEBUGCHK(pModifiers->ModNumber != NULL);
wModNum = pModifiers->ModNumber[wModBits];
}
return wModNum;
}
//----------------------------------------------------------------------------
//
// SearchVkToWCharTables
//
// Returns the table containing VirtualKey, or NULL if not in any.
//
//----------------------------------------------------------------------------
static
const VK_TO_WCHARS1*
SearchVkToWCharTables(
UINT32 VirtualKey,
const VK_TO_WCHAR_TABLE **ppVkToWCharTable
)
{
PREFAST_DEBUGCHK(ppVkToWCharTable != NULL);
PREFAST_DEBUGCHK(*ppVkToWCharTable != NULL);
DEBUGCHK(IsLocked());
const VK_TO_WCHARS1 *pActualVkToWChars = NULL;
const VK_TO_WCHARS1 *pCurrVkToWChars;
const VK_TO_WCHAR_TABLE *pVkToWCharTable = *ppVkToWCharTable;
if (VirtualKey) {
while ( (pActualVkToWChars == NULL) &&
(pVkToWCharTable->pVkToWchars != NULL) ) {
DEBUGCHK(pVkToWCharTable->pVkToWchars != NULL);
pCurrVkToWChars = pVkToWCharTable->pVkToWchars;
PREFAST_DEBUGCHK(pCurrVkToWChars != NULL);
DWORD cbCurrEntry = pVkToWCharTable->cbSize;
// Linear search for entry
while (pCurrVkToWChars->VirtualKey != 0) {
if (pCurrVkToWChars->VirtualKey == VirtualKey) {
*ppVkToWCharTable = pVkToWCharTable;
pActualVkToWChars = pCurrVkToWChars;
break;
}
pCurrVkToWChars = (PVK_TO_WCHARS1)
(((const BYTE*) pCurrVkToWChars) + cbCurrEntry);
}
++pVkToWCharTable;
}
}
DEBUGCHK((pActualVkToWChars == NULL) ||
(pActualVkToWChars->VirtualKey == VirtualKey));
return pActualVkToWChars;
}
//----------------------------------------------------------------------------
//
// GetControlledChar
//
// Ctrl-[Shift]-A through Ctrl-[Shift]-Z return chars of 1 through 26.
// Returns 0 if Alt is down.
//
//----------------------------------------------------------------------------
static
WCHAR
GetControlledChar(
UINT32 uiVKey,
KEY_STATE_FLAGS ksf
)
{
static const UINT32 uiMask = KeyShiftAnyCtrlFlag | KeyShiftAnyAltFlag;
static const UINT32 uiMaskMatch = KeyShiftAnyCtrlFlag;
WCHAR wch = '\0';
if ((ksf & uiMask) == uiMaskMatch) {
if (uiVKey >= 'A' && uiVKey <= 'Z') {
wch = uiVKey - 'A' + 1;
}
}
return wch;
}
// Update the pwModBits based on row properties. Perhaps even change
// row pointer (ppVkToWChars).
static
VOID
ProcessModBitsForAttributes(
DWORD cbVkToWChars,
KEY_STATE_FLAGS ShiftFlags,
IN OUT PWORD pwModBits,
IN OUT const VK_TO_WCHARS1 **ppVkToWChars
)
{
DEBUGCHK(cbVkToWChars);
PREFAST_DEBUGCHK(pwModBits);
PREFAST_DEBUGCHK(ppVkToWChars);
PREFAST_DEBUGCHK(*ppVkToWChars);
const WORD wCtrlAltMask = (KBDALT | KBDCTRL);
WORD wModBits = *pwModBits;
const VK_TO_WCHARS1 *pVkToWChars = *ppVkToWChars;
if ((wModBits & wCtrlAltMask) == KBDALT) {
// The KBDALT modifier in the Input Language tells the Layout
// Manager to perform Alt+NumPad character generation, so
// we mask it off here. However, we only do this when the
// KBDCTRL modifier is not set since Ctrl+Alt is a valid
// modifier combination.
wModBits &= ~KBDALT;
}
// If Kana is on and affects this character, then none of the other
// Attributes should affect the modification bits.
if ( (pVkToWChars->Attributes & KANALOK) &&
(ShiftFlags & KeyShiftKanaFlag) ) {
DEBUGCHK(wModBits & KBDKANA);
}
else {
if ( (pVkToWChars->Attributes & CAPLOK) &&
((wModBits & wCtrlAltMask) == 0) &&
(ShiftFlags & KeyShiftCapitalFlag) ) {
// Flip the shift bit if CAPLOK is set for this key,
// neither control nor alt are down, and CapsLock is on.
wModBits ^= KBDSHIFT;
}
else if ( (pVkToWChars->Attributes & CAPLOKALTGR) &&
((wModBits & wCtrlAltMask) == wCtrlAltMask) &&
(ShiftFlags & KeyShiftCapitalFlag) ) {
// Flip the shift bit if CAPLOKALTGR is set for this key,
// both alt and control are down, and CapsLock is on.
wModBits ^= KBDSHIFT;
}
if ( (pVkToWChars->Attributes & SGCAPS) &&
((wModBits & wCtrlAltMask) == 0) &&
(ShiftFlags & KeyShiftCapitalFlag) ) {
// Use the next VkToWChars entry if SGCAPS is set for this key,
// neither control nor alt are down, and CapsLock is on.
BYTE bCurrVk = pVkToWChars->VirtualKey;
pVkToWChars = (const VK_TO_WCHARS1*)
(((const BYTE*) pVkToWChars) + cbVkToWChars);
DEBUGCHK(pVkToWChars->VirtualKey == bCurrVk);
}
}
*pwModBits = wModBits;
*ppVkToWChars = pVkToWChars;
}
// Safely write to the pChar buffer. Increments *pcChars if there is space
// for this character.
static
inline
VOID
WriteToCharBuffer(
WCHAR wch,
UINT32 cChars, // Total count of elements in pcChars
UINT32 *pChars, // Index of next empty slot in pcChars
UINT32 *pcChars
)
{
PREFAST_DEBUGCHK(pChars);
PREFAST_DEBUGCHK(pcChars);
if (*pcChars < cChars) {
pChars[(*pcChars)++] = wch;
}
else {
ERRORMSG(1,
(_T("WriteToCharBuffer: Character buffer is not large enough to hold '%c' (0x%04x)\r\n"),
wch, wch));
}
}
//----------------------------------------------------------------------------
//
// ProcessDeadKeys
//
// Called when a key is pressed after a dead key. Fills pChars with either
// the generated character or both individual characters if this was not a
// valid dead key combination.
//
// Returns number of characters placed in pChars.
//
//----------------------------------------------------------------------------
static
UINT32
ProcessDeadKeys(
WCHAR *pwchDeadKey,
const DEADKEY *pDeadKey,
WCHAR wch,
UINT32 *pChars,
UINT32 cChars,
KEY_STATE_FLAGS ShiftFlags
)
{
SETFNAME(_T("ProcessDeadKeys"));
PREFAST_DEBUGCHK(pwchDeadKey != NULL);
DEBUGCHK(*pwchDeadKey != 0);
PREFAST_DEBUGCHK(pDeadKey != NULL);
DEBUGCHK(wch != 0);
DEBUGCHK(pChars != NULL);
DEBUGCHK(cChars != 0);
UINT32 cchValid = 0;
WCHAR wchOriginalDeadKey = *pwchDeadKey;
DWORD dwBoth = MAKELONG(wch, *pwchDeadKey);
BOOL fKeyDown = (ShiftFlags & KeyStateDownFlag);
BOOL fFound = FALSE;
// First search the dead key table for a match of the combination
// of dead key char + new key char
if (fKeyDown) {
// Dead keys only apply to the next key pressed.
// Reset the dead key variable.
*pwchDeadKey = 0;
}
while (pDeadKey->dwBoth != 0)
{
if (pDeadKey->dwBoth == dwBoth) {
// Found the match.
if (pDeadKey->uFlags & DKF_DEAD) {
DEBUGMSG(ZONE_ERROR, (_T("%s: No support for DKF_DEAD flag\r\n"),
pszFname));
}
else {
WriteToCharBuffer(pDeadKey->wchComposed, cChars, pChars, &cchValid);
}
fFound = TRUE;
break;
}
++pDeadKey;
}
if (fFound == FALSE) {
// There was not dead key match for this combination.
// Both the dead key char and the new key char should
// be sent as individual characters.
WriteToCharBuffer(wchOriginalDeadKey, cChars, pChars, &cchValid);
if (cChars >= 2) {
WriteToCharBuffer(wch, cChars, pChars, &cchValid);
}
}
return cchValid;
}
// Process the WCH_LGTR match.
// Returns number of characters placed in pChars.
static
UINT32
ProcessLigature(
PINPUT_LANGUAGE_INFO pili,
UINT32 uiVk,
KEY_STATE_FLAGS ShiftFlags,
WORD wModNum,
UINT32 *pChars,
UINT32 cChars
)
{
SETFNAME(_T("ProcessLigature"));
PREFAST_DEBUGCHK(pili);
DEBUGCHK(pChars);
DEBUGCHK(cChars);
DEBUGCHK(IsLocked());
UINT32 cchValid = 0;
const LIGATURE1 *pLigature = pili->il.pLigature;
if (pLigature == NULL) {
ERRORMSG(1, (_T("ProcessLigature: WCH_LGTR but no ligature table\r\n")));
WriteToCharBuffer(0, cChars, pChars, &cchValid);
}
else {
const DWORD cbLigatureRow = pili->il.cbLgEntry;
while (pLigature->VirtualKey) {
if ( (pLigature->VirtualKey == uiVk) &&
(pLigature->ModificationNumber == wModNum) ) {
// Found match
DWORD dwChar = 0;
const DWORD cwchLig = pili->il.nLgMax;
while (dwChar < cwchLig) {
WCHAR wch = pLigature->wch[dwChar];
if (cchValid > cwchLig) {
ERRORMSG(1, (_T("ProcessLigature: Too many characters for buffer\r\n")));
break;
}
else if (wch == WCH_NONE) {
// No more characters for this row
break;
}
else {
if (pili->wchDeadChar) {
DWORD dwNewChars =
ProcessDeadKeys(&pili->wchDeadChar,
pili->il.pDeadKey, wch, pChars + cchValid,
cChars - cchValid, ShiftFlags);
if (dwNewChars) {
cchValid += dwNewChars;
}
else {
// This is very unexpected and should probably be avoided.
DEBUGMSG(ZONE_ERROR,
(_T("%s: Dead key + ligature 0x%04x produced a dead key 0x%04x"),
pszFname, wch, pili->wchDeadChar));
}
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -