📄 keybdmdd.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.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
@doc EXTERNAL DRIVERS
@module keybdmdd.cpp |
This file implements the platform independent code of the keyboard driver.
This is provided as a sample to platform driver writers and is expected to
be able to be used without major modification on most hardware platforms.
*/
#include <windows.h>
#include <memory.h>
#include <nkintr.h>
#include <keybddr.h>
#include <keybdpdd.h>
#ifdef DEBUG
DBGPARAM dpCurSettings = { TEXT("Keybd"), {
TEXT("Init"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"),
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"),
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"),
TEXT("Undefined"), TEXT("Undefined"), TEXT("Warning"), TEXT("Error") },
0x00000000 };
#define ZONE_INIT DEBUGZONE(0)
#define ZONE_WARN DEBUGZONE(14)
#define ZONE_ERROR DEBUGZONE(15)
#endif
#define C_VIRTUAL_KEYS 256
#define MAX_TO_UNICODE_CHARACTERS 1
#define VK_0 0x30
#define VK_9 0x39
// Auto repeat #defines and state variables.
#define AR_WAIT_FOR_ANY 0
#define AR_INITIAL_DELAY 1
#define AR_AUTOREPEATING 2
#define AUTO_REPEAT_INITIAL_DELAY_MIN 250
#define AUTO_REPEAT_INITIAL_DELAY_MAX 1000
#define AUTO_REPEAT_INITIAL_DELAY_DEFAULT 500
#define AUTO_REPEAT_KEYS_PER_SEC_MIN 2
#define AUTO_REPEAT_KEYS_PER_SEC_MAX 30
#define AUTO_REPEAT_KEYS_PER_SEC_DEFAULT 20
static int v_AutoRepeatState = AR_WAIT_FOR_ANY;
static DWORD v_AutoRepeatInitialDelay = AUTO_REPEAT_INITIAL_DELAY_DEFAULT;
static DWORD v_AutoRepeatKeysPerSec = AUTO_REPEAT_KEYS_PER_SEC_DEFAULT;
static UINT32 v_AutoRepeatVKey;
static KEY_STATE_FLAGS v_AutoRepeatFlags;
// Routine to call back in to user when there is a keyboard event.
static PFN_KEYBD_EVENT_CALLBACK v_pfnKeybdEventCallback;
// The real state of the certain keys.
static BOOL v_fLShiftDown;
static BOOL v_fRShiftDown;
static BOOL v_fLAltDown;
static BOOL v_fRAltDown;
static BOOL v_fLCtrlDown;
static BOOL v_fRCtrlDown;
// Use a pseudo Alt key since we simulate that the Alt key goes up and down.
static BOOL v_fLPseudoAltDown;
static BOOL v_fRPseudoAltDown;
static BOOL v_fLastKeyDownWasPseudoAlt;
// Keep track of the last vkey actually sent for keys which have multiple
// virtual keys.
static UINT32 v_LShiftVKeySent;
static UINT32 v_RShiftVKeySent;
static UINT32 v_PeriodVKeySent;
static UINT32 v_CommaVKeySent;
static UINT32 v_BackVKeySent;
static UINT32 v_RightVKeySent;
static UINT32 v_LeftVKeySent;
static UINT32 v_UpVKeySent;
static UINT32 v_DownVKeySent;
#define ANY_ALT_DOWN() (v_fLAltDown || v_fRAltDown)
#define ANY_CTRL_DOWN() (v_fLCtrlDown || v_fRCtrlDown)
#define ANY_SHIFT_DOWN() (v_fLShiftDown || v_fRShiftDown)
// @doc EXTERNAL DRIVERS
/* @struct TO_UNICODE_STATE |
State info needed by the driver to convert virtual keys to Unicode.
@xref
<tab><f KeybdDriverGetDeviceInfo><nl>
<tab><f KeybdDriverInitStates><nl>
<tab><f KeybdDriverVKeyToUnicode><nl>
@comm This struct would be used by the driver to maintain any state
information needed between key events in order to generate Unicode
characters from virtual keys.
@comm This structure is not visible outside of the driver. The driver
provides information on its size via the <f KeybdDriverGetDeviceInfo>
function. The input system allocates a buffer for the structure and
passes it in when it calls <f KeybdDriverVKeyToUnicode>.
@comm In the sample driver code, it appears for demo purposes only.
*/
struct TO_UNICODE_STATE
{
int KeybdSpecificVKeyToUnicodeStateHere; // @field Whatever is needed by a specific keyboard driver
};
extern "C"
// @doc EXTERNAL DRIVERS
/* @func
Gives information about the keyboard and driver.
@rdesc If the function succeeds the return value is TRUE, otherwise, it is
FALSE. Extended error information is available via the GetLastError
function.
@xref
<tab><c KBDI_VKEY_TO_UNICODE_INFO_ID><nl>
<tab><c KBDI_AUTOREPEAT_INFO_ID><nl>
<tab><c KBDI_AUTOREPEAT_SELECTIONS_INFO_ID>
@comm This function must be re-entrant since it is exposed by the input
system via the <f KeybdGetDeviceInfo> function and may be called by
multiple threads.
*/
BOOL KeybdDriverGetInfo(
INT iKeybdId, // @parm Id of the keyboard to get the information from.
INT iIndex, // @parm Id of info to retrieve.
LPVOID lpOutput // @parm Output buffer.
)
{
if ( lpOutput == NULL )
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
switch ( iIndex )
{
case KBDI_VKEY_TO_UNICODE_INFO_ID:
{
struct KBDI_VKEY_TO_UNICODE_INFO *pInfo =
(struct KBDI_VKEY_TO_UNICODE_INFO*)lpOutput;
pInfo -> cbToUnicodeState = sizeof(TO_UNICODE_STATE); //for demo purposes only
pInfo -> cMaxToUnicodeCharacters = MAX_TO_UNICODE_CHARACTERS;
}
break;
case KBDI_AUTOREPEAT_INFO_ID:
{
struct KBDI_AUTOREPEAT_INFO *pInfo =
(struct KBDI_AUTOREPEAT_INFO*)lpOutput;
pInfo -> CurrentInitialDelay = v_AutoRepeatInitialDelay;
pInfo -> CurrentRepeatRate = v_AutoRepeatKeysPerSec;
pInfo -> cInitialDelaysSelectable = -1;
pInfo -> cRepeatRatesSelectable = -1;
}
break;
case KBDI_AUTOREPEAT_SELECTIONS_INFO_ID:
{
INT32 *pInfo = (INT32*)lpOutput;
*(pInfo) = AUTO_REPEAT_INITIAL_DELAY_MIN; // Min initial delay
*(pInfo+1) = AUTO_REPEAT_INITIAL_DELAY_MAX; // Max initial delay
*(pInfo+2) = AUTO_REPEAT_KEYS_PER_SEC_MIN; // Min repeat rate
*(pInfo+3) = AUTO_REPEAT_KEYS_PER_SEC_MAX; // Max repeat rate
}
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return TRUE;
}
#ifdef DEBUG
PFN_KEYBD_DRIVER_GET_INFO v_pfnGetInfoTest = KeybdDriverGetInfo;
#endif
extern "C"
// @doc EXTERNAL DRIVERS
/* @func
Initializes the virtual key state and driver specific state.
@xref
<tab><t KEY_STATE><nl>
<tab><t TO_UNICODE_STATE><nl>
<tab><f KeybdDriverGetInfo><nl>
<tab><c KBDI_VKEY_TO_UNICODE_INFO_ID><nl>
<tab><t KBDI_VKEY_TO_UNICODE_INFO><nl>
@comm After calling <f KeybdDriverGetInfo> and allocating its required
memory, the input system calls this function to allow the driver to
initialize the memory.
@comm The pKeybdDriverToUnicodeState is a pointer to a piece of memory of
at least cbToUnicodeState bytes as reported by the <f KeybdDriverGetInfo>
function in the <t KBDI_VKEY_TO_UNICODE_INFO> structure. If
cbToUnicodeState was reported as 0, this parameter may be NULL.
@comm This function must be re-entrant since it is exposed by the input
system via the <f KeybdInitStates> function and may be called by multiple
threads.
*/
BOOL KeybdDriverInitStates(
INT iKeybdId, // @parm Id of the keyboard to initialize keystate data for.
KEY_STATE KeyState, // @parm Key state to initialize.
void *pKeybdDeviceToUnicodeState // @parm Keyboard specific state to initialize.
)
{
TO_UNICODE_STATE *pDemoState = (TO_UNICODE_STATE*)pKeybdDeviceToUnicodeState;
int i;
// We have some demo state, so check for it. If we had no state,
// this parameter could be NULL with no error.
if ( pDemoState == NULL )
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
for ( i = 0; i < COUNT_VKEYS; i++ )
{
KeyState[i] = 0;
}
return TRUE;
}
#ifdef DEBUG
PFN_KEYBD_DRIVER_INIT_STATES v_pfnInitStatesTest = KeybdDriverInitStates;
#endif
/*++
MapLRVKeys:
Map left and right virtual keys to their common vkey.
Return Value:
The common vkey.
--*/
UINT32
MapLRVKeys(
UINT32 vkey
)
{
if ( ( vkey == VK_LCONTROL ) ||
( vkey == VK_RCONTROL ) )
return VK_CONTROL;
if ( ( vkey == VK_LMENU ) ||
( vkey == VK_RMENU ) )
return VK_MENU;
if ( ( vkey == VK_LSHIFT ) ||
( vkey == VK_RSHIFT ) )
return VK_SHIFT;
// VK_LWIN and VK_RWIN do not have a merged key.
return vkey;
}
/*++
NewKeyStateFlags:
Figure out the new key state flags based on the current state and the
event.
Return Value:
The new flag settings.
--*/
UINT32
NewKeyStateFlags(
KEY_STATE_FLAGS CurrentState,
KEY_STATE_FLAGS KeyEventFlags
)
{
// Just interested in down/up flag.
KeyEventFlags &= KeyStateDownFlag;
// First update the key state for the specific key.
// Remember the previous state.
if ( KeyStateIsDown(CurrentState) )
CurrentState |= KeyStatePrevDownFlag;
else
CurrentState &= ~KeyStatePrevDownFlag;
// Set the new state.
if ( KeyEventFlags )
CurrentState |= KeyStateDownFlag | KeyStateGetAsyncDownFlag;
else
CurrentState &= ~KeyStateDownFlag;
// Toggle flag only changes on down transition, not auto repeat.
if ( KeyStateIsDownTransition(CurrentState) )
CurrentState ^= KeyStateToggledFlag;
return CurrentState;
}
/*++
KeybdDriverKeyStateToShiftFlags:
Collapse the shift state from a given key state array into a single
element.
Notes:
For the given virtual key, the current flags from the key state array are
put into the low bits of the output flags.
--*/
void KeybdDriverKeyStateToShiftFlags(
KEY_STATE KeyState, // Key state array.
UINT32 VKey, // Virtual key.
KEY_STATE_FLAGS *pShiftStateFlags // Location to put collapsed shift state.
)
{
KEY_STATE_FLAGS ShiftFlags = 0;
// Add the standard keys.
if ( KeyStateIsDown(KeyState[VK_CONTROL]) )
{
ShiftFlags |= KeyShiftAnyCtrlFlag;
}
if ( KeyStateIsDown(KeyState[VK_LCONTROL]) )
{
ShiftFlags |= KeyShiftLeftCtrlFlag;
}
if ( KeyStateIsDown(KeyState[VK_RCONTROL]) )
{
ShiftFlags |= KeyShiftRightCtrlFlag;
}
if ( KeyStateIsDown(KeyState[VK_SHIFT]) )
{
ShiftFlags |= KeyShiftAnyShiftFlag;
}
if ( KeyStateIsDown(KeyState[VK_LSHIFT]) )
{
ShiftFlags |= KeyShiftLeftShiftFlag;
}
if ( KeyStateIsDown(KeyState[VK_RSHIFT]) )
{
ShiftFlags |= KeyShiftRightShiftFlag;
}
if ( KeyStateIsDown(KeyState[VK_MENU]) )
{
ShiftFlags |= KeyShiftAnyAltFlag;
}
if ( KeyStateIsDown(KeyState[VK_LMENU]) )
{
ShiftFlags |= KeyShiftLeftAltFlag;
}
if ( KeyStateIsDown(KeyState[VK_RMENU]) )
{
ShiftFlags |= KeyShiftRightAltFlag;
}
if ( KeyStateIsDown(KeyState[VK_LWIN]) )
{
ShiftFlags |= KeyShiftLeftWinFlag;
}
if ( KeyStateIsDown(KeyState[VK_RWIN]) )
{
ShiftFlags |= KeyShiftRightWinFlag;
}
if ( KeyStateIsToggled(KeyState[VK_CAPITAL]) )
ShiftFlags |= KeyShiftCapitalFlag;
// Set the low order bits to reflect the current key.
*pShiftStateFlags = ShiftFlags | KeyState[VKey];
return;
}
/*
The following defines will be used for converting the key pressed
into a Unicode character using the context information (the state
of other keys). We are assuming here that the count of bytes required
for state info for Unicode character generation (cbToUnicodeState
field in KEYBD_DRIVER_INFO structure) is zero, ie the driver does
not maintain any state information (besides CAPS, SHIFT, ALT and
CONTROL state) for Unicode character generation.
The Unicode character generated depends on the key pressed and
the state of the following keys: CAPS, SHIFT, ALT and CONTROL. Hence
for every Virtual key generated by the PDD, there can be a total of
16 different Unicode Characters in the worst case. Since there are
a total of 256 different virtual keys possible, storing all possible
states would require a lot of memory. Hence rows which are together
have been grouped and columns which have the same corresponding values
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -