📄 kbdhid.cpp
字号:
UNREFERENCED_PARAMETER(wParam);
if (VALID_HID_KBD(pHidKbd) == FALSE) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Received invalid structure pointer\r\n"), pszFname));
goto EXIT;
}
ValidateHidKbd(pHidKbd);
switch(dwMsg) {
case HID_CLOSE_DEVICE:
// Free all of our resources.
WaitForSingleObject(pHidKbd->hThread, INFINITE);
CloseHandle(pHidKbd->hThread);
pHidKbd->hThread = NULL;
// Key up all keys that are still down.
SendKeyboardUsages(pHidKbd, pHidKbd->puapPrevUsages, pHidKbd->dwMaxUsages,
HidP_Keyboard_Break, &pHidKbd->KeyStateFlags);
DeactivateDevice(pHidKbd->hOSDevice);
FreeHidKbd(pHidKbd);
fRet = TRUE;
break;
default:
DEBUGMSG(ZONE_ERROR, (_T("%s: Unhandled message %u\r\n"), pszFname));
break;
};
EXIT:
return fRet;
}
#ifdef DEBUG
// Match function with typedef.
static LPHID_CLIENT_NOTIFICATIONS g_pfnDeviceNotifications = HIDDeviceNotifications;
#endif
// Flashes the keyboard's LEDs.
static
BOOL
FlashLEDs(
PHID_KBD pHidKbd
)
{
SETFNAME(_T("FlashLEDs"));
DEBUGCHK(pHidKbd != NULL);
// Turn on all LEDs.
SetLEDs(pHidKbd, ~0);
// Turn off all LEDs.
SetLEDs(pHidKbd, 0);
return TRUE;
}
// Allocate the usage lists for this keyboard. The lists are allocated in
// a single block and then divided up.
static
BOOL
AllocateUsageLists(
PHID_KBD pHidKbd,
size_t cbUsages
)
{
SETFNAME(_T("AllocateUsageLists"));
BOOL fRet = FALSE;
size_t cbTotal;
PBYTE pbStart;
DWORD dwIdx;
PUSAGE_AND_PAGE *rgppUsageAndPage[] = {
&pHidKbd->puapPrevUsages,
&pHidKbd->puapCurrUsages,
&pHidKbd->puapBreakUsages,
&pHidKbd->puapMakeUsages,
&pHidKbd->puapOldMakeUsages
};
DEBUGCHK(pHidKbd != NULL);
DEBUGCHK(cbUsages > 0);
// Allocate a block of memory for all the usage lists
cbTotal = cbUsages * dim(rgppUsageAndPage);
pbStart = (PBYTE) LocalAlloc(LPTR, cbTotal);
if (pbStart == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("%s: LocalAlloc error:%d\r\n"), pszFname, GetLastError()));
goto EXIT;
}
// Divide the block.
for (dwIdx = 0; dwIdx < dim(rgppUsageAndPage); ++dwIdx) {
*rgppUsageAndPage[dwIdx] = (PUSAGE_AND_PAGE) (pbStart + (cbUsages * dwIdx));
}
fRet = TRUE;
EXIT:
return fRet;
}
// Free the memory used by pHidKbd
void
FreeHidKbd(
PHID_KBD pHidKbd
)
{
DEBUGCHK(pHidKbd != NULL);
// Close thread if it has been created.
if (pHidKbd->hThread != NULL) {
DEBUGCHK(pHidKbd->hevClosing != NULL);
SetEvent(pHidKbd->hevClosing);
WaitForSingleObject(pHidKbd->hThread, INFINITE);
CloseHandle(pHidKbd->hThread);
}
if (pHidKbd->hevClosing != NULL) CloseHandle(pHidKbd->hevClosing);
if (pHidKbd->puapPrevUsages != NULL) LocalFree(pHidKbd->puapPrevUsages);
if (pHidKbd->pbOutputBuffer != NULL) LocalFree(pHidKbd->pbOutputBuffer);
LocalFree(pHidKbd);
}
// Determine what usages have been set/unset and send the key events off to
// the system.
//
// On entry, pHidKbd->puapPrevUsages contains the previous usage list and
// pHidKbd->puapMakeUsages contains the most recent set of usages that
// went down (usually a single usage).
static
void
ProcessKeyboardReport(
PHID_KBD pHidKbd,
PCHAR pbHidPacket,
DWORD cbHidPacket
)
{
SETFNAME(_T("ProcessKeyboardReport"));
BOOL fRollover = FALSE;
ULONG uCurrUsages;
DWORD dwUsageIdx;
DWORD cbUsageList;
DWORD cKeysSent;
NTSTATUS status;
DEBUGCHK(pHidKbd != NULL);
DEBUGCHK(pbHidPacket != NULL);
uCurrUsages = pHidKbd->dwMaxUsages;
cbUsageList = uCurrUsages * sizeof(USAGE_AND_PAGE);
RETAILMSG(1,(TEXT("ProcessKeyboardReport: pbHidPacket: %08x, cbHidPacket: %d, %02x %02x %02x %02x %02x %02x %02x %02x.\r\n"),
pbHidPacket, cbHidPacket, pbHidPacket[0], pbHidPacket[1], pbHidPacket[2], pbHidPacket[3], pbHidPacket[4], pbHidPacket[5], pbHidPacket[6], pbHidPacket[7] ));
status = HidP_GetUsagesEx(
HidP_Input,
0,
pHidKbd->puapCurrUsages,
&uCurrUsages, // IN OUT parameter
pHidKbd->phidpPreparsedData,
pbHidPacket,
cbHidPacket
);
DEBUGCHK(NT_SUCCESS(status));
DEBUGCHK(uCurrUsages <= pHidKbd->dwMaxUsages);
// Check usages returned for keyboard rollover.
for (dwUsageIdx = 0; dwUsageIdx < uCurrUsages; ++dwUsageIdx)
{
PUSAGE_AND_PAGE puapCurr = &pHidKbd->puapCurrUsages[dwUsageIdx];
if (puapCurr->UsagePage == HID_USAGE_PAGE_KEYBOARD)
{
if (puapCurr->Usage == HID_USAGE_KEYBOARD_ROLLOVER) {
DEBUGMSG(ZONE_WARNING, (_T("%s: HID keyboard rollover\r\n"), pszFname));
fRollover = TRUE;
}
// At this point either we got the rollover usage or there will
// not be one. Break either way.
break;
}
}
if (fRollover == FALSE)
{
// Save our most recent down list.
memcpy(pHidKbd->puapOldMakeUsages, pHidKbd->puapMakeUsages, cbUsageList);
// Determine what keys went down and up.
status = HidP_UsageAndPageListDifference(
pHidKbd->puapPrevUsages,
pHidKbd->puapCurrUsages,
pHidKbd->puapBreakUsages,
pHidKbd->puapMakeUsages,
pHidKbd->dwMaxUsages
);
DEBUGCHK(NT_SUCCESS(status));
if (HidP_IsSameUsageAndPage(pHidKbd->puapMakeUsages[0], g_uapZero) &&
HidP_IsSameUsageAndPage(pHidKbd->puapBreakUsages[0], g_uapZero))
{
// No new keys
DEBUGMSG(ZONE_USAGES, (_T("%s: No new keys. Hardware autorepeat?\r\n"), pszFname));
// Replace the list of recent downs.
memcpy(pHidKbd->puapMakeUsages, pHidKbd->puapOldMakeUsages, cbUsageList);
}
else
{
// Move the current usages to the previous usage list.
memcpy(pHidKbd->puapPrevUsages, pHidKbd->puapCurrUsages, cbUsageList);
// Convert the key ups into scan codes and send them
cKeysSent = SendKeyboardUsages(pHidKbd, pHidKbd->puapBreakUsages, pHidKbd->dwMaxUsages,
HidP_Keyboard_Break, &pHidKbd->KeyStateFlags);
// If there were ups, then turn off repeat.
if (cKeysSent > 0) {
pHidKbd->ARState = AR_WAIT_FOR_ANY;
}
if (HidP_IsSameUsageAndPage(pHidKbd->puapCurrUsages[0], g_uapZero) == FALSE &&
HidP_IsSameUsageAndPage(pHidKbd->puapMakeUsages[0], g_uapZero) == TRUE)
{
// There are not any new downs, but there may be some old ones
// that are repeating in hardware. We'll update our make usages
// to include any keys that have not come up.
status = HidP_UsageAndPageListDifference(
pHidKbd->puapBreakUsages,
pHidKbd->puapOldMakeUsages,
pHidKbd->puapCurrUsages, // We can scrap the current usages now
pHidKbd->puapMakeUsages,
pHidKbd->dwMaxUsages
);
DEBUGCHK(NT_SUCCESS(status));
}
else {
// Convert the key downs to scan codes and send them
cKeysSent = SendKeyboardUsages(pHidKbd, pHidKbd->puapMakeUsages, pHidKbd->dwMaxUsages,
HidP_Keyboard_Make, &pHidKbd->KeyStateFlags);
// If there were downs, then set for repeat.
if (cKeysSent > 0) {
pHidKbd->ARState = AR_INITIAL_DELAY;
}
}
}
}
}
// Converts the usages to virtual keys and sends them off.
// Returns the number of usages converted.
static
DWORD
SendKeyboardUsages(
PHID_KBD pHidKbd,
PUSAGE_AND_PAGE puapUsages,
DWORD dwMaxUsages,
HIDP_KEYBOARD_DIRECTION hidpKeyEvent,
KEY_STATE_FLAGS *pKeyStateFlags
)
{
SETFNAME(_T("SendKeyboardUsages"));
DWORD dwIdx;
DEBUGCHK(puapUsages != NULL);
DEBUGCHK(pKeyStateFlags != NULL);
for (dwIdx = 0; dwIdx < dwMaxUsages; ++dwIdx) {
// Determine virtual key mapping
PUSAGE_AND_PAGE puapCurr = &puapUsages[dwIdx];
PFN_PROCESSING_TYPE pfnProcessingType;
ProcessingType PT;
UINT8 uiFlags;
DWORD dwFlags = 0;
UINT uiSc = 0;
UINT uiVk;
if (puapCurr->Usage == 0) {
// No more usages
break;
}
// Convert the usage to a scan code with flags.
switch (puapCurr->UsagePage)
{
case HID_USAGE_PAGE_KEYBOARD:
{
const USAGE_TO_SCANCODE *pUsageToSc = FindUsageToSc(puapCurr->Usage);
if( pUsageToSc )
{
RETAILMSG(1,(TEXT("SendKbdUsg: U: %08x, Sc: %08x, Fl: %08x.\r\n"), puapCurr->Usage, pUsageToSc->uiSc, pUsageToSc->uiFlags ));
}
else
{
RETAILMSG(1,(TEXT("SendKbdsg: U: %08x has no scancode mapping.\r\n")));
}
if ( (pUsageToSc != NULL) && (pUsageToSc->uiSc != 0) ) {
uiFlags = pUsageToSc->uiFlags;
uiSc = pUsageToSc->uiSc;
}
break;
}
case HID_USAGE_PAGE_CONSUMER:
{
// Note that most consumer keys will be handled in the 0xC 0x1
// HID client.
DWORD dwAssn;
for (dwAssn = 0; dwAssn < dim(g_rgConsumerToScAssn); ++dwAssn) {
if (g_rgConsumerToScAssn[dwAssn].usage == puapCurr->Usage) {
uiSc = g_rgConsumerToScAssn[dwAssn].uiSc;
uiFlags = MAKE_FLAGS(EB_NONE, PT_STANDARD);
break;
}
}
break;
}
};
// Was there a conversion? If so, send the event.
if (uiSc != 0)
{
DEBUGMSG(ZONE_USAGES, (_T("%s: Usage Page: 0x%04x Usage: 0x%04x -> SC: 0x%06x\r\n"),
pszFname, puapCurr->UsagePage, puapCurr->Usage, uiSc));
if (hidpKeyEvent == HidP_Keyboard_Break) {
dwFlags |= KEYEVENTF_KEYUP;
}
// Prepend extended bits
switch (GET_EB(uiFlags)) {
case EB_E0:
uiSc |= 0xE000;
dwFlags |= KEYEVENTF_EXTENDEDKEY;
break;
case EB_E114:
uiSc |= 0xE11400;
break;
};
// Convert scan code to virtual key
DEBUGCHK(IsAPIReady(SH_WMGR) == TRUE); // Exception if FALSE
// used to use MapVirtualKey. This way, the VK's are looked up directly
if( uiSc <= ScanCodeTableLast )
{
uiVk = ScanCodeToVKeyTable[uiSc];
RETAILMSG(1,(TEXT("SendKbdUsg: Map: %d, Sc: %08x, Vk: %08x.\r\n"), 0, uiSc, uiVk ));
}
else
if( ( uiSc <= E0ScanCodeTableLast ) && ( uiSc >= E0ScanCodeTableFirst ) )
{
uiVk = E0ScanCodeToVKeyTable[uiSc - E0ScanCodeTableFirst];
RETAILMSG(1,(TEXT("SendKbdUsg: Map: %d, Sc: %08x, Vk: %08x.\r\n"), 0, uiSc, uiVk ));
}
else
{
RETAILMSG(1,(TEXT("SendKbdUsg: no VKeyTable entry for %08x.\r\n"), uiSc ));
}
// look for a numlock on key make events
if( hidpKeyEvent == HidP_Keyboard_Make )
{
if( uiVk == VK_NUMLOCK )
{
// need to toggle the numlock state
if (IS_NUMLOCK_ENABLED() == FALSE)
{
*pKeyStateFlags |= KeyShiftNumLockFlag;
RETAILMSG(1,(TEXT("SendKbdUsb: Setting numlock flag. Result: %08x.\r\n"), *pKeyStateFlags ));
}
else
{
*pKeyStateFlags &= ~KeyShiftNumLockFlag;
RETAILMSG(1,(TEXT("SendKbdUsb: Clearing numlock flag. Result: %08x.\r\n"), *pKeyStateFlags ));
}
SetLEDs( pHidKbd, *pKeyStateFlags );
}
}
// look for a caps lock on key make events
if( hidpKeyEvent == HidP_Keyboard_Make )
{
if( uiVk == VK_CAPITAL )
{
// need to toggle the numlock state
if (IS_CAPSLOCK_ENABLED() == FALSE)
{
*pKeyStateFlags |= KeyShiftCapitalFlag;
RETAILMSG(1,(TEXT("SendKbdUsb: Setting capslock flag. Result: %08x.\r\n"), *pKeyStateFlags ));
}
else
{
*pKeyStateFlags &= ~KeyShiftCapitalFlag;
RETAILMSG(1,(TEXT("SendKbdUsb: Clearing capslock flag. Result: %08x.\r\n"), *pKeyStateFlags ));
}
SetLEDs( pHidKbd, *pKeyStateFlags );
}
}
// look for a scroll lock on key make events
if( hidpKeyEvent == HidP_Keyboard_Make )
{
if( uiVk == VK_SCROLL )
{
// need to toggle the numlock state
if (IS_SCROLLLOCK_ENABLED() == FALSE)
{
*pKeyStateFlags |= KeyShiftScrollLockFlag;
RETAILMSG(1,(TEXT("SendKbdUsb: Setting scrolllock flag. Result: %08x.\r\n"), *pKeyStateFlags ));
}
else
{
*pKeyStateFlags &= ~KeyShiftScrollLockFlag;
RETAILMSG(1,(TEXT("SendKbdUsb: Clearing scrolllock flag. Result: %08x.\r\n"), *pKeyStateFlags ));
}
SetLEDs( pHidKbd, *pKeyStateFlags );
}
}
// Determine which processing function to call
PT = GET_PT(uiFlags);
RETAILMSG(1,(TEXT("SendKbdUsg: key category is %d.\r\n"), PT ));
DEBUGCHK(dim(g_rgpfnProcessingType) == PT_COUNT);
DEBUGCHK(PT < PT_COUNT);
pfnProcessingType = g_rgpfnProcessingType[PT];
DEBUGCHK(pfnProcessingType != NULL);
// Call the processing function to send off the event
(*pfnProcessingType)(uiVk, uiSc, dwFlags, hidpKeyEvent, pKeyStateFlags);
}
else {
DEBUGMSG(ZONE_WARNING, (_T("%s: No scan code for Usage Page: 0x%04x Usage: 0x%04x\r\n"),
pszFname, puapCurr->UsagePage, puapCurr->Usage));
}
}
return dwIdx;
}
// Send the keyboard event to GWES.
static
void
KeyboardEvent(
UINT vk,
UINT sc,
DWORD dwFlags
)
{
SETFNAME(_T("KeyboardEvent"));
UINT8 uiVk = (UINT8) vk;
UINT8 uiSc = (UINT8) sc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -