/*++ Copyright (c) 1996 Microsoft Corporation Module Name: query.c Abstract: This module contains the code for Translating HID report packets. Environment: Kernel & user mode Revision History: Nov-96 : created by Kenneth Ray --*/ #include #include "hidsdi.h" #include "hidparse.h" NTSTATUS __stdcall HidP_UsageListDifference ( IN PUSAGE PreviousUsageList, IN PUSAGE CurrentUsageList, OUT PUSAGE BreakUsageList, OUT PUSAGE MakeUsageList, IN ULONG UsageListLength ) /*++ Routine Description: Please see hidpi.h for description Notes: --*/ { ULONG i,j; ULONG test; ULONG b; // an index into MakeUsageList ULONG m; // an index into BreakUsageList USHORT usage; BOOLEAN found; b = m = 0; // // This assumes that UsageListLength will be a small number. // No keyboard today can generate more than 14 keys in one packet, and // there is no anticipation for other devices with greater than 14 usages // at once. For this reason the straight forward naive approach follows... // // These lists are not sorted. // // // Find the Old usages. // for (i=0; i Scancode // 0x0224, 0x6AE0, // WWW Back 0x0225, 0x69E0, // WWW Forward 0x0226, 0x68E0, // WWW Stop 0x0227, 0x67E0, // WWW Refresh 0x0221, 0x65E0, // WWW Search 0x022A, 0x66E0, // WWW Favorites 0x0223, 0x32E0, // WWW Home 0x018A, 0x6CE0 // Mail }; HIDP_SCANCODE_SUBTABLE HidP_ConsumerSubTables [1] = { {NULL, NULL} }; // //BOOLEAN //HidP_KbdPutKey ( // ULONG Code, // HIDP_KEYBOARD_DIRECTION KeyAction, // PHIDP_INSERT_SCANCODES Insert, // PVOID Context) // // Add the scan codes to the callers buffer using the callback routine // Insert. // // If we find a zero in the list then we are done with no error // If we find a invalid code (anything that starts with an F, then // we have a problem. No where in current published i8042 specs is there // a scan code of F0 ~ FF. // // If we are breaking then we need to set the high byte. // BOOLEAN HidP_KbdPutKey ( ULONG PassedCode, HIDP_KEYBOARD_DIRECTION KeyAction, PHIDP_INSERT_SCANCODES Insert, PVOID Context) { PUCHAR pCode = (PCHAR)&PassedCode; ULONG i; for (i = 0; i < sizeof(ULONG); i++) { // // Some swell keyboard vendors have added Fx charaters to their // keyboards which we now have to emulate. // // if ((0xF0 & *pCode) == 0xF0) { // return FALSE; // } if (0 == pCode[i]) { break; } if (HidP_Keyboard_Break == KeyAction) { pCode[i] |= 0x80; } } if (i) { (*Insert)(Context, pCode, i); } return TRUE; } NTSTATUS HidP_TranslateUsagesToI8042ScanCodes ( PUSAGE ChangedUsageList, // Those usages that changed ULONG UsageListLength, HIDP_KEYBOARD_DIRECTION KeyAction, PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, PHIDP_INSERT_SCANCODES InsertCodesProcedure, PVOID InsertCodesContext ) /*++ Routine Description: Please see hidpi.h for description Notes: --*/ { PUSAGE usage; ULONG i; NTSTATUS status = HIDP_STATUS_SUCCESS; for (i = 0, usage = ChangedUsageList; i < UsageListLength; i++, usage++) { if (0 == *usage) { // No more interesting usages. Zero terminated if not max length. break; } status = HidP_TranslateUsage (*usage, KeyAction, ModifierState, HidP_StraightLookup, HidP_KeyboardToScanCodeTable, HidP_KeyboardSubTables, InsertCodesProcedure, InsertCodesContext); if (HIDP_STATUS_SUCCESS != status) { break; } } return status; } NTSTATUS __stdcall HidP_TranslateUsageAndPagesToI8042ScanCodes ( PUSAGE_AND_PAGE ChangedUsageList, // Those usages that changed ULONG UsageListLength, HIDP_KEYBOARD_DIRECTION KeyAction, PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, PHIDP_INSERT_SCANCODES InsertCodesProcedure, PVOID InsertCodesContext ) /*++ Routine Description: Please see hidpi.h for description Notes: --*/ { PUSAGE_AND_PAGE usage; ULONG i; NTSTATUS status = HIDP_STATUS_SUCCESS; for (i = 0, usage = ChangedUsageList; i < UsageListLength; i++, usage++) { if (0 == usage->Usage) { break; } switch (usage->UsagePage) { case HID_USAGE_PAGE_KEYBOARD: status = HidP_TranslateUsage (usage->Usage, KeyAction, ModifierState, HidP_StraightLookup, HidP_KeyboardToScanCodeTable, HidP_KeyboardSubTables, InsertCodesProcedure, InsertCodesContext); break; case HID_USAGE_PAGE_CONSUMER: status = HidP_TranslateUsage (usage->Usage, KeyAction, ModifierState, HidP_AssociativeLookup, HidP_ConsumerToScanCodeTable, HidP_ConsumerSubTables, InsertCodesProcedure, InsertCodesContext); break; default: status = HIDP_STATUS_I8042_TRANS_UNKNOWN; } if (HIDP_STATUS_SUCCESS != status) { break; } } return status; } NTSTATUS __stdcall HidP_TranslateUsage ( USAGE Usage, HIDP_KEYBOARD_DIRECTION KeyAction, PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, PHIDP_LOOKUP_TABLE_PROC LookupTableProc, PULONG TranslationTable, PHIDP_SCANCODE_SUBTABLE SubTranslationTable, PHIDP_INSERT_SCANCODES InsertCodesProcedure, PVOID InsertCodesContext ) /*++ Routine Description: Notes: --*/ { ULONG scancode; PHIDP_SCANCODE_SUBTABLE table; NTSTATUS status; scancode = (* LookupTableProc) (TranslationTable, Usage); if (0 == scancode) { return HIDP_STATUS_I8042_TRANS_UNKNOWN; } if ((ModifierState->LeftControl || ModifierState->RightControl) && (scancode == 0x451DE1)) { // // The scancode of the pause key completely changes // if the control key is down. // scancode = 0x46E0; } if ((0xF0 & scancode) == 0xF0) { // Use a secondary table table = &SubTranslationTable [scancode & 0xF]; if (table->ScanCodeFcn) { if ((*table->ScanCodeFcn) (table->Table, (UCHAR) ((scancode & 0xFF00) >> 8), InsertCodesProcedure, InsertCodesContext, KeyAction, ModifierState)) { ; } else { return HIDP_STATUS_I8042_TRANS_UNKNOWN; } } else { return HIDP_STATUS_I8042_TRANS_UNKNOWN; } } else { HidP_KbdPutKey (scancode, KeyAction, InsertCodesProcedure, InsertCodesContext); } return HIDP_STATUS_SUCCESS; } BOOLEAN HidP_KeyboardKeypadCode ( IN ULONG * Table, IN UCHAR Index, IN PHIDP_INSERT_SCANCODES Insert, IN PVOID Context, IN HIDP_KEYBOARD_DIRECTION KeyAction, IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState ) /*++ Routine Description: Notes: --*/ { // // The num lock key (if set then we add even more scan codes for these // keys) // ULONG DarrylRis_Magic_Code = 0x2AE0; BOOLEAN status = TRUE; if ((ModifierState->NumLock) && (HidP_Keyboard_Make == KeyAction) ) { status = HidP_KbdPutKey (DarrylRis_Magic_Code, KeyAction, Insert, Context); } if (!status) { return status; } status = HidP_KbdPutKey (Table[Index], KeyAction, Insert, Context); if (!status) { return status; } if ((ModifierState->NumLock) && (HidP_Keyboard_Break == KeyAction) ) { status = HidP_KbdPutKey (DarrylRis_Magic_Code, KeyAction, Insert, Context); } return status; } BOOLEAN HidP_ModifierCode ( IN ULONG * Table, IN UCHAR Index, IN PHIDP_INSERT_SCANCODES Insert, IN PVOID Context, IN HIDP_KEYBOARD_DIRECTION KeyAction, IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState ) /*++ Routine Description: Notes: --*/ { if (Index >> 3) { // // Indices greater than 8 are sticky. // switch (KeyAction) { case HidP_Keyboard_Make: if (!(ModifierState->ul & (1 << (Index+16)))) { // // Mark this as the first make. // ModifierState->ul |= (1 << (Index+16)); // // Only toggle the state when this is the first make sent. // ModifierState->ul ^= (1 << Index); } break; case HidP_Keyboard_Break: // // Clear the fist make field. // ModifierState->ul &= ~(1 << (Index+16)); break; } } else { switch (KeyAction) { case HidP_Keyboard_Make: // The key is now on ModifierState->ul |= (1 << Index); break; case HidP_Keyboard_Break: // The key is now off ModifierState->ul &= ~(1 << Index); break; } } return HidP_KbdPutKey (Table[Index], KeyAction, Insert, Context); } BOOLEAN HidP_VendorBreakCodesAsMakeCodes ( IN ULONG * Table, IN UCHAR Index, IN PHIDP_INSERT_SCANCODES Insert, IN PVOID Context, IN HIDP_KEYBOARD_DIRECTION KeyAction, IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState ) { // // Vendor scan codes that have the high bit set and are technically // break codes, but are sent as make codes. No break code will be sent. // UNREFERENCED_PARAMETER (ModifierState); switch (KeyAction) { case HidP_Keyboard_Make: return HidP_KbdPutKey (Table[Index], KeyAction, Insert, Context); case HidP_Keyboard_Break: // do Nothing return TRUE; default: return FALSE; } } BOOLEAN HidP_PrintScreenCode ( IN ULONG * Table, IN UCHAR Index, IN PHIDP_INSERT_SCANCODES Insert, IN PVOID Context, IN HIDP_KEYBOARD_DIRECTION KeyAction, IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState ) /*++ Routine Description: Notes: --*/ { BOOLEAN status = TRUE; // // Special casing for the printscreen key. // if (ModifierState->LeftAlt || ModifierState->RightAlt) { // // Alt key down. // status = HidP_KbdPutKey (0x54, KeyAction, Insert, Context); } else if (ModifierState->LeftShift || ModifierState->RightShift || ModifierState->LeftControl || ModifierState->RightControl) { // // Shift or ctrl keys down. // status = HidP_KbdPutKey (Table[Index], KeyAction, Insert, Context); } else { // // No modifier keys down. Add some extra "padding" to the make and break. // ULONG DarrylRis_Magic_Code = 0x2AE0; if (HidP_Keyboard_Make == KeyAction) { status = HidP_KbdPutKey (DarrylRis_Magic_Code, KeyAction, Insert, Context); } if (!status) { return status; } status = HidP_KbdPutKey (Table[Index], KeyAction, Insert, Context); if (!status) { return status; } if (HidP_Keyboard_Break == KeyAction) { status = HidP_KbdPutKey (DarrylRis_Magic_Code, KeyAction, Insert, Context); } } return status; } ULONG HidP_StraightLookup ( IN PULONG Table, IN ULONG Usage ) { if (Usage > 0xFF) { // We have // have no translation for this usage. return 0; } return Table[Usage]; } ULONG HidP_AssociativeLookup ( IN PULONG Table, IN ULONG Usage ) { ULONG i; for (i = 0; i < (HIDP_CONSUMER_TABLE_SIZE - 1); i+=2) { if (Usage == Table[i]) { return Table[i+1]; } } return 0; }