/*++ Copyright (c) 2000 Microsoft Corporation Module Name: kbd.cpp Abstract: High-level Xbox keyboard support Environment: Designed for XBOX. Notes: Revision History: 12-20-00 created by Mitchell Dernis (mitchd) --*/ // // Pull in OS headers // #define _XAPI_ extern "C" { #include } #include #include #include //Nothing in here matters, if we don't have keyboard support enabled. #include // // Setup the debug information for this file (see ..\inc\debug.h) // #define MODULE_POOL_TAG '_DBK' #include DEFINE_USB_DEBUG_FUNCTIONS("KBD"); // // Pull in public usb headers // #include // // Pull in xid headers // #include "xid.h" #include #pragma data_seg(".XBLD$V") #if DBG USHORT XKbdBuildNumberD[8] = { 'KX', 'DB', 'D', 0, VER_PRODUCTVERSION | 0x8000 #else USHORT XKbdBuildNumber[8] = { 'KX', 'DB', 0, 0, VER_PRODUCTVERSION #endif }; #pragma data_seg(".XPP$Data") //-------------------------------------------------------------------- // Local Structure Definitions //-------------------------------------------------------------------- typedef struct _XID_KEYBOARD_INSTANCE { HANDLE hDevice; XINPUT_KEYBOARD LastPacket; XINPUT_KEYBOARD_LEDS KeyboardLeds; XINPUT_DEBUG_KEYSTROKE *KeyQueue; ULONG QueueReadPos; ULONG QueueWritePos; XINPUT_DEBUG_KEYSTROKE RepeatKeystroke; DWORD LastRepeatTick; } XID_KEYBOARD_INSTANCE, *PXID_KEYBOARD_INSTANCE; typedef struct _XID_KEYBOARD_STATE { #ifdef SINGLE_KEYBOARD_ONLY XID_KEYBOARD_INSTANCE Keyboards[1]; #else XID_KEYBOARD_INSTANCE Keyboards[5]; #endif XINPUT_DEBUG_KEYQUEUE_PARAMETERS QueueParameters; } XID_KEYBOARD_STATE, *PXID_KEYBOARD_STATE; XID_KEYBOARD_STATE XID_KeyboardState = {0}; //-------------------------------------------------------------------- // Keyboard Services Service Table for XID //-------------------------------------------------------------------- void XID_KeyboardOpen(HANDLE hDevice); void XID_KeyboardClose(HANDLE hDevice); void XID_KeyboardRemove(HANDLE hDevice); void XID_KeyboardNewData(HANDLE hDevice, XINPUT_KEYBOARD *pPacket); XID_KEYBOARD_SERVICES XID_KeyboardServices = { XID_KeyboardOpen, XID_KeyboardClose, XID_KeyboardRemove, XID_KeyboardNewData }; //-------------------------------------------------------------------- // Local Utility Functions //-------------------------------------------------------------------- BOOL XID_KeyboardInitQueue(int iInstance, DWORD dwQueueLength); void XID_KeyboardReset(int iInstance); void XID_KeyboardUpdate(int iInstance, XINPUT_KEYBOARD *pPacket); XINPUT_DEBUG_KEYSTROKE *XID_KeyboardQueueGetWritePos(int iQueueIndex); XINPUT_DEBUG_KEYSTROKE *XID_KeyboardQueueIncrementWritePos(int iQueueIndex); VOID XID_KeyboardQueueHidKeystroke(UCHAR HidUsage, UCHAR Flags, PXINPUT_DEBUG_KEYSTROKE pKeystroke); /*-------------------------------------------------------------------- * HID to VK_ convertion table. *---------------------------------------------- * HID_USAGE_INDEX_KEYBOARD_NOEVENT to * HID_USAGE_INDEX_KEYBOARD_UNDEFINED are not * real keys, but so don't need convertion. *---------------------------------------------- * HID_USAGE_INDEX_KEYBOARD_aA to * HID_USAGE_INDEX_KEYBOARD_zZ are * not converted by lookup but rather by * by adding (VK_A-HID_USAGE_INDEX_KEYBOARD_aA) * to the HID usage. * * NOTE: localization, may require a couple of * substitutions in this range. *---------------------------------------------- * HID_USAGE_INDEX_KEYBOARD_ONE to * HID_USAGE_INDEX_KEYBOARD_NINE are * not converted by lookeup but rather by * adding (VK_1-HID_USAGE_INDEX_KEYBOARD_ONE) * to the HID usage. * (0 is last in HID, first in ASCII, so * is just part of the lookup table) *---------------------------------------------- **/ UCHAR HidToVK_Table[] = { /*HID_USAGE_INDEX_KEYBOARD_ZERO*/ '0', /*HID_USAGE_INDEX_KEYBOARD_RETURN*/ VK_RETURN, /*HID_USAGE_INDEX_KEYBOARD_ESCAPE*/ VK_ESCAPE, /*HID_USAGE_INDEX_KEYBOARD_BACKSPACE*/ VK_BACK, /*HID_USAGE_INDEX_KEYBOARD_TAB*/ VK_TAB, /*HID_USAGE_INDEX_KEYBOARD_SPACEBAR*/ VK_SPACE, /*HID_USAGE_INDEX_KEYBOARD_MINUS*/ VK_OEM_MINUS, /*HID_USAGE_INDEX_KEYBOARD_EQUALS*/ VK_OEM_PLUS, /*HID_USAGE_INDEX_KEYBOARD_OPEN_BRACE*/ VK_OEM_4, /*HID_USAGE_INDEX_KEYBOARD_CLOSE_BRACE*/ VK_OEM_6, /*HID_USAGE_INDEX_KEYBOARD_BACKSLASH*/ VK_OEM_5, /*HID_USAGE_INDEX_KEYBOARD_NON_US_TILDE*/ VK_OEM_3, /*HID_USAGE_INDEX_KEYBOARD_COLON*/ VK_OEM_1, /*HID_USAGE_INDEX_KEYBOARD_QUOTE*/ VK_OEM_7, /*HID_USAGE_INDEX_KEYBOARD_TILDE*/ VK_OEM_3, /*HID_USAGE_INDEX_KEYBOARD_COMMA*/ VK_OEM_COMMA, /*HID_USAGE_INDEX_KEYBOARD_PERIOD*/ VK_OEM_PERIOD, /*HID_USAGE_INDEX_KEYBOARD_QUESTION*/ VK_OEM_2, /*HID_USAGE_INDEX_KEYBOARD_CAPS_LOCK*/ VK_CAPITAL, /*HID_USAGE_INDEX_KEYBOARD_F1*/ VK_F1, /*HID_USAGE_INDEX_KEYBOARD_F2*/ VK_F2, /*HID_USAGE_INDEX_KEYBOARD_F3*/ VK_F3, /*HID_USAGE_INDEX_KEYBOARD_F4*/ VK_F4, /*HID_USAGE_INDEX_KEYBOARD_F5*/ VK_F5, /*HID_USAGE_INDEX_KEYBOARD_F6*/ VK_F6, /*HID_USAGE_INDEX_KEYBOARD_F7*/ VK_F7, /*HID_USAGE_INDEX_KEYBOARD_F8*/ VK_F8, /*HID_USAGE_INDEX_KEYBOARD_F9*/ VK_F9, /*HID_USAGE_INDEX_KEYBOARD_F10*/ VK_F10, /*HID_USAGE_INDEX_KEYBOARD_F11*/ VK_F11, /*HID_USAGE_INDEX_KEYBOARD_F12*/ VK_F12, /*HID_USAGE_INDEX_KEYBOARD_PRINT_SCREEN*/ VK_PRINT, /*HID_USAGE_INDEX_KEYBOARD_SCROLL_LOCK*/ VK_SCROLL, /*HID_USAGE_INDEX_KEYBOARD_PAUSE*/ VK_PAUSE, /*HID_USAGE_INDEX_KEYBOARD_INSERT*/ VK_INSERT, /*HID_USAGE_INDEX_KEYBOARD_HOME*/ VK_HOME, /*HID_USAGE_INDEX_KEYBOARD_PAGE_UP*/ VK_PRIOR, /*HID_USAGE_INDEX_KEYBOARD_DELETE*/ VK_DELETE, /*HID_USAGE_INDEX_KEYBOARD_END*/ VK_END, /*HID_USAGE_INDEX_KEYBOARD_PAGE_DOWN*/ VK_NEXT, /*HID_USAGE_INDEX_KEYBOARD_RIGHT_ARROW*/ VK_RIGHT, /*HID_USAGE_INDEX_KEYBOARD_LEFT_ARROW*/ VK_LEFT, /*HID_USAGE_INDEX_KEYBOARD_DOWN_ARROW*/ VK_DOWN, /*HID_USAGE_INDEX_KEYBOARD_UP_ARROW*/ VK_UP, /*HID_USAGE_INDEX_KEYPAD_NUM_LOCK*/ VK_NUMLOCK, /*HID_USAGE_INDEX_KEYPAD_BACKSLASH*/ VK_DIVIDE, /*HID_USAGE_INDEX_KEYPAD_ASTERICK*/ VK_MULTIPLY, /*HID_USAGE_INDEX_KEYPAD_MINUS*/ VK_SUBTRACT, /*HID_USAGE_INDEX_KEYPAD_PLUS*/ VK_ADD, /*HID_USAGE_INDEX_KEYPAD_ENTER*/ VK_SEPARATOR, /*HID_USAGE_INDEX_KEYPAD_ONE*/ VK_NUMPAD1, /*HID_USAGE_INDEX_KEYPAD_TWO*/ VK_NUMPAD2, /*HID_USAGE_INDEX_KEYPAD_THREE*/ VK_NUMPAD3, /*HID_USAGE_INDEX_KEYPAD_FOUR*/ VK_NUMPAD4, /*HID_USAGE_INDEX_KEYPAD_FIVE*/ VK_NUMPAD5, /*HID_USAGE_INDEX_KEYPAD_SIX*/ VK_NUMPAD6, /*HID_USAGE_INDEX_KEYPAD_SEVEN*/ VK_NUMPAD7, /*HID_USAGE_INDEX_KEYPAD_EIGHT*/ VK_NUMPAD8, /*HID_USAGE_INDEX_KEYPAD_NINE*/ VK_NUMPAD9, /*HID_USAGE_INDEX_KEYPAD_ZERO*/ VK_NUMPAD0, /*HID_USAGE_INDEX_KEYPAD_DECIMAL*/ VK_DECIMAL, /*HID_USAGE_INDEX_KEYBOARD_NON_US_BACKSLASH*/ VK_OEM_5, /*HID_USAGE_INDEX_KEYBOARD_APPLICATION*/ VK_APPS, /*HID_USAGE_INDEX_KEYBOARD_POWER*/ VK_SLEEP, /*HID_USAGE_INDEX_KEYPAD_EQUALS*/ VK_OEM_NEC_EQUAL, /*HID_USAGE_INDEX_KEYBOARD_F13*/ VK_F13, /*HID_USAGE_INDEX_KEYBOARD_F14*/ VK_F14, /*HID_USAGE_INDEX_KEYBOARD_F15*/ VK_F15, /*HID_USAGE_INDEX_KEYBOARD_F16*/ VK_F16, /*HID_USAGE_INDEX_KEYBOARD_F17*/ VK_F17, /*HID_USAGE_INDEX_KEYBOARD_F18*/ VK_F18, /*HID_USAGE_INDEX_KEYBOARD_F19*/ VK_F19, /*HID_USAGE_INDEX_KEYBOARD_F20*/ VK_F20, /*HID_USAGE_INDEX_KEYBOARD_F21*/ VK_F21, /*HID_USAGE_INDEX_KEYBOARD_F22*/ VK_F22, /*HID_USAGE_INDEX_KEYBOARD_F23*/ VK_F23, /*HID_USAGE_INDEX_KEYBOARD_F24*/ VK_F24, /*HID_USAGE_INDEX_KEYBOARD_EXECUTE*/ VK_EXECUTE, /*HID_USAGE_INDEX_KEYBOARD_HELP*/ VK_HELP, /*HID_USAGE_INDEX_KEYBOARD_MENU*/ VK_MENU, /*HID_USAGE_INDEX_KEYBOARD_SELECT*/ VK_SELECT, /*HID_USAGE_INDEX_KEYBOARD_STOP*/ VK_BROWSER_STOP, /*HID_USAGE_INDEX_KEYBOARD_AGAIN*/ 0, /*HID_USAGE_INDEX_KEYBOARD_UNDO*/ 0, /*HID_USAGE_INDEX_KEYBOARD_CUT*/ 0, /*HID_USAGE_INDEX_KEYBOARD_COPY*/ 0, /*HID_USAGE_INDEX_KEYBOARD_PASTE*/ 0, /*HID_USAGE_INDEX_KEYBOARD_FIND*/ VK_BROWSER_SEARCH, /*HID_USAGE_INDEX_KEYBOARD_MUTE*/ VK_VOLUME_MUTE, /*HID_USAGE_INDEX_KEYBOARD_VOLUME_UP*/ VK_VOLUME_UP, /*HID_USAGE_INDEX_KEYBOARD_VOLUME_DOWN*/ VK_VOLUME_DOWN, /*HID_USAGE_INDEX_KEYBOARD_LOCKING_CAPS*/ 0, /*HID_USAGE_INDEX_KEYBOARD_LOCKING_NUM*/ 0, /*HID_USAGE_INDEX_KEYBOARD_LOCKING_SCROLL*/ 0, /*HID_USAGE_INDEX_KEYPAD_COMMA*/ VK_DECIMAL, //Brazillian keyboards have comma instead of period /*HID_USAGE_INDEX_KEYPAD_EQUALS_AS400*/ VK_OEM_NEC_EQUAL, /*HID_USAGE_INDEX_KEYBOARD_INTERNATIONAL1*/ 0, /*HID_USAGE_INDEX_KEYBOARD_INTERNALIONAL2*/ 0, /*HID_USAGE_INDEX_KEYBOARD_INTERNATIONAL3*/ 0, /*HID_USAGE_INDEX_KEYBOARD_INTERNATIONAL4*/ 0, /*HID_USAGE_INDEX_KEYBOARD_INTERNATIONAL5*/ 0, /*HID_USAGE_INDEX_KEYBOARD_INTERNATIONAL6*/ 0, /*HID_USAGE_INDEX_KEYBOARD_INTERNATIONAL7*/ 0, /*HID_USAGE_INDEX_KEYBOARD_INTERNATIONAL8*/ 0, /*HID_USAGE_INDEX_KEYBOARD_INTERNATIONAL9*/ 0, /*HID_USAGE_INDEX_KEYBOARD_LANG1*/ 0, /*HID_USAGE_INDEX_KEYBOARD_LANG2*/ VK_HANJA, /*HID_USAGE_INDEX_KEYBOARD_LANG3*/ VK_KANA, /*HID_USAGE_INDEX_KEYBOARD_LANG4*/ 0, /*HID_USAGE_INDEX_KEYBOARD_LANG5*/ 0, /*HID_USAGE_INDEX_KEYBOARD_LANG6*/ 0, /*HID_USAGE_INDEX_KEYBOARD_LANG7*/ 0, /*HID_USAGE_INDEX_KEYBOARD_LANG8*/ 0, /*HID_USAGE_INDEX_KEYBOARD_LANG9*/ 0 }; UCHAR HidModifierToVK_Table[] = { /*HID_USAGE_INDEX_KEYBOARD_LCTRL*/ VK_LCONTROL, /*HID_USAGE_INDEX_KEYBOARD_LSHFT*/ VK_LSHIFT, /*HID_USAGE_INDEX_KEYBOARD_LALT*/ VK_LMENU, /*HID_USAGE_INDEX_KEYBOARD_LGUI*/ VK_LWIN, /*HID_USAGE_INDEX_KEYBOARD_RCTRL*/ VK_RCONTROL, /*HID_USAGE_INDEX_KEYBOARD_RSHFT*/ VK_RSHIFT, /*HID_USAGE_INDEX_KEYBOARD_RALT*/ VK_RMENU, /*HID_USAGE_INDEX_KEYBOARD_RGUI*/ VK_RWIN }; UCHAR HidSymToAscii_Table[] = { /*HID_USAGE_INDEX_KEYBOARD_ZERO*/ '0', /*HID_USAGE_INDEX_KEYBOARD_RETURN*/ '\n', /*HID_USAGE_INDEX_KEYBOARD_ESCAPE*/ 27, /*HID_USAGE_INDEX_KEYBOARD_BACKSPACE*/ '\b', /*HID_USAGE_INDEX_KEYBOARD_TAB*/ '\t', /*HID_USAGE_INDEX_KEYBOARD_SPACEBAR*/ ' ', /*HID_USAGE_INDEX_KEYBOARD_MINUS*/ '-', /*HID_USAGE_INDEX_KEYBOARD_EQUALS*/ '=', /*HID_USAGE_INDEX_KEYBOARD_OPEN_BRACE*/ '[', /*HID_USAGE_INDEX_KEYBOARD_CLOSE_BRACE*/ ']', /*HID_USAGE_INDEX_KEYBOARD_BACKSLASH*/ '\\', /*HID_USAGE_INDEX_KEYBOARD_NON_US_TILDE*/ '~', /*HID_USAGE_INDEX_KEYBOARD_COLON*/ ';', /*HID_USAGE_INDEX_KEYBOARD_QUOTE*/ '\'', /*HID_USAGE_INDEX_KEYBOARD_TILDE*/ '`', /*HID_USAGE_INDEX_KEYBOARD_COMMA*/ ',', /*HID_USAGE_INDEX_KEYBOARD_PERIOD*/ '.', /*HID_USAGE_INDEX_KEYBOARD_QUESTION*/ '/' }; UCHAR HidSymToAsciiShift_Table[] = { /*HID_USAGE_INDEX_KEYBOARD_ONE*/ '!', /*HID_USAGE_INDEX_KEYBOARD_TWO*/ '@', /*HID_USAGE_INDEX_KEYBOARD_THREE*/ '#', /*HID_USAGE_INDEX_KEYBOARD_FOUR*/ '$', /*HID_USAGE_INDEX_KEYBOARD_FIVE*/ '%', /*HID_USAGE_INDEX_KEYBOARD_SIX*/ '^', /*HID_USAGE_INDEX_KEYBOARD_SEVEN*/ '&', /*HID_USAGE_INDEX_KEYBOARD_EIGHT*/ '*', /*HID_USAGE_INDEX_KEYBOARD_NINE*/ '(', /*HID_USAGE_INDEX_KEYBOARD_ZERO*/ ')', /*HID_USAGE_INDEX_KEYBOARD_RETURN*/ '\n', /*HID_USAGE_INDEX_KEYBOARD_ESCAPE*/ 27, /*HID_USAGE_INDEX_KEYBOARD_BACKSPACE*/ '\b', /*HID_USAGE_INDEX_KEYBOARD_TAB*/ '\t', /*HID_USAGE_INDEX_KEYBOARD_SPACEBAR*/ ' ', /*HID_USAGE_INDEX_KEYBOARD_MINUS*/ '_', /*HID_USAGE_INDEX_KEYBOARD_EQUALS*/ '+', /*HID_USAGE_INDEX_KEYBOARD_OPEN_BRACE*/ '{', /*HID_USAGE_INDEX_KEYBOARD_CLOSE_BRACE*/ '}', /*HID_USAGE_INDEX_KEYBOARD_BACKSLASH*/ '|', /*HID_USAGE_INDEX_KEYBOARD_NON_US_TILDE*/ '~', /*HID_USAGE_INDEX_KEYBOARD_COLON*/ ':', /*HID_USAGE_INDEX_KEYBOARD_QUOTE*/ '\"', /*HID_USAGE_INDEX_KEYBOARD_TILDE*/ '~', /*HID_USAGE_INDEX_KEYBOARD_COMMA*/ '<', /*HID_USAGE_INDEX_KEYBOARD_PERIOD*/ '>', /*HID_USAGE_INDEX_KEYBOARD_QUESTION*/ '?' }; UCHAR HidNumPadToAscii[] = { /*HID_USAGE_INDEX_KEYPAD_BACKSLASH*/ '/', /*HID_USAGE_INDEX_KEYPAD_ASTERICK*/ '*', /*HID_USAGE_INDEX_KEYPAD_MINUS*/ '-', /*HID_USAGE_INDEX_KEYPAD_PLUS*/ '+', /*HID_USAGE_INDEX_KEYPAD_ENTER*/ '\n', /*HID_USAGE_INDEX_KEYPAD_ONE*/ 0, /*HID_USAGE_INDEX_KEYPAD_TWO*/ 0, /*HID_USAGE_INDEX_KEYPAD_THREE*/ 0, /*HID_USAGE_INDEX_KEYPAD_FOUR*/ 0, /*HID_USAGE_INDEX_KEYPAD_FIVE*/ 0, /*HID_USAGE_INDEX_KEYPAD_SIX*/ 0, /*HID_USAGE_INDEX_KEYPAD_SEVEN*/ 0, /*HID_USAGE_INDEX_KEYPAD_EIGHT*/ 0, /*HID_USAGE_INDEX_KEYPAD_NINE*/ 0, /*HID_USAGE_INDEX_KEYPAD_ZERO*/ 0, /*HID_USAGE_INDEX_KEYPAD_DECIMAL*/ 127 }; UCHAR HidNumPadShiftToAscii[] = { /*HID_USAGE_INDEX_KEYPAD_BACKSLASH*/ '/', /*HID_USAGE_INDEX_KEYPAD_ASTERICK*/ '*', /*HID_USAGE_INDEX_KEYPAD_MINUS*/ '-', /*HID_USAGE_INDEX_KEYPAD_PLUS*/ '+', /*HID_USAGE_INDEX_KEYPAD_ENTER*/ '\n', /*HID_USAGE_INDEX_KEYPAD_ONE*/ '1', /*HID_USAGE_INDEX_KEYPAD_TWO*/ '2', /*HID_USAGE_INDEX_KEYPAD_THREE*/ '3', /*HID_USAGE_INDEX_KEYPAD_FOUR*/ '4', /*HID_USAGE_INDEX_KEYPAD_FIVE*/ '5', /*HID_USAGE_INDEX_KEYPAD_SIX*/ '6', /*HID_USAGE_INDEX_KEYPAD_SEVEN*/ '7', /*HID_USAGE_INDEX_KEYPAD_EIGHT*/ '8', /*HID_USAGE_INDEX_KEYPAD_NINE*/ '9', /*HID_USAGE_INDEX_KEYPAD_ZERO*/ '0', /*HID_USAGE_INDEX_KEYPAD_DECIMAL*/ '.' }; XBOXAPI DWORD WINAPI XInputDebugInitKeyboardQueue( IN PXINPUT_DEBUG_KEYQUEUE_PARAMETERS pParameters OPTIONAL ) { BOOL fSuccess = TRUE; // // Store the parameters // if(pParameters) { RtlCopyMemory(&XID_KeyboardState.QueueParameters, pParameters, sizeof(XINPUT_DEBUG_KEYQUEUE_PARAMETERS)); } else { XID_KeyboardState.QueueParameters.dwFlags = XINPUT_DEBUG_KEYQUEUE_FLAG_KEYDOWN | XINPUT_DEBUG_KEYQUEUE_FLAG_KEYREPEAT; XID_KeyboardState.QueueParameters.dwQueueSize = 40; XID_KeyboardState.QueueParameters.dwRepeatDelay = 400; XID_KeyboardState.QueueParameters.dwRepeatInterval = 100; } // // Allocate Queue(s) // DWORD dwQueueLength = XID_KeyboardState.QueueParameters.dwQueueSize * sizeof(XINPUT_DEBUG_KEYSTROKE); #ifdef SINGLE_KEYBOARD_ONLY fSuccess = XID_KeyboardInitQueue(0, dwQueueLength); #else if(XID_KeyboardState.QueueParameters.dwFlags & XINPUT_DEBUG_KEYQUEUE_FLAG_ONE_QUEUE) { fSuccess = XID_KeyboardInitQueue(0, dwQueueLength); } else { int i; for(i=0; i<4;i++) { fSuccess = XID_KeyboardInitQueue(i,dwQueueLength); if(!fSuccess) { while(--i >= 0) { ExFreePool(XID_KeyboardState.Keyboards[i].KeyQueue); XID_KeyboardState.Keyboards[i].KeyQueue = NULL; } return ERROR_OUTOFMEMORY; } } } #endif if(fSuccess) { // // Setup the Hook // XID_pKeyboardServices = &XID_KeyboardServices; return ERROR_SUCCESS; } return ERROR_OUTOFMEMORY; } XBOXAPI DWORD WINAPI XInputDebugGetKeystroke( #ifndef SINGLE_KEYBOARD_ONLY IN HANDLE hDevice, #endif // SINGLE_KEYBOARD_ONLY OUT PXINPUT_DEBUG_KEYSTROKE pKeystroke ) { #ifdef SINGLE_KEYBOARD_ONLY const int iQueueIndex=0; #else int iQueueIndex = 0; #endif DWORD dwError = ERROR_SUCCESS; DWORD dwReadPos; KIRQL oldIrql; DWORD dwTickCount = 0; oldIrql = KeRaiseIrqlToDpcLevel(); #ifndef SINGLE_KEYBOARD_ONLY if(hDevice == NULL) { if(!(XID_KeyboardState.QueueParameters.dwFlags&XINPUT_DEBUG_KEYQUEUE_FLAG_ONE_QUEUE)) { KeLowerIrql(oldIrql); RIP("XInputDebugGetKeystroke: hDevice may only be NULL, if XINPUT_DEBUG_KEYQUEUE_FLAG_ONE_QUEUE was set."); oldIrql = KeRaiseIrqlToDpcLevel(); } } else { for(iQueueIndex=0; iQueueIndex<4; iQueueIndex++) { if(hDevice == XID_KeyboardState.Keyboards[iQueueIndex].hDevice) { break; } } } if(4==iQueueIndex) { KeLowerIrql(oldIrql); RIP("XInputDebugGetKeystroke: hDevice is not valid."); return ERROR_INVALID_HANDLE; } #endif //SINGLE_KEYBOARD_ONLY dwTickCount = GetTickCount(); if(dwTickCount == 0) dwTickCount = 1; dwReadPos = XID_KeyboardState.Keyboards[iQueueIndex].QueueReadPos; if( dwReadPos == XID_KeyboardState.Keyboards[iQueueIndex].QueueWritePos) { // // Handle Repeat Count // DWORD dwTickCountDiff = dwTickCount - XID_KeyboardState.Keyboards[iQueueIndex].LastRepeatTick; if(dwTickCountDiff > 2000) dwTickCountDiff = 0; if( (XID_KeyboardState.QueueParameters.dwFlags&XINPUT_DEBUG_KEYQUEUE_FLAG_KEYREPEAT) && XID_KeyboardState.Keyboards[iQueueIndex].LastRepeatTick && (dwTickCountDiff > XID_KeyboardState.QueueParameters.dwRepeatInterval) ) { RtlCopyMemory( pKeystroke, &XID_KeyboardState.Keyboards[iQueueIndex].RepeatKeystroke, sizeof(XINPUT_DEBUG_KEYSTROKE) ); XID_KeyboardState.Keyboards[iQueueIndex].LastRepeatTick = dwTickCount; } else { dwError = ERROR_HANDLE_EOF; } goto ExitXInputGetKeyStroke; } RtlCopyMemory( pKeystroke, &XID_KeyboardState.Keyboards[iQueueIndex].KeyQueue[dwReadPos], sizeof(XINPUT_DEBUG_KEYSTROKE) ); if( (XID_KeyboardState.QueueParameters.dwFlags&XINPUT_DEBUG_KEYQUEUE_FLAG_KEYREPEAT)&& !(pKeystroke->Flags&XINPUT_DEBUG_KEYSTROKE_FLAG_KEYUP) ) { RtlCopyMemory( &XID_KeyboardState.Keyboards[iQueueIndex].RepeatKeystroke, &XID_KeyboardState.Keyboards[iQueueIndex].KeyQueue[dwReadPos], sizeof(XINPUT_DEBUG_KEYSTROKE) ); XID_KeyboardState.Keyboards[iQueueIndex].RepeatKeystroke.Flags |= XINPUT_DEBUG_KEYSTROKE_FLAG_REPEAT; dwTickCount += XID_KeyboardState.QueueParameters.dwRepeatDelay - XID_KeyboardState.QueueParameters.dwRepeatInterval; XID_KeyboardState.Keyboards[iQueueIndex].LastRepeatTick = dwTickCount; } XID_KeyboardState.Keyboards[iQueueIndex].QueueReadPos = (dwReadPos + 1)%XID_KeyboardState.QueueParameters.dwQueueSize; ExitXInputGetKeyStroke: KeLowerIrql(oldIrql); return dwError; } void XID_KeyboardOpen(HANDLE hDevice) { #ifdef SINGLE_KEYBOARD_ONLY if(NULL == XID_KeyboardState.Keyboards[0].hDevice) { XID_KeyboardState.Keyboards[0].hDevice = hDevice; XID_KeyboardReset(0); } #else // !SINGLE_KEYBOARD_ONLY // // Find an empty keyboard instance // int i; for(i=0; i<4; i++) { if(NULL == XID_KeyboardState.Keyboards[i].hDevice) { XID_KeyboardState.Keyboards[i].hDevice = hDevice; XID_KeyboardReset(i); break; } } #endif //SINGLE_KEYBOARD_ONLY } void XID_KeyboardClose(HANDLE hDevice) { #ifdef SINGLE_KEYBOARD_ONLY if(hDevice == XID_KeyboardState.Keyboards[0].hDevice) { XID_KeyboardState.Keyboards[0].hDevice = NULL; } #else int i; for(i=0; i<4; i++) { if(hDevice == XID_KeyboardState.Keyboards[i].hDevice) { XID_KeyboardState.Keyboards[i].hDevice = NULL; XID_KeyboardReset(i); break; } } #endif //SINGLE_KEYBOARD_ONLY } void XID_KeyboardRemove(HANDLE hDevice) { XID_KeyboardClose(hDevice); } void XID_KeyboardNewData(HANDLE hDevice, XINPUT_KEYBOARD *pPacket) { #ifdef SINGLE_KEYBOARD_ONLY if(hDevice == XID_KeyboardState.Keyboards[0].hDevice) { XID_KeyboardUpdate(0, pPacket); } #else int i; for(i=0; i<4; i++) { if(hDevice == XID_KeyboardState.Keyboards[i].hDevice) { XID_KeyboardUpdate(i, pPacket); break; } } #endif //SINGLE_KEYBOARD_ONLY } BOOL XID_KeyboardInitQueue(int iInstance, DWORD dwQueueLength) { XID_KeyboardState.Keyboards[iInstance].KeyQueue = (PXINPUT_DEBUG_KEYSTROKE)ExAllocatePoolWithTag( dwQueueLength, 'drbk' ); if(XID_KeyboardState.Keyboards[iInstance].KeyQueue) { XID_KeyboardState.Keyboards[iInstance].QueueReadPos = 0; XID_KeyboardState.Keyboards[iInstance].QueueWritePos = 0; XID_KeyboardState.Keyboards[iInstance].LastRepeatTick =0; return TRUE; } else { return FALSE; } } void XID_KeyboardReset(int iInstance) { XID_KeyboardState.Keyboards[iInstance].KeyboardLeds.LedStates = 0; RtlZeroMemory(&XID_KeyboardState.Keyboards[iInstance].LastPacket,sizeof(XINPUT_KEYBOARD)); } void XID_KeyboardUpdate(int iInstance, XINPUT_KEYBOARD *pPacket) { BYTE oldModifiers; BYTE newModifiers; XINPUT_KEYBOARD DownKeys; XINPUT_KEYBOARD UpKeys; int index, iNewKeyIndex, iOldKeyIndex; UCHAR keyStrokeFlags; // // Assume key queue is per keyboard, until we know differently. // int iQueueIndex = iInstance; //** //** Figure out which keys were pressed and released. //** A good deal of the following code is for the //** special case of a mixing all keyboards into a //** single queue. //** // // Calculate the old and new state of the modifiers across all combined queues // #ifndef SINGLE_KEYBOARD_ONLY if(XID_KeyboardState.QueueParameters.dwFlags&XINPUT_DEBUG_KEYQUEUE_FLAG_ONE_QUEUE) { iQueueIndex = 0; //Change the queue to 0 since this is one queue oldModifiers = 0; newModifiers = 0; for(index = 0; index < 4; index++) { if(XID_KeyboardState.Keyboards[index].hDevice) { oldModifiers |= XID_KeyboardState.Keyboards[index].LastPacket.Modifiers; if((iInstance != index)) { newModifiers |= XID_KeyboardState.Keyboards[index].LastPacket.Modifiers; } else { newModifiers |= pPacket->Modifiers; } } } } else #endif //SINGLE_KEYBOARD_ONLY // // Queues are not combined so do just this keyboard // { oldModifiers = XID_KeyboardState.Keyboards[iInstance].LastPacket.Modifiers; newModifiers = pPacket->Modifiers; } // // Calculate the modifiers pressed and released // UpKeys.Modifiers = oldModifiers & ~newModifiers; DownKeys.Modifiers = ~oldModifiers & newModifiers; // // Shut off key repeat if modifiers changed // if(oldModifiers != newModifiers) { XID_KeyboardState.Keyboards[iQueueIndex].LastRepeatTick = 0; } // // Calculate keys that went down (for this keyboard only) // for(iNewKeyIndex = 0; iNewKeyIndex<6; iNewKeyIndex++) { BOOL fAddKey = FALSE; UCHAR NewKey = pPacket->Keys[iNewKeyIndex]; if(NewKey > HID_USAGE_INDEX_KEYBOARD_UNDEFINED) { fAddKey = TRUE; for(iOldKeyIndex = 0; iOldKeyIndex<6; iOldKeyIndex++) { if(NewKey == XID_KeyboardState.Keyboards[iInstance].LastPacket.Keys[iOldKeyIndex]) { fAddKey = FALSE; break; } } } if(fAddKey) { XID_KeyboardState.Keyboards[iQueueIndex].LastRepeatTick = 0; DownKeys.Keys[iNewKeyIndex] = NewKey; } else { DownKeys.Keys[iNewKeyIndex] = 0; } } // // Calculate keys that went up (for this keyboard only) // for(iOldKeyIndex = 0; iOldKeyIndex<6; iOldKeyIndex++) { UCHAR OldKey = XID_KeyboardState.Keyboards[iInstance].LastPacket.Keys[iOldKeyIndex]; BOOL fAddKey = FALSE; if(OldKey > HID_USAGE_INDEX_KEYBOARD_UNDEFINED) { fAddKey = TRUE; for(iNewKeyIndex = 0; iNewKeyIndex<6; iNewKeyIndex++) { if(OldKey == pPacket->Keys[iNewKeyIndex]) { fAddKey = FALSE; break; } } } if(fAddKey) { XID_KeyboardState.Keyboards[iQueueIndex].LastRepeatTick = 0; UpKeys.Keys[iOldKeyIndex] = OldKey; } else { UpKeys.Keys[iOldKeyIndex] = 0; } } // // Now check up and down keys against other keyboards // (if single queue). Basically, a key cannot have gone up or down // if it is down on another keyboard. // #ifndef SINGLE_KEYBOARD_ONLY if(XID_KeyboardState.QueueParameters.dwFlags&XINPUT_DEBUG_KEYQUEUE_FLAG_ONE_QUEUE) { for(index = 0; index < 4; index++) { if(XID_KeyboardState.Keyboards[index].hDevice && (iInstance != index)) { for(iNewKeyIndex = 0; iNewKeyIndex<6; iNewKeyIndex++) { for(iOldKeyIndex = 0; iOldKeyIndex<6; iOldKeyIndex++) { UCHAR OldKey = XID_KeyboardState.Keyboards[index].LastPacket.Keys[iOldKeyIndex]; if(UpKeys.Keys[iNewKeyIndex]==OldKey) { UpKeys.Keys[iNewKeyIndex]=0; } if(DownKeys.Keys[iNewKeyIndex]==OldKey) { DownKeys.Keys[iNewKeyIndex]=0; } } } } } } #endif //SINGLE_KEYBOARD_ONLY // // Copy the packet into the last packet // RtlCopyMemory(&XID_KeyboardState.Keyboards[iInstance].LastPacket, pPacket, sizeof(XINPUT_KEYBOARD)); //** //** Calculate the new CapsLock, NumLock and ScrollLock states. //** (The only left to do is the lock key checking.) BOOL fLedStateChange = FALSE; for(index =0; index < 6; index++) { switch(DownKeys.Keys[index]) { case HID_USAGE_INDEX_KEYBOARD_SCROLL_LOCK: XID_KeyboardState.Keyboards[iQueueIndex].KeyboardLeds.LedStates ^= HID_KEYBOARDLED_MASK_SCROLL_LOCK; fLedStateChange = TRUE; break; case HID_USAGE_INDEX_KEYPAD_NUM_LOCK: XID_KeyboardState.Keyboards[iQueueIndex].KeyboardLeds.LedStates ^= HID_KEYBOARDLED_MASK_NUM_LOCK; fLedStateChange = TRUE; break; case HID_USAGE_INDEX_KEYBOARD_CAPS_LOCK: XID_KeyboardState.Keyboards[iQueueIndex].KeyboardLeds.LedStates ^= HID_KEYBOARDLED_MASK_CAPS_LOCK; fLedStateChange = TRUE; break; } } // // Kick off LED update state machine. // if(fLedStateChange) { //TODO SOMETIME WAY IN FUTURE, NOT PLANNED ANYTIME BEFORE INITIAL XBOX LAUNCH. } //** //** Queue Events //** XINPUT_DEBUG_KEYSTROKE *pKeystrokeBuffer = XID_KeyboardQueueGetWritePos(iQueueIndex); // Set the Ctrl, Shift and Alt Flags keyStrokeFlags = (newModifiers | (newModifiers >> 4)) & 0x07; //Add in the Lock flags if(HID_KEYBOARDLED_MASK_SCROLL_LOCK&XID_KeyboardState.Keyboards[iQueueIndex].KeyboardLeds.LedStates) keyStrokeFlags |= XINPUT_DEBUG_KEYSTROKE_FLAG_SCROLLLOCK; if(HID_KEYBOARDLED_MASK_NUM_LOCK&XID_KeyboardState.Keyboards[iQueueIndex].KeyboardLeds.LedStates) keyStrokeFlags |= XINPUT_DEBUG_KEYSTROKE_FLAG_NUMLOCK; if(HID_KEYBOARDLED_MASK_CAPS_LOCK&XID_KeyboardState.Keyboards[iQueueIndex].KeyboardLeds.LedStates) keyStrokeFlags |= XINPUT_DEBUG_KEYSTROKE_FLAG_CAPSLOCK; // Stuff Modifier events in queue if(!(XINPUT_DEBUG_KEYQUEUE_FLAG_ASCII_ONLY&XID_KeyboardState.QueueParameters.dwFlags)) { int i,mask; BOOL fSet; for(i = 0, mask=1; i < 8; i++, mask<<=1) { fSet = FALSE; // UpKeys if(XINPUT_DEBUG_KEYQUEUE_FLAG_KEYUP&XID_KeyboardState.QueueParameters.dwFlags) { if(UpKeys.Modifiers&mask) { pKeystrokeBuffer->Flags = XINPUT_DEBUG_KEYSTROKE_FLAG_KEYUP; fSet = TRUE; } } // DownKeys if(XINPUT_DEBUG_KEYQUEUE_FLAG_KEYDOWN&XID_KeyboardState.QueueParameters.dwFlags) { if(DownKeys.Modifiers&mask) { pKeystrokeBuffer->Flags = 0; fSet = TRUE; } } if(fSet) { pKeystrokeBuffer->Flags |= keyStrokeFlags; pKeystrokeBuffer->VirtualKey = HidModifierToVK_Table[i]; pKeystrokeBuffer->Ascii = 0; pKeystrokeBuffer = XID_KeyboardQueueIncrementWritePos(iQueueIndex); } } } // // Place normal key up in queue // if(XINPUT_DEBUG_KEYQUEUE_FLAG_KEYUP&XID_KeyboardState.QueueParameters.dwFlags) { for(iNewKeyIndex=0; iNewKeyIndex<6; iNewKeyIndex++) { if(UpKeys.Keys[iNewKeyIndex] > HID_USAGE_INDEX_KEYBOARD_UNDEFINED) { XID_KeyboardQueueHidKeystroke( UpKeys.Keys[iNewKeyIndex], XINPUT_DEBUG_KEYSTROKE_FLAG_KEYUP|keyStrokeFlags, pKeystrokeBuffer ); if( !(XINPUT_DEBUG_KEYQUEUE_FLAG_ASCII_ONLY&XID_KeyboardState.QueueParameters.dwFlags) || (pKeystrokeBuffer->Ascii) ) { pKeystrokeBuffer = XID_KeyboardQueueIncrementWritePos(iQueueIndex); } } } } //** //** Place key down events in //** if(XINPUT_DEBUG_KEYQUEUE_FLAG_KEYDOWN&XID_KeyboardState.QueueParameters.dwFlags) { for(iNewKeyIndex=0; iNewKeyIndex<6; iNewKeyIndex++) { if(DownKeys.Keys[iNewKeyIndex] > HID_USAGE_INDEX_KEYBOARD_UNDEFINED) { XID_KeyboardQueueHidKeystroke( DownKeys.Keys[iNewKeyIndex], keyStrokeFlags, pKeystrokeBuffer ); if( !(XINPUT_DEBUG_KEYQUEUE_FLAG_ASCII_ONLY&XID_KeyboardState.QueueParameters.dwFlags) || (pKeystrokeBuffer->Ascii) ) { pKeystrokeBuffer = XID_KeyboardQueueIncrementWritePos(iQueueIndex); } } } } } XINPUT_DEBUG_KEYSTROKE *XID_KeyboardQueueGetWritePos(int iQueueIndex) { return &XID_KeyboardState.Keyboards[iQueueIndex].KeyQueue[XID_KeyboardState.Keyboards[iQueueIndex].QueueWritePos]; } XINPUT_DEBUG_KEYSTROKE *XID_KeyboardQueueIncrementWritePos(int iQueueIndex) { // // Get write position and increment it. // ULONG ulWritePos = XID_KeyboardState.Keyboards[iQueueIndex].QueueWritePos; ulWritePos = (ulWritePos+1)%XID_KeyboardState.QueueParameters.dwQueueSize; // // Check for a full queue, and just don't increment. // if(XID_KeyboardState.Keyboards[iQueueIndex].QueueReadPos==ulWritePos) { ulWritePos = XID_KeyboardState.Keyboards[iQueueIndex].QueueWritePos; }else { XID_KeyboardState.Keyboards[iQueueIndex].QueueWritePos = ulWritePos; } // // Return the next open keystroke position // return &XID_KeyboardState.Keyboards[iQueueIndex].KeyQueue[ulWritePos]; } VOID XID_KeyboardQueueHidKeystroke(UCHAR HidUsage, UCHAR Flags, PXINPUT_DEBUG_KEYSTROKE pKeystroke) { UCHAR Shift = (XINPUT_DEBUG_KEYSTROKE_FLAG_SHIFT&Flags) ? 1 : 0; UCHAR CapsLock = (XINPUT_DEBUG_KEYSTROKE_FLAG_CAPSLOCK&Flags) ? 1 : 0; UCHAR NumLock = (XINPUT_DEBUG_KEYSTROKE_FLAG_NUMLOCK&Flags) ? 1 : 0; ASSERT(HidUsage > HID_USAGE_INDEX_KEYBOARD_UNDEFINED); pKeystroke->Flags = Flags; pKeystroke->Ascii = 0; // // Check for A to Z range // The VK_A and VK_Z are not defined, but are the same as 'A' to 'Z'. // For ASCII we do the following: // If alt is down the ASCII is 0 regardless of anything else. // If ctrl is down and not shift, then it ^A to ^Z which is a // contiguous ASCII range from 1 to 26. // If CapsLock XOR Shift it is 'A' to 'Z', otherwise it is 'a' to 'z'. // (Unfortunately there is no logical XOR operator) if( (HidUsage >= HID_USAGE_INDEX_KEYBOARD_aA) && (HidUsage <= HID_USAGE_INDEX_KEYBOARD_zZ) ){ pKeystroke->VirtualKey = HidUsage + ('A' - HID_USAGE_INDEX_KEYBOARD_aA); // // Figure out the ASCII // if(!(XINPUT_DEBUG_KEYSTROKE_FLAG_ALT & Flags)) { if(XINPUT_DEBUG_KEYSTROKE_FLAG_CTRL & Flags) { if(!Shift) { // Control pKeystroke->Ascii = HidUsage - (HID_USAGE_INDEX_KEYBOARD_aA - 1); } }else { if(Shift^CapsLock) { pKeystroke->Ascii = HidUsage + ('A' - HID_USAGE_INDEX_KEYBOARD_aA); } else { pKeystroke->Ascii = HidUsage + ('a' - HID_USAGE_INDEX_KEYBOARD_aA); } } } } // // check 1-9 range // else if( (HidUsage >= HID_USAGE_INDEX_KEYBOARD_ONE) && (HidUsage <= HID_USAGE_INDEX_KEYBOARD_NINE) ) { pKeystroke->VirtualKey = HidUsage + ('1' - HID_USAGE_INDEX_KEYBOARD_ONE); if(Shift) { pKeystroke->Ascii = HidSymToAsciiShift_Table[HidUsage-HID_USAGE_INDEX_KEYBOARD_ONE]; } else { pKeystroke->Ascii = pKeystroke->VirtualKey; } } else // // Use the lookup table to get the Virtual Key. // // There are special ranges that require additional lookup // for ASCII. The numpad keys have wo tables, a (shifted xor numlock) table // and two symbol lookup table, shifted only (caps lock doesn't effect it). // { pKeystroke->VirtualKey = HidToVK_Table[HidUsage-HID_USAGE_INDEX_KEYBOARD_ZERO]; if(HidUsage <= HID_USAGE_INDEX_KEYBOARD_QUESTION) { if(Shift) { pKeystroke->Ascii = HidSymToAsciiShift_Table[HidUsage-HID_USAGE_INDEX_KEYBOARD_ONE]; } else { pKeystroke->Ascii = HidSymToAscii_Table[HidUsage-HID_USAGE_INDEX_KEYBOARD_ZERO]; } } else if( (HidUsage >= HID_USAGE_INDEX_KEYPAD_BACKSLASH) && (HidUsage <= HID_USAGE_INDEX_KEYPAD_DECIMAL) ) { if(Shift^NumLock) { pKeystroke->Ascii = HidNumPadShiftToAscii[HidUsage-HID_USAGE_INDEX_KEYPAD_BACKSLASH]; } else { pKeystroke->Ascii = HidNumPadToAscii[HidUsage-HID_USAGE_INDEX_KEYPAD_BACKSLASH]; } } } return; }