📄 laymgr.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
// Copyright (C) 2004-2006, Freescale Semiconductor, Inc. All Rights Reserved.
// THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
// AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//------------------------------------------------------------------------------
#include <windows.h>
#include <keybd.h>
#include <keybddr.h>
#include <laymgr.h>
#include <keybdpdd.h>
#include <pnp.h>
#include <msgqueue.h>
#include "devicelayout.h"
#include "InputLang.h"
#include <winuserm.h>
const char pszFname[]="LayMgr.cpp";
struct PRIVATE_KEYBD_EVENT {
UINT uiPddId;
UINT32 uiScanCode;
BOOL fKeyUp;
#ifdef DEBUG
BOOL fValid;
#endif
};
// Used to send a keyboard event to the keyboard thread
static PRIVATE_KEYBD_EVENT g_PrivateKeybdEvent;
static HANDLE g_hEventThread;
static HANDLE g_hevBeginEvent;
static HANDLE g_hevEndEvent;
CRITICAL_SECTION g_csEventCallback;
struct MODIFIER_TO_SHIFT {
BYTE bModifier;
KEY_STATE_FLAGS ShiftFlag;
};
#define MAX_MODIFIERS 6
// Input language wrapper
typedef struct tagINPUT_LANGUAGE_INFO {
HKL hkl;
WCHAR szName[KL_NAMELENGTH];
WCHAR szDll[MAX_PATH];
INPUT_LANGUAGE il;
BOOL fGenerateNumPadChars;
WCHAR wchDeadChar;
const VK_TO_SHIFT *pVkToShiftState;
const VK_TO_SHIFT *pVkToToggledState;
MODIFIER_TO_SHIFT rgModToShift[MAX_MODIFIERS+1]; // +1 FOR {0, 0}
HINSTANCE hDll;
HKL hklFull;
WCHAR szFullName[KL_NAMELENGTH];
} INPUT_LANGUAGE_INFO, *PINPUT_LANGUAGE_INFO;
#define INVALID_HKL ((HKL)0x00000000)
static INPUT_LANGUAGE_INFO g_ili = { INVALID_HKL };
#define DL_PROC_PREFIXLENGTH 30
#define DL_PROC_NAMELENGTH (DL_PROC_PREFIXLENGTH + KL_NAMELENGTH + 1)
#ifdef DEBUG
#define DEFAULT_REMAP_BUFFER_SIZE 1 // Exercise dynamic code
#else
#define DEFAULT_REMAP_BUFFER_SIZE 8
#endif
// Device layout wrapper
typedef struct tagDEVICE_LAYOUT_INFO {
HKL hkl;
WCHAR szProcName[DL_PROC_NAMELENGTH];
WCHAR szDll[MAX_PATH];
DEVICE_LAYOUT dl;
HINSTANCE hDll;
KEYBD_EVENT rgKbdEvent[DEFAULT_REMAP_BUFFER_SIZE];
UINT cMaxRmpKbdEvents;
KEYBD_EVENT *pKbdEvents; // Buffer in case rgKbdEvent is too small
} DEVICE_LAYOUT_INFO, *PDEVICE_LAYOUT_INFO;
// PDD wrapper
typedef struct tagKEYBD_PDD_INFO {
BOOL fValid;
PKEYBD_PDD pKeybdPdd;
DEVICE_LAYOUT_INFO dli;
} KEYBD_PDD_INFO, *PKEYBD_PDD_INFO;
static KEYBD_PDD_INFO *g_pPdds;
static UINT g_cPdds;
// Event used to terminate the notifications thread.
static HANDLE g_hevExitNotficationThread;
// Array holding open file handles to keyboard devices.
static HANDLE g_rghKbd[10];
// Critical section to guard access to all global data structures
static CRITICAL_SECTION g_csAccessInputLocaleInfo;
#ifdef DEBUG
static UINT g_cInAccessCS = 0;
#endif
// Keeps track of the most recent KeyStateFlags
static KEY_STATE_FLAGS g_KeyStateFlags;
// Size of buffer used in KeybdDriverVKeyToUnicode
#define MAX_TO_UNICODE_CHARACTERS 16
// AltGr can turn one scan code/vkey into two
#define ALTGR_MAPPING 2
#define VK_A 'A'
#define VK_F 'F'
#define VK_X 'X'
static const VK_TO_SHIFT g_rgVkToShiftState[] = {
{ VK_CONTROL, KeyShiftAnyCtrlFlag },
{ VK_LCONTROL, KeyShiftLeftCtrlFlag },
{ VK_RCONTROL, KeyShiftRightCtrlFlag },
{ VK_SHIFT, KeyShiftAnyShiftFlag },
{ VK_LSHIFT, KeyShiftLeftShiftFlag },
{ VK_RSHIFT, KeyShiftRightShiftFlag },
{ VK_MENU, KeyShiftAnyAltFlag },
{ VK_LMENU, KeyShiftLeftAltFlag },
{ VK_RMENU, KeyShiftRightAltFlag },
// VK_LWIN and VK_RWIN do not have a merged key.
{ VK_LWIN, KeyShiftLeftWinFlag },
{ VK_RWIN, KeyShiftRightWinFlag },
{ VK_SYMBOL, KeyShiftReserved100 },
{ 0, 0 }
};
static const VK_TO_SHIFT g_rgVkToToggledState[] = {
{ VK_CAPITAL, KeyShiftCapitalFlag },
{ VK_NUMLOCK, KeyShiftNumLockFlag },
{ VK_SCROLL, KeyShiftScrollLockFlag },
{ 0, 0 }
};
static const TCHAR g_szRegLayouts[] =
_T("System\\CurrentControlSet\\Control\\Layouts");
static const TCHAR g_szProcPrefix[] = _T("IL_");
static const TCHAR g_szLayoutTextValue[] = _T("Layout Text");
static const TCHAR g_szLayoutFileValue[] = _T("Layout File");
static const TCHAR g_szImeFileValue[] = _T("Ime File");
// List of PDD entry points.
extern PFN_KEYBD_PDD_ENTRY g_rgpfnPddEntries[];
void
ToggleLights(
KEY_STATE_FLAGS KeyStateFlags
);
#ifdef DEBUG
// Checks to see if the global access cs is currently entered
static
inline
BOOL
IsLocked(
void
)
{
return g_cInAccessCS > 0;
}
#endif
// Enters the global access cs
static
inline
void
LockConfig(
void
)
{
DEBUGCHK(g_cInAccessCS < 10); // Check for cycle
EnterCriticalSection(&g_csAccessInputLocaleInfo);
#ifdef DEBUG
++g_cInAccessCS;
#endif
}
// Leaves the global access cs
static
inline
void
UnlockConfig(
void
)
{
DEBUGCHK(IsLocked() == TRUE);
LeaveCriticalSection(&g_csAccessInputLocaleInfo);
#ifdef DEBUG
--g_cInAccessCS;
#endif
}
// Gets the PDD info structure from an index. Checks bounds.
static
inline
PKEYBD_PDD_INFO
pKeybdPddInfoFromId(
UINT uiPddId
)
{
PREFAST_DEBUGCHK(g_pPdds != NULL);
DEBUGCHK(uiPddId < g_cPdds);
PKEYBD_PDD_INFO pKeybdPddInfo = &(g_pPdds[uiPddId]);
DEBUGCHK(pKeybdPddInfo != NULL);
return pKeybdPddInfo;
}
// Gets the PDD structure from an index.
// Return value is a reference so that the caller can take the address of it.
static
inline
PKEYBD_PDD
pKeybdPddFromId(
UINT uiPddId
)
{
PKEYBD_PDD pKeybdPdd = pKeybdPddInfoFromId(uiPddId)->pKeybdPdd;
DEBUGCHK(pKeybdPdd != NULL);
return pKeybdPdd;
}
// Gets the device layout info structure from a PDD index.
static
inline
PDEVICE_LAYOUT_INFO
pDLIFromPDDIndex(
UINT uiPddId
)
{
PDEVICE_LAYOUT_INFO pdli = &(pKeybdPddInfoFromId(uiPddId)->dli);
DEBUGCHK(pdli != NULL);
return pdli;
}
static
BOOL
ValidateKeybdPdd(
const KEYBD_PDD *pKeybdPdd
)
{
return TRUE;
}
//----------------------------------------------------------------------------
//
// ValidateInputLanguage
//
// Validates all data in an input language.
//
// Return value:
//
// TRUE if it is valid.
//
//----------------------------------------------------------------------------
static
BOOL
ValidateInputLanguage(
const INPUT_LANGUAGE *pil
)
{
BOOL fRet = FALSE;
PREFAST_DEBUGCHK(pil);
if (pil->dwSize != sizeof(INPUT_LANGUAGE)) {
goto leave;
}
if ( (pil->pCharModifiers == NULL) ||
(pil->pCharModifiers->pVkToBit == NULL) ||
(pil->pVkToWcharTable == NULL) ||
(pil->pVkToScanCodeTable == NULL) ) {
goto leave;
}
const VK_TO_WCHAR_TABLE *pVkToWcharTable = pil->pVkToWcharTable;
while (pVkToWcharTable->pVkToWchars) {
const VK_TO_WCHARS1 *pVkToWchars = pVkToWcharTable->pVkToWchars;
DWORD cbSize = pVkToWcharTable->cbSize;
if (cbSize == 0) {
goto leave;
}
++pVkToWcharTable;
}
if (pil->pLigature) {
if ( (pil->nLgMax == 0) || (pil->cbLgEntry == 0) ) {
goto leave;
}
else if (pil->nLgMax > MAX_TO_UNICODE_CHARACTERS) {
goto leave;
}
}
fRet = TRUE;
leave:
if (fRet == FALSE) {
ERRORMSG(1, (_T("ValidateInputLanguage: Invalid input language\r\n")));
}
return fRet;
}
//----------------------------------------------------------------------------
//
// ValidateDeviceLayout
//
// Validates all data in a device layout.
//
// Return value:
//
// TRUE if it is valid.
//
//----------------------------------------------------------------------------
static
BOOL
ValidateDeviceLayout(
const DEVICE_LAYOUT *pdl
)
{
BOOL fRet = FALSE;
DWORD dwIdx;
PREFAST_DEBUGCHK(pdl);
if (pdl->dwSize != sizeof(DEVICE_LAYOUT)) {
goto leave;
}
else if (pdl->pfnRemapKey && IsBadCodePtr((FARPROC)pdl->pfnRemapKey)) {
goto leave;
}
else if (pdl->rgpscvk == NULL) {
goto leave;
}
for (dwIdx = 0; dwIdx < pdl->cpscvk; ++dwIdx) {
const ScanCodeToVKeyData *pScToVkData = pdl->rgpscvk[dwIdx];
if (pScToVkData->uMax < pScToVkData->uMin) {
goto leave;
}
}
fRet = TRUE;
leave:
return fRet;
}
//----------------------------------------------------------------------------
//
// ScanCodeToVKey
//
// Map a scan code to virtual key(s).
//
// Return value:
//
// Whether the is a key mapping. If there is not key mapping, *puiVKey will
// be 0, as well.
//
//----------------------------------------------------------------------------
static
BOOL
ScanCodeToVKey(
UINT32 uiScanCode,
ScanCodeToVKeyData **rgpscvk,
UINT cpscvk,
UINT32 *puiVKey
)
{
SETFNAME(_T("ScanCodeToVKey"));
PREFAST_DEBUGCHK(rgpscvk != NULL);
PREFAST_DEBUGCHK(puiVKey != NULL);
DEBUGCHK(IsLocked());
BOOL fRet = FALSE;
*puiVKey = 0;
ScanCodeToVKeyData *pscvk = NULL;
// Determine which table to look in
for (UINT uiTable = 0; uiTable < cpscvk; ++uiTable)
{
ScanCodeToVKeyData *pscvkCurr = rgpscvk[uiTable];
PREFAST_DEBUGCHK(pscvkCurr != NULL);
DEBUGCHK(pscvkCurr->uMin <= pscvkCurr->uMax);
DEBUGCHK(pscvkCurr->puScanCodeToVKey != NULL);
UINT32 uPrefixMask = pscvkCurr->uPrefixMask;
if (((uiScanCode & uPrefixMask) == uPrefixMask) &&
(uiScanCode >= pscvkCurr->uMin) && (uiScanCode <= pscvkCurr->uMax))
{
pscvk = pscvkCurr;
break;
}
}
// If this scan code falls in a table range, determine its virtual key
if (pscvk != NULL)
{
DEBUGCHK(uiScanCode >= pscvk->uMin);
DEBUGCHK(uiScanCode <= pscvk->uMax);
// Get the normalized index
UINT idxScan = uiScanCode - pscvk->uMin;
*puiVKey = pscvk->puScanCodeToVKey[idxScan];
if (*puiVKey != 0) { // 0 is an invalid virtual key
fRet = TRUE;
}
}
return fRet;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -