├── sys ├── croskeyboard.inx ├── firmware.h ├── public.h ├── croskeyboard.rc ├── croskeyboard.vcxproj.Filters ├── firmware.c ├── croskeyboard.vcxproj ├── croskeyboard.h └── rawpdo.c ├── croskbhidremapper ├── croskbhidremapper │ ├── resource.h │ ├── croskbhidremapper.rc │ ├── Trace.h │ ├── croskbhidremapper.inf │ ├── hidcommon.h │ ├── croskbhidremapper.h │ ├── croskbhidremapper.vcxproj │ └── croskbhidremapper.cpp └── croskbhidremapper.sln ├── croskbreload ├── croskbreload.cpp ├── croskbreload.vcxproj.filters ├── croskbreload.sln ├── croskbhid.h ├── croskbreload.vcxproj └── client.cpp ├── exe ├── kbftest.vcxproj.Filters ├── kbftest.vcxproj └── kbftest.c ├── README.md ├── croskeyboard.sln ├── croskbsettings.bin └── .gitignore /sys/croskeyboard.inx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrultrabook/croskeyboard4/master/sys/croskeyboard.inx -------------------------------------------------------------------------------- /sys/firmware.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct firmware { 5 | void* data; 6 | size_t size; 7 | }; 8 | 9 | NTSTATUS request_firmware(const struct firmware** img, PCWSTR path); 10 | void free_firmware(const struct firmware* fw); -------------------------------------------------------------------------------- /sys/public.h: -------------------------------------------------------------------------------- 1 | #ifndef _PUBLIC_H 2 | #define _PUBLIC_H 3 | 4 | #define IOCTL_INDEX 0x800 5 | 6 | #define IOCTL_KBFILTR_GET_KEYBOARD_ATTRIBUTES CTL_CODE( FILE_DEVICE_KEYBOARD, \ 7 | IOCTL_INDEX, \ 8 | METHOD_BUFFERED, \ 9 | FILE_READ_DATA) 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /croskbhidremapper/croskbhidremapper/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by croskbhidremapper.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /croskbreload/croskbreload.cpp: -------------------------------------------------------------------------------- 1 | // crosecservice.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #include 5 | #include 6 | #include 7 | #include "croskbhid.h" 8 | 9 | int main() 10 | { 11 | pcroskbhid_client client = croskbhid_alloc(); 12 | BOOL connect = croskbhid_connect(client); 13 | printf("Connected? %d\n", connect); 14 | 15 | CrosKBHIDRemapperSettingsReport report = { 0 }; 16 | 17 | report.ReportID = REPORTID_SETTINGS; 18 | report.SettingsRegister = SETTINGS_REG_RELOADSETTINGS; 19 | report.SettingsValue = 0; 20 | 21 | croskbhid_write_keyboard(client, &report); 22 | 23 | croskbhid_disconnect(client); 24 | } -------------------------------------------------------------------------------- /exe/kbftest.vcxproj.Filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* 6 | {36E465FA-C1F4-4BC1-8C9D-3BF543B2D569} 7 | 8 | 9 | h;hpp;hxx;hm;inl;inc;xsd 10 | {AEE95AC2-A478-46ED-83E9-20529E0198F8} 11 | 12 | 13 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml 14 | {51D79FBF-B30A-49FB-A34C-19FBE6DA4A8F} 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /sys/croskeyboard.rc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define VER_FILETYPE VFT_DRV 4 | #define VER_FILESUBTYPE VFT2_DRV_KEYBOARD 5 | #define VER_FILEDESCRIPTION_STR "Chromebook Keyboard Driver" 6 | #define VER_INTERNALNAME_STR "croskeyboard.sys" 7 | #define VER_ORIGINALFILENAME_STR "croskeyboard.sys" 8 | 9 | #define VER_LEGALCOPYRIGHT_YEARS "2023" 10 | #define VER_LEGALCOPYRIGHT_STR "Copyright (C) " VER_LEGALCOPYRIGHT_YEARS " CoolStar." 11 | 12 | #define VER_FILEVERSION 4,0,0,0 13 | #define VER_PRODUCTVERSION_STR "4.0.0.0" 14 | #define VER_PRODUCTVERSION 4,0,0,0 15 | #define LVER_PRODUCTVERSION_STR L"4.0.0.0" 16 | 17 | #define VER_FILEFLAGSMASK (VS_FF_DEBUG | VS_FF_PRERELEASE) 18 | #ifdef DEBUG 19 | #define VER_FILEFLAGS (VS_FF_DEBUG) 20 | #else 21 | #define VER_FILEFLAGS (0) 22 | #endif 23 | 24 | #define VER_FILEOS VOS_NT_WINDOWS32 25 | 26 | #define VER_COMPANYNAME_STR "CoolStar" 27 | #define VER_PRODUCTNAME_STR "Chromebook Keyboard Driver" 28 | 29 | #include "common.ver" -------------------------------------------------------------------------------- /croskbhidremapper/croskbhidremapper/croskbhidremapper.rc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define VER_FILETYPE VFT_DRV 4 | #define VER_FILESUBTYPE VFT2_DRV_KEYBOARD 5 | #define VER_FILEDESCRIPTION_STR "Chromebook Keyboard HID Helper" 6 | #define VER_INTERNALNAME_STR "croskbhidremapper.sys" 7 | #define VER_ORIGINALFILENAME_STR "croskbhidremapper.sys" 8 | 9 | #define VER_LEGALCOPYRIGHT_YEARS "2023" 10 | #define VER_LEGALCOPYRIGHT_STR "Copyright (C) " VER_LEGALCOPYRIGHT_YEARS " CoolStar." 11 | 12 | #define VER_FILEVERSION 4,0,0,0 13 | #define VER_PRODUCTVERSION_STR "4.0.0.0" 14 | #define VER_PRODUCTVERSION 4,0,0,0 15 | #define LVER_PRODUCTVERSION_STR L"4.0.0.0" 16 | 17 | #define VER_FILEFLAGSMASK (VS_FF_DEBUG | VS_FF_PRERELEASE) 18 | #ifdef DEBUG 19 | #define VER_FILEFLAGS (VS_FF_DEBUG) 20 | #else 21 | #define VER_FILEFLAGS (0) 22 | #endif 23 | 24 | #define VER_FILEOS VOS_NT_WINDOWS32 25 | 26 | #define VER_COMPANYNAME_STR "CoolStar" 27 | #define VER_PRODUCTNAME_STR "Chromebook Keyboard HID Helper" 28 | 29 | #include "common.ver" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # croskeyboard4 2 | Windows keyboard filter driver with function key override support for Chromebooks 3 | 4 | # Compatibility 5 | Works on the Chromebook Pixel and any chromebook released after the Pixel, though works best on chromebooks that support Vivaldi 6 | 7 | # Installation 8 | First you need to install croskeyboard4 on top of the existing keyboard device (ACPI\GOOG000A) 9 | 10 | If your chromebook supports Vivaldi, you should also install https://github.com/coolstar/crosecvivaldi to ACPI\GOOG0007 11 | Also make sure to install croskbhidremapper to CROSKB\HID0000 in order to get support for brightness keys and settings 12 | 13 | # Settings 14 | 15 | Settings are loaded from C:\Windows\system32\drivers\croskbsettings.bin 16 | 17 | A sample binary has been provided here https://github.com/coolstar/croskeyboard4/blob/master/croskbsettings.bin with settings matching croskeyboard3 / croskbremap. To load settings, drag the binary in and either reboot, or run croskbreload to hot-reload settings. 18 | 19 | To create your own settings, you may use https://github.com/coolstar/VivaldiKeyboardTester and search for croskbsettings.bin in VivaldiKeyboardTester.cpp. 20 | 21 | A GUI tool will be coming soon to support generating your own remap files. -------------------------------------------------------------------------------- /croskbreload/croskbreload.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /croskbreload/croskbreload.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "croskbreload", "croskbreload.vcxproj", "{25357B70-BB72-4B8E-9334-19F6BA5999BB}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {25357B70-BB72-4B8E-9334-19F6BA5999BB}.Debug|x64.ActiveCfg = Debug|x64 17 | {25357B70-BB72-4B8E-9334-19F6BA5999BB}.Debug|x64.Build.0 = Debug|x64 18 | {25357B70-BB72-4B8E-9334-19F6BA5999BB}.Debug|x86.ActiveCfg = Debug|Win32 19 | {25357B70-BB72-4B8E-9334-19F6BA5999BB}.Debug|x86.Build.0 = Debug|Win32 20 | {25357B70-BB72-4B8E-9334-19F6BA5999BB}.Release|x64.ActiveCfg = Release|x64 21 | {25357B70-BB72-4B8E-9334-19F6BA5999BB}.Release|x64.Build.0 = Release|x64 22 | {25357B70-BB72-4B8E-9334-19F6BA5999BB}.Release|x86.ActiveCfg = Release|Win32 23 | {25357B70-BB72-4B8E-9334-19F6BA5999BB}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {4F0E98D9-AC19-42AB-B6E9-EF9F9261E0A2} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /croskbreload/croskbhid.h: -------------------------------------------------------------------------------- 1 | #if !defined(_CROSKBHIDREMAPPER_COMMON_H_) 2 | #define _CROSKBHIDREMAPPER_COMMON_H_ 3 | 4 | typedef struct _croskbhid_client_t* pcroskbhid_client; 5 | 6 | 7 | // 8 | //These are the device attributes returned by vmulti in response 9 | // to IOCTL_HID_GET_DEVICE_ATTRIBUTES. 10 | // 11 | 12 | #define CROSKBHIDREMAPPER_PID 0x0303 13 | #define CROSKBHIDREMAPPER_VID 0x18D1 14 | #define CROSKBHIDREMAPPER_VERSION 0x0004 15 | 16 | #define CROSKBLIGHT_PID 0x0002 17 | #define CROSKBLIGHT_VID 0x18D1 18 | #define CROSKBLIGHT_VERSION 0x0001 19 | 20 | // 21 | // These are the report ids 22 | // 23 | 24 | #define REPORTID_KBLIGHT 0x01 25 | 26 | #define REPORTID_KEYBOARD 0x07 27 | #define REPORTID_MEDIA 0x08 28 | #define REPORTID_SETTINGS 0x09 29 | 30 | #define SETTINGS_REG_RELOADSETTINGS 0x01 31 | 32 | #pragma pack(1) 33 | typedef struct _CROSKBHIDREMAPPER_SETTINGS_REPORT 34 | { 35 | 36 | BYTE ReportID; 37 | 38 | BYTE SettingsRegister; 39 | 40 | BYTE SettingsValue; 41 | 42 | } CrosKBHIDRemapperSettingsReport; 43 | #pragma pack() 44 | 45 | pcroskbhid_client croskbhid_alloc(void); 46 | 47 | void croskbhid_free(pcroskbhid_client vmulti); 48 | 49 | BOOL croskbhid_connect(pcroskbhid_client vmulti); 50 | 51 | void croskbhid_disconnect(pcroskbhid_client vmulti); 52 | 53 | BOOL croskblight_connect(pcroskbhid_client croskbhid); 54 | void croskblight_disconnect(pcroskbhid_client croskbhid); 55 | 56 | BOOL croskbhid_read_keyboard(pcroskbhid_client vmulti, CrosKBHIDRemapperSettingsReport* pReport); 57 | BOOL croskbhid_write_keyboard(pcroskbhid_client vmulti, CrosKBHIDRemapperSettingsReport* pReport); 58 | 59 | #endif 60 | #pragma once 61 | -------------------------------------------------------------------------------- /croskbhidremapper/croskbhidremapper/Trace.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Module Name: 4 | 5 | Trace.h 6 | 7 | Abstract: 8 | 9 | Header file for the debug tracing related function defintions and macros. 10 | 11 | Environment: 12 | 13 | Kernel mode 14 | 15 | --*/ 16 | 17 | // 18 | // Define the tracing flags. 19 | // 20 | // Tracing GUID - 79182672-fe97-45b4-bd65-fe00a2fb2477 21 | // 22 | 23 | #define WPP_CONTROL_GUIDS \ 24 | WPP_DEFINE_CONTROL_GUID( \ 25 | croskeyboard3TraceGuid, (79182672,fe97,45b4,bd65,fe00a2fb2477), \ 26 | \ 27 | WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ 28 | WPP_DEFINE_BIT(TRACE_DRIVER) \ 29 | WPP_DEFINE_BIT(TRACE_DEVICE) \ 30 | WPP_DEFINE_BIT(TRACE_QUEUE) \ 31 | ) 32 | 33 | #define WPP_FLAG_LEVEL_LOGGER(flag, level) \ 34 | WPP_LEVEL_LOGGER(flag) 35 | 36 | #define WPP_FLAG_LEVEL_ENABLED(flag, level) \ 37 | (WPP_LEVEL_ENABLED(flag) && \ 38 | WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) 39 | 40 | #define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ 41 | WPP_LEVEL_LOGGER(flags) 42 | 43 | #define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ 44 | (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) 45 | 46 | // 47 | // This comment block is scanned by the trace preprocessor to define our 48 | // Trace function. 49 | // 50 | // begin_wpp config 51 | // FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); 52 | // FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); 53 | // end_wpp 54 | // 55 | -------------------------------------------------------------------------------- /croskbhidremapper/croskbhidremapper/croskbhidremapper.inf: -------------------------------------------------------------------------------- 1 | ;/*++ 2 | ; 3 | ;Copyright (c) CoolStar. All rights reserved. 4 | ; 5 | ;Module Name: 6 | ; coolstar.inf 7 | ; 8 | ;Abstract: 9 | ; INF file for installing the CrosKBHIDRemapper MaxTouch Touch Screen Driver 10 | ; 11 | ; 12 | ;--*/ 13 | 14 | [Version] 15 | Signature = "$WINDOWS NT$" 16 | Class = HIDClass 17 | ClassGuid = {745a17a0-74d3-11d0-b6fe-00a0c90f57da} 18 | Provider = CoolStar 19 | DriverVer = 06/21/2006,6.1.7779.2 20 | CatalogFile = croskbhidremapper.cat 21 | PnpLockdown = 1 22 | 23 | [DestinationDirs] 24 | DefaultDestDir = 12 25 | 26 | [SourceDisksNames] 27 | 1 = %DiskId1%,,,"" 28 | 29 | [SourceDisksFiles] 30 | croskbhidremapper.sys = 1,, 31 | 32 | ;***************************************** 33 | ; CrosTouchScreen Install Section 34 | ;***************************************** 35 | 36 | [Manufacturer] 37 | %StdMfg%=Standard,NT$ARCH$ 38 | 39 | ; Decorated model section take precedence over undecorated 40 | ; ones on XP and later. 41 | [Standard.NT$ARCH$] 42 | %CrosKBHIDRemapper.DeviceDesc%=CrosKBHIDRemapper_Device, CROSKB\HID0000 43 | 44 | [CrosKBHIDRemapper_Device.NT] 45 | CopyFiles=Drivers_Dir 46 | 47 | [CrosKBHIDRemapper_Device.NT.HW] 48 | AddReg=CrosKBHIDRemapper_AddReg 49 | 50 | [Drivers_Dir] 51 | croskbhidremapper.sys 52 | 53 | [CrosKBHIDRemapper_AddReg] 54 | HKR,,"UpperFilters",0x00010000,"mshidkmdf" 55 | 56 | ;-------------- Service installation 57 | [CrosKBHIDRemapper_Device.NT.Services] 58 | AddService = CrosKBHIDRemapper,%SPSVCINST_ASSOCSERVICE%, CrosKBHIDRemapper_Service_Inst 59 | 60 | ; -------------- CrosTouchScreen driver install sections 61 | [CrosKBHIDRemapper_Service_Inst] 62 | DisplayName = %CrosKBHIDRemapper.SVCDESC% 63 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 64 | StartType = 3 ; SERVICE_DEMAND_START 65 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 66 | ServiceBinary = %12%\croskbhidremapper.sys 67 | LoadOrderGroup = Base 68 | 69 | [Strings] 70 | SPSVCINST_ASSOCSERVICE= 0x00000002 71 | StdMfg = "CoolStar" 72 | DiskId1 = "CrosKBHIDRemapper Installation Disk #1" 73 | CrosKBHIDRemapper.DeviceDesc = "Chromebook Keyboard HID Helper" 74 | CrosKBHIDRemapper.SVCDESC = "CrosKBHIDRemapper Service" 75 | -------------------------------------------------------------------------------- /sys/croskeyboard.vcxproj.Filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* 6 | {69D0BA5C-EFD2-4A08-8829-DABFDD34CCDE} 7 | 8 | 9 | h;hpp;hxx;hm;inl;inc;xsd 10 | {9DBC6F0A-A32B-4824-BE0B-1DF2B8F92760} 11 | 12 | 13 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml 14 | {2EBD3B86-D170-4C37-8437-0A64E6864AA6} 15 | 16 | 17 | inf;inv;inx;mof;mc; 18 | {A6674166-7336-4066-9782-8BC6F701B19A} 19 | 20 | 21 | 22 | 23 | Source Files 24 | 25 | 26 | Source Files 27 | 28 | 29 | Source Files 30 | 31 | 32 | 33 | 34 | Resource Files 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | 55 | 56 | Driver Files 57 | 58 | 59 | -------------------------------------------------------------------------------- /croskbhidremapper/croskbhidremapper.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "croskbhidremapper", "croskbhidremapper\croskbhidremapper.vcxproj", "{E0C3F023-6A54-419C-9C6E-E0638B55D99F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|ARM = Release|ARM 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Debug|ARM.ActiveCfg = Debug|ARM 21 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Debug|ARM.Build.0 = Debug|ARM 22 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Debug|ARM64.ActiveCfg = Debug|ARM64 23 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Debug|ARM64.Build.0 = Debug|ARM64 24 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Debug|x64.ActiveCfg = Debug|x64 25 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Debug|x64.Build.0 = Debug|x64 26 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Debug|x86.ActiveCfg = Debug|Win32 27 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Debug|x86.Build.0 = Debug|Win32 28 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Release|ARM.ActiveCfg = Release|ARM 29 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Release|ARM.Build.0 = Release|ARM 30 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Release|ARM64.ActiveCfg = Release|ARM64 31 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Release|ARM64.Build.0 = Release|ARM64 32 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Release|x64.ActiveCfg = Release|x64 33 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Release|x64.Build.0 = Release|x64 34 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Release|x86.ActiveCfg = Release|Win32 35 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F}.Release|x86.Build.0 = Release|Win32 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {EDB8A6EF-8960-4FF7-AEB7-4D5038938614} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /sys/firmware.c: -------------------------------------------------------------------------------- 1 | #include "firmware.h" 2 | #include "croskeyboard.h" 3 | 4 | NTSTATUS request_firmware(const struct firmware** img, PCWSTR path) { 5 | *img = NULL; 6 | 7 | struct firmware* fw = (struct firmware*)ExAllocatePoolZero(NonPagedPool, sizeof(struct firmware), KBFILTER_POOL_TAG); 8 | if (!fw) { 9 | return STATUS_NO_MEMORY; 10 | } 11 | RtlZeroMemory(fw, sizeof(struct firmware)); 12 | 13 | NTSTATUS status; 14 | 15 | UNICODE_STRING uniName; 16 | OBJECT_ATTRIBUTES objAttr; 17 | 18 | RtlInitUnicodeString(&uniName, path); 19 | InitializeObjectAttributes(&objAttr, &uniName, 20 | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 21 | NULL, NULL); 22 | 23 | // Do not try to perform any file operations at higher IRQL levels. 24 | // Instead, you may use a work item or a system worker thread to perform file operations. 25 | 26 | if (KeGetCurrentIrql() != PASSIVE_LEVEL) { 27 | status = STATUS_INVALID_DEVICE_STATE; 28 | free_firmware(fw); 29 | return status; 30 | } 31 | 32 | HANDLE handle; 33 | IO_STATUS_BLOCK ioStatusBlock; 34 | 35 | status = ZwCreateFile(&handle, 36 | GENERIC_READ, 37 | &objAttr, &ioStatusBlock, NULL, 38 | FILE_ATTRIBUTE_NORMAL, 39 | 0, 40 | FILE_OPEN, 41 | FILE_SYNCHRONOUS_IO_NONALERT, 42 | NULL, 0); 43 | if (!NT_SUCCESS(status)) { 44 | free_firmware(fw); 45 | return status; 46 | } 47 | 48 | FILE_STANDARD_INFORMATION fileInfo; 49 | status = ZwQueryInformationFile( 50 | handle, 51 | &ioStatusBlock, 52 | &fileInfo, 53 | sizeof(fileInfo), 54 | FileStandardInformation 55 | ); 56 | if (!NT_SUCCESS(status)) { 57 | ZwClose(handle); 58 | free_firmware(fw); 59 | return status; 60 | } 61 | 62 | fw->size = fileInfo.EndOfFile.QuadPart; 63 | fw->data = ExAllocatePoolZero(NonPagedPool, fw->size, KBFILTER_POOL_TAG); 64 | if (!fw->data) { 65 | status = STATUS_NO_MEMORY; 66 | ZwClose(handle); 67 | free_firmware(fw); 68 | return status; 69 | } 70 | 71 | LARGE_INTEGER byteOffset; 72 | byteOffset.LowPart = byteOffset.HighPart = 0; 73 | status = ZwReadFile(handle, NULL, NULL, NULL, &ioStatusBlock, fw->data, (ULONG)fw->size, &byteOffset, NULL); 74 | if (!NT_SUCCESS(status)) { 75 | ZwClose(handle); 76 | free_firmware(fw); 77 | return status; 78 | } 79 | *img = fw; 80 | 81 | ZwClose(handle); 82 | return status; 83 | } 84 | 85 | void free_firmware(const struct firmware* fw) { 86 | if (fw->data) { 87 | ExFreePoolWithTag(fw->data, KBFILTER_POOL_TAG); 88 | } 89 | ExFreePoolWithTag((PVOID)fw, KBFILTER_POOL_TAG); 90 | } -------------------------------------------------------------------------------- /croskbhidremapper/croskbhidremapper/hidcommon.h: -------------------------------------------------------------------------------- 1 | #if !defined(_CROSKBHIDREMAPPER_COMMON_H_) 2 | #define _CROSKBHIDREMAPPER_COMMON_H_ 3 | 4 | // 5 | //These are the device attributes returned by vmulti in response 6 | // to IOCTL_HID_GET_DEVICE_ATTRIBUTES. 7 | // 8 | 9 | #define CROSKBHIDREMAPPER_PID 0x0303 10 | #define CROSKBHIDREMAPPER_VID 0x18D1 11 | #define CROSKBHIDREMAPPER_VERSION 0x0004 12 | 13 | // 14 | // These are the report ids 15 | // 16 | 17 | #define REPORTID_KEYBOARD 0x07 18 | #define REPORTID_MEDIA 0x08 19 | #define REPORTID_SETTINGS 0x09 20 | 21 | // 22 | // Keyboard specific report infomation 23 | // 24 | 25 | #define KBD_LCONTROL_BIT 1 26 | #define KBD_LSHIFT_BIT 2 27 | #define KBD_LALT_BIT 4 28 | #define KBD_LGUI_BIT 8 29 | #define KBD_RCONTROL_BIT 16 30 | #define KBD_RSHIFT_BIT 32 31 | #define KBD_RALT_BIT 64 32 | #define KBD_RGUI_BIT 128 33 | 34 | #define KBD_KEY_CODES 6 35 | 36 | #pragma pack(1) 37 | typedef struct _CROSKBHIDREMAPPER_KEYBOARD_REPORT 38 | { 39 | 40 | BYTE ReportID; 41 | 42 | // Left Control, Left Shift, Left Alt, Left GUI 43 | // Right Control, Right Shift, Right Alt, Right GUI 44 | BYTE ShiftKeyFlags; 45 | 46 | BYTE Reserved; 47 | 48 | // See http://www.usb.org/developers/devclass_docs/Hut1_11.pdf 49 | // for a list of key codes 50 | BYTE KeyCodes[KBD_KEY_CODES]; 51 | 52 | } CrosKBHIDRemapperKeyboardReport; 53 | 54 | #pragma pack() 55 | 56 | #pragma pack(1) 57 | typedef struct _CROSKBHIDREMAPPER_MEDIA_REPORT 58 | { 59 | 60 | BYTE ReportID; 61 | 62 | BYTE ControlCode; 63 | 64 | BYTE Reserved; 65 | 66 | } CrosKBHIDRemapperMediaReport; 67 | 68 | #pragma pack() 69 | 70 | #pragma pack() 71 | 72 | // 73 | // Feature report infomation 74 | // 75 | 76 | #define DEVICE_MODE_MOUSE 0x00 77 | #define DEVICE_MODE_SINGLE_INPUT 0x01 78 | #define DEVICE_MODE_MULTI_INPUT 0x02 79 | 80 | #pragma pack(1) 81 | typedef struct _CROSKBHIDREMAPPER_FEATURE_REPORT 82 | { 83 | 84 | BYTE ReportID; 85 | 86 | BYTE DeviceMode; 87 | 88 | BYTE DeviceIdentifier; 89 | 90 | } CrosKBHIDRemapperFeatureReport; 91 | 92 | #define SETTINGS_REG_RELOADSETTINGS 0x01 93 | 94 | #pragma pack(1) 95 | typedef struct _CROSKBHIDREMAPPER_SETTINGS_REPORT 96 | { 97 | 98 | BYTE ReportID; 99 | 100 | BYTE SettingsRegister; 101 | 102 | BYTE SettingsValue; 103 | 104 | } CrosKBHIDRemapperSettingsReport; 105 | #pragma pack() 106 | 107 | #endif 108 | #pragma once 109 | -------------------------------------------------------------------------------- /croskeyboard.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0 5 | MinimumVisualStudioVersion = 12.0 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{FEF6FE00-75E7-4016-BD79-3A0DFFC7128F}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{4F78C4A7-C561-4CAC-811B-D22496D2C231}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kbftest", "exe\kbftest.vcxproj", "{CB35D9AC-AD35-4381-ADA4-84378289F086}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "croskeyboard", "sys\croskeyboard.vcxproj", "{7227DB35-883A-4EF0-B083-1698CFEF85A3}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Win32 = Debug|Win32 17 | Release|Win32 = Release|Win32 18 | Debug|x64 = Debug|x64 19 | Release|x64 = Release|x64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {CB35D9AC-AD35-4381-ADA4-84378289F086}.Debug|Win32.ActiveCfg = Debug|Win32 23 | {CB35D9AC-AD35-4381-ADA4-84378289F086}.Debug|Win32.Build.0 = Debug|Win32 24 | {CB35D9AC-AD35-4381-ADA4-84378289F086}.Release|Win32.ActiveCfg = Release|Win32 25 | {CB35D9AC-AD35-4381-ADA4-84378289F086}.Release|Win32.Build.0 = Release|Win32 26 | {CB35D9AC-AD35-4381-ADA4-84378289F086}.Debug|x64.ActiveCfg = Debug|x64 27 | {CB35D9AC-AD35-4381-ADA4-84378289F086}.Debug|x64.Build.0 = Debug|x64 28 | {CB35D9AC-AD35-4381-ADA4-84378289F086}.Release|x64.ActiveCfg = Release|x64 29 | {CB35D9AC-AD35-4381-ADA4-84378289F086}.Release|x64.Build.0 = Release|x64 30 | {7227DB35-883A-4EF0-B083-1698CFEF85A3}.Debug|Win32.ActiveCfg = Debug|Win32 31 | {7227DB35-883A-4EF0-B083-1698CFEF85A3}.Debug|Win32.Build.0 = Debug|Win32 32 | {7227DB35-883A-4EF0-B083-1698CFEF85A3}.Release|Win32.ActiveCfg = Release|Win32 33 | {7227DB35-883A-4EF0-B083-1698CFEF85A3}.Release|Win32.Build.0 = Release|Win32 34 | {7227DB35-883A-4EF0-B083-1698CFEF85A3}.Debug|x64.ActiveCfg = Debug|x64 35 | {7227DB35-883A-4EF0-B083-1698CFEF85A3}.Debug|x64.Build.0 = Debug|x64 36 | {7227DB35-883A-4EF0-B083-1698CFEF85A3}.Release|x64.ActiveCfg = Release|x64 37 | {7227DB35-883A-4EF0-B083-1698CFEF85A3}.Release|x64.Build.0 = Release|x64 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(NestedProjects) = preSolution 43 | {CB35D9AC-AD35-4381-ADA4-84378289F086} = {FEF6FE00-75E7-4016-BD79-3A0DFFC7128F} 44 | {7227DB35-883A-4EF0-B083-1698CFEF85A3} = {4F78C4A7-C561-4CAC-811B-D22496D2C231} 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /croskbsettings.bin: -------------------------------------------------------------------------------- 1 | BKrC(jig .0SSW*[*[[[**[KGMOHIPQ]&[]& -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_h.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *_wpftmp.csproj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush personal settings 296 | .cr/personal 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | 333 | # Local History for Visual Studio 334 | .localhistory/ 335 | -------------------------------------------------------------------------------- /exe/kbftest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {CB35D9AC-AD35-4381-ADA4-84378289F086} 23 | $(MSBuildProjectName) 24 | Debug 25 | Win32 26 | {59782B64-B06B-4AB2-AB2A-748656C59DB3} 27 | 28 | 29 | 30 | Windows10 31 | False 32 | Desktop 33 | 34 | WindowsApplicationForDrivers10.0 35 | Application 36 | 37 | 38 | Windows10 39 | True 40 | Desktop 41 | 42 | WindowsApplicationForDrivers10.0 43 | Application 44 | 45 | 46 | Windows10 47 | False 48 | Desktop 49 | 50 | WindowsApplicationForDrivers10.0 51 | Application 52 | 53 | 54 | Windows10 55 | True 56 | Desktop 57 | 58 | WindowsApplicationForDrivers10.0 59 | Application 60 | 61 | 62 | 63 | $(IntDir) 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | kbftest 80 | 81 | 82 | kbftest 83 | 84 | 85 | kbftest 86 | 87 | 88 | kbftest 89 | 90 | 91 | 92 | %(AdditionalDependencies);setupapi.lib 93 | 94 | 95 | 96 | 97 | 98 | 99 | sha256 100 | 101 | 102 | 103 | 104 | %(AdditionalDependencies);setupapi.lib 105 | 106 | 107 | 108 | 109 | 110 | 111 | sha256 112 | 113 | 114 | 115 | 116 | %(AdditionalDependencies);setupapi.lib 117 | 118 | 119 | 120 | 121 | 122 | 123 | sha256 124 | 125 | 126 | 127 | 128 | %(AdditionalDependencies);setupapi.lib 129 | 130 | 131 | 132 | 133 | 134 | 135 | sha256 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /exe/kbftest.c: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 6 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 7 | IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 8 | PURPOSE. 9 | 10 | Module Name: 11 | 12 | KBFTEST.C 13 | 14 | Abstract: 15 | 16 | 17 | Environment: 18 | 19 | usermode console application 20 | 21 | --*/ 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #pragma warning(disable:4201) 34 | 35 | #include 36 | #include 37 | 38 | #pragma warning(default:4201) 39 | 40 | #include "..\sys\public.h" 41 | 42 | //----------------------------------------------------------------------------- 43 | // 4127 -- Conditional Expression is Constant warning 44 | //----------------------------------------------------------------------------- 45 | #define WHILE(constant) \ 46 | __pragma(warning(disable: 4127)) while(constant); __pragma(warning(default: 4127)) 47 | 48 | DEFINE_GUID(GUID_DEVINTERFACE_KBFILTER, 49 | 0x3fb7299d, 0x6847, 0x4490, 0xb0, 0xc9, 0x99, 0xe0, 0x98, 0x6a, 0xb8, 0x86); 50 | // {3FB7299D-6847-4490-B0C9-99E0986AB886} 51 | 52 | 53 | int 54 | _cdecl 55 | main( 56 | _In_ int argc, 57 | _In_ char *argv[] 58 | ) 59 | { 60 | HDEVINFO hardwareDeviceInfo; 61 | SP_DEVICE_INTERFACE_DATA deviceInterfaceData; 62 | PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; 63 | ULONG predictedLength = 0; 64 | ULONG requiredLength = 0, bytes=0; 65 | HANDLE file; 66 | ULONG i =0; 67 | KEYBOARD_ATTRIBUTES kbdattrib; 68 | 69 | UNREFERENCED_PARAMETER(argc); 70 | UNREFERENCED_PARAMETER(argv); 71 | 72 | // 73 | // Open a handle to the device interface information set of all 74 | // present toaster class interfaces. 75 | // 76 | 77 | hardwareDeviceInfo = SetupDiGetClassDevs ( 78 | (LPGUID)&GUID_DEVINTERFACE_KBFILTER, 79 | NULL, // Define no enumerator (global) 80 | NULL, // Define no 81 | (DIGCF_PRESENT | // Only Devices present 82 | DIGCF_DEVICEINTERFACE)); // Function class devices. 83 | if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) 84 | { 85 | printf("SetupDiGetClassDevs failed: %x\n", GetLastError()); 86 | return 0; 87 | } 88 | 89 | deviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); 90 | 91 | printf("\nList of KBFILTER Device Interfaces\n"); 92 | printf("---------------------------------\n"); 93 | 94 | i = 0; 95 | 96 | // 97 | // Enumerate devices of toaster class 98 | // 99 | 100 | do { 101 | if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, 102 | 0, // No care about specific PDOs 103 | (LPGUID)&GUID_DEVINTERFACE_KBFILTER, 104 | i, // 105 | &deviceInterfaceData)) { 106 | 107 | if(deviceInterfaceDetailData) { 108 | free (deviceInterfaceDetailData); 109 | deviceInterfaceDetailData = NULL; 110 | } 111 | 112 | // 113 | // Allocate a function class device data structure to 114 | // receive the information about this particular device. 115 | // 116 | 117 | // 118 | // First find out required length of the buffer 119 | // 120 | 121 | if(!SetupDiGetDeviceInterfaceDetail ( 122 | hardwareDeviceInfo, 123 | &deviceInterfaceData, 124 | NULL, // probing so no output buffer yet 125 | 0, // probing so output buffer length of zero 126 | &requiredLength, 127 | NULL)) { // not interested in the specific dev-node 128 | if(ERROR_INSUFFICIENT_BUFFER != GetLastError()) { 129 | printf("SetupDiGetDeviceInterfaceDetail failed %d\n", GetLastError()); 130 | SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); 131 | return FALSE; 132 | } 133 | 134 | } 135 | 136 | predictedLength = requiredLength; 137 | 138 | deviceInterfaceDetailData = malloc (predictedLength); 139 | 140 | if(deviceInterfaceDetailData) { 141 | deviceInterfaceDetailData->cbSize = 142 | sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); 143 | } else { 144 | printf("Couldn't allocate %d bytes for device interface details.\n", predictedLength); 145 | SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); 146 | return FALSE; 147 | } 148 | 149 | 150 | if (! SetupDiGetDeviceInterfaceDetail ( 151 | hardwareDeviceInfo, 152 | &deviceInterfaceData, 153 | deviceInterfaceDetailData, 154 | predictedLength, 155 | &requiredLength, 156 | NULL)) { 157 | printf("Error in SetupDiGetDeviceInterfaceDetail\n"); 158 | SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); 159 | free (deviceInterfaceDetailData); 160 | return FALSE; 161 | } 162 | printf("%d) %s\n", ++i, 163 | deviceInterfaceDetailData->DevicePath); 164 | } 165 | else if (ERROR_NO_MORE_ITEMS != GetLastError()) { 166 | free (deviceInterfaceDetailData); 167 | deviceInterfaceDetailData = NULL; 168 | continue; 169 | } 170 | else 171 | break; 172 | 173 | } WHILE (TRUE); 174 | 175 | 176 | SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); 177 | 178 | if(!deviceInterfaceDetailData) 179 | { 180 | printf("No device interfaces present\n"); 181 | return 0; 182 | } 183 | 184 | // 185 | // Open the last toaster device interface 186 | // 187 | 188 | printf("\nOpening the last interface:\n %s\n", 189 | deviceInterfaceDetailData->DevicePath); 190 | 191 | file = CreateFile ( deviceInterfaceDetailData->DevicePath, 192 | GENERIC_READ | GENERIC_WRITE, 193 | 0, 194 | NULL, // no SECURITY_ATTRIBUTES structure 195 | OPEN_EXISTING, // No special create flags 196 | 0, // No special attributes 197 | NULL); 198 | 199 | if (INVALID_HANDLE_VALUE == file) { 200 | printf("Error in CreateFile: %x", GetLastError()); 201 | free (deviceInterfaceDetailData); 202 | return 0; 203 | } 204 | 205 | // 206 | // Send an IOCTL to retrive the keyboard attributes 207 | // These are cached in the kbfiltr 208 | // 209 | 210 | if (!DeviceIoControl (file, 211 | IOCTL_KBFILTR_GET_KEYBOARD_ATTRIBUTES, 212 | NULL, 0, 213 | &kbdattrib, sizeof(kbdattrib), 214 | &bytes, NULL)) { 215 | printf("Retrieve Keyboard Attributes request failed:0x%x\n", GetLastError()); 216 | free (deviceInterfaceDetailData); 217 | CloseHandle(file); 218 | return 0; 219 | } 220 | 221 | printf("\nKeyboard Attributes:\n" 222 | " KeyboardMode: 0x%x\n" 223 | " NumberOfFunctionKeys: 0x%x\n" 224 | " NumberOfIndicators: 0x%x\n" 225 | " NumberOfKeysTotal: 0x%x\n" 226 | " InputDataQueueLength: 0x%x\n", 227 | kbdattrib.KeyboardMode, 228 | kbdattrib.NumberOfFunctionKeys, 229 | kbdattrib.NumberOfIndicators, 230 | kbdattrib.NumberOfKeysTotal, 231 | kbdattrib.InputDataQueueLength); 232 | 233 | free (deviceInterfaceDetailData); 234 | CloseHandle(file); 235 | return 0; 236 | } 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /croskbreload/croskbreload.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {25357b70-bb72-4b8e-9334-19f6ba5999bb} 25 | croskbreload 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;hid.lib;%(AdditionalDependencies) 96 | 97 | 98 | 99 | 100 | Level3 101 | true 102 | true 103 | true 104 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | 107 | 108 | Console 109 | true 110 | true 111 | true 112 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;hid.lib;%(AdditionalDependencies) 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;hid.lib;%(AdditionalDependencies) 126 | 127 | 128 | 129 | 130 | Level3 131 | true 132 | true 133 | true 134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 135 | true 136 | 137 | 138 | Console 139 | true 140 | true 141 | true 142 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;setupapi.lib;hid.lib;%(AdditionalDependencies) 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /sys/croskeyboard.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {7227DB35-883A-4EF0-B083-1698CFEF85A3} 23 | $(MSBuildProjectName) 24 | 1 25 | Debug 26 | Win32 27 | {878C17AE-8F1D-43E4-9F8E-0321CA186895} 28 | $(LatestTargetPlatformVersion) 29 | croskeyboard 30 | 31 | 32 | 33 | Windows10 34 | False 35 | Universal 36 | KMDF 37 | WindowsKernelModeDriver10.0 38 | Driver 39 | 40 | 41 | Windows10 42 | True 43 | Universal 44 | KMDF 45 | WindowsKernelModeDriver10.0 46 | Driver 47 | 48 | 49 | Windows10 50 | False 51 | Universal 52 | KMDF 53 | WindowsKernelModeDriver10.0 54 | Driver 55 | 56 | 57 | Windows10 58 | True 59 | Universal 60 | KMDF 61 | WindowsKernelModeDriver10.0 62 | Driver 63 | 64 | 65 | 66 | $(IntDir) 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | croskeyboard 83 | 84 | 85 | croskeyboard 86 | 87 | 88 | croskeyboard 89 | 90 | 91 | croskeyboard 92 | 93 | 94 | 95 | true 96 | Level4 97 | 98 | 99 | 100 | 101 | %(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\rtlver.lib 102 | 103 | 104 | sha256 105 | 106 | 107 | 4.0.0 108 | 109 | 110 | 111 | 112 | true 113 | Level4 114 | 115 | 116 | 117 | 118 | %(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\rtlver.lib 119 | 120 | 121 | sha256 122 | 123 | 124 | 4.0.0 125 | 126 | 127 | 128 | 129 | true 130 | Level4 131 | 132 | 133 | 134 | 135 | %(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\rtlver.lib 136 | 137 | 138 | sha256 139 | 140 | 141 | 4.0.0 142 | 143 | 144 | 145 | 146 | true 147 | Level4 148 | 149 | 150 | 151 | 152 | %(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\rtlver.lib 153 | 154 | 155 | sha256 156 | 157 | 158 | 4.0.0 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /croskbreload/client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "croskbhid.h" 8 | 9 | #if __GNUC__ 10 | #define __in 11 | #define __in_ecount(x) 12 | typedef void* PVOID; 13 | typedef PVOID HDEVINFO; 14 | WINHIDSDI BOOL WINAPI HidD_SetOutputReport(HANDLE, PVOID, ULONG); 15 | #endif 16 | 17 | typedef struct _croskbhid_client_t 18 | { 19 | HANDLE hSettings; 20 | } croskbhid_client_t; 21 | 22 | // 23 | // Function prototypes 24 | // 25 | 26 | HANDLE 27 | SearchMatchingHwID( 28 | USHORT vendorID, 29 | USHORT productID, 30 | USAGE myUsagePage, 31 | USAGE myUsage 32 | ); 33 | 34 | HANDLE 35 | OpenDeviceInterface( 36 | HDEVINFO HardwareDeviceInfo, 37 | PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, 38 | USHORT vendorID, 39 | USHORT productID, 40 | USAGE myUsagePage, 41 | USAGE myUsage 42 | ); 43 | 44 | BOOLEAN 45 | CheckIfOurDevice( 46 | HANDLE file, 47 | USHORT vendorID, 48 | USHORT productID, 49 | USAGE myUsagePage, 50 | USAGE myUsage 51 | ); 52 | 53 | BOOL 54 | HidOutput( 55 | BOOL useSetOutputReport, 56 | HANDLE file, 57 | PCHAR buffer, 58 | ULONG bufferSize 59 | ); 60 | 61 | // 62 | // Copied this structure from hidport.h 63 | // 64 | 65 | typedef struct _HID_DEVICE_ATTRIBUTES { 66 | 67 | ULONG Size; 68 | // 69 | // sizeof (struct _HID_DEVICE_ATTRIBUTES) 70 | // 71 | // 72 | // Vendor ids of this hid device 73 | // 74 | USHORT VendorID; 75 | USHORT ProductID; 76 | USHORT VersionNumber; 77 | USHORT Reserved[11]; 78 | 79 | } HID_DEVICE_ATTRIBUTES, * PHID_DEVICE_ATTRIBUTES; 80 | 81 | static USHORT TpVendorID = 0; 82 | 83 | USHORT getVendorID() { 84 | return TpVendorID; 85 | } 86 | 87 | // 88 | // Implementation 89 | // 90 | 91 | pcroskbhid_client croskbhid_alloc(void) 92 | { 93 | return (pcroskbhid_client)malloc(sizeof(croskbhid_client_t)); 94 | } 95 | 96 | void croskbhid_free(pcroskbhid_client croskbhid) 97 | { 98 | free(croskbhid); 99 | } 100 | 101 | BOOL croskbhid_connect(pcroskbhid_client croskbhid) 102 | { 103 | // 104 | // Find the HID devices 105 | // 106 | 107 | croskbhid->hSettings = SearchMatchingHwID(CROSKBHIDREMAPPER_VID, CROSKBHIDREMAPPER_PID, 0xff00, 0x0003); 108 | if (croskbhid->hSettings == INVALID_HANDLE_VALUE || croskbhid->hSettings == NULL) 109 | { 110 | croskbhid_disconnect(croskbhid); 111 | return FALSE; 112 | } 113 | 114 | // 115 | // Set the buffer count to 10 on the setting HID 116 | // 117 | 118 | if (!HidD_SetNumInputBuffers(croskbhid->hSettings, 10)) 119 | { 120 | printf("failed HidD_SetNumInputBuffers %d\n", GetLastError()); 121 | croskbhid_disconnect(croskbhid); 122 | return FALSE; 123 | } 124 | return TRUE; 125 | } 126 | 127 | void croskbhid_disconnect(pcroskbhid_client croskbhid) 128 | { 129 | if (croskbhid->hSettings != NULL) 130 | CloseHandle(croskbhid->hSettings); 131 | croskbhid->hSettings = NULL; 132 | } 133 | 134 | BOOL croskbhid_read_keyboard(pcroskbhid_client vmulti, CrosKBHIDRemapperSettingsReport* pReport) 135 | { 136 | ULONG bytesRead; 137 | 138 | // 139 | // Read the report 140 | // 141 | 142 | if (!ReadFile(vmulti->hSettings, pReport, sizeof(CrosKBHIDRemapperSettingsReport), &bytesRead, NULL)) 143 | { 144 | printf("failed ReadFile %d\n", GetLastError()); 145 | return FALSE; 146 | } 147 | 148 | return TRUE; 149 | } 150 | 151 | BOOL croskbhid_write_keyboard(pcroskbhid_client croskbhid, CrosKBHIDRemapperSettingsReport* pReport) 152 | { 153 | ULONG bytesWritten; 154 | 155 | // 156 | // Write the report 157 | // 158 | 159 | if (!WriteFile(croskbhid->hSettings, pReport, sizeof(CrosKBHIDRemapperSettingsReport), &bytesWritten, NULL)) 160 | { 161 | printf("failed WriteFile %d\n", GetLastError()); 162 | return FALSE; 163 | } 164 | 165 | return TRUE; 166 | } 167 | 168 | HANDLE 169 | SearchMatchingHwID( 170 | USHORT vendorID, 171 | USHORT productID, 172 | USAGE myUsagePage, 173 | USAGE myUsage 174 | ) 175 | { 176 | HDEVINFO hardwareDeviceInfo; 177 | SP_DEVICE_INTERFACE_DATA deviceInterfaceData; 178 | SP_DEVINFO_DATA devInfoData; 179 | GUID hidguid; 180 | int i; 181 | 182 | HidD_GetHidGuid(&hidguid); 183 | 184 | hardwareDeviceInfo = 185 | SetupDiGetClassDevs((LPGUID)&hidguid, 186 | NULL, 187 | NULL, // Define no 188 | (DIGCF_PRESENT | 189 | DIGCF_INTERFACEDEVICE)); 190 | 191 | if (INVALID_HANDLE_VALUE == hardwareDeviceInfo) 192 | { 193 | printf("SetupDiGetClassDevs failed: %x\n", GetLastError()); 194 | return INVALID_HANDLE_VALUE; 195 | } 196 | 197 | deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 198 | 199 | devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 200 | 201 | // 202 | // Enumerate devices of this interface class 203 | // 204 | 205 | printf("\n....looking for our HID device (with UP=0x%x " 206 | "and Usage=0x%x)\n", myUsagePage, myUsage); 207 | 208 | for (i = 0; SetupDiEnumDeviceInterfaces(hardwareDeviceInfo, 209 | 0, // No care about specific PDOs 210 | (LPGUID)&hidguid, 211 | i, // 212 | &deviceInterfaceData); 213 | i++) 214 | { 215 | 216 | // 217 | // Open the device interface and Check if it is our device 218 | // by matching the Usage page and Usage from Hid_Caps. 219 | // If this is our device then send the hid request. 220 | // 221 | 222 | HANDLE file = OpenDeviceInterface(hardwareDeviceInfo, &deviceInterfaceData, vendorID, productID, myUsagePage, myUsage); 223 | 224 | if (file != INVALID_HANDLE_VALUE) 225 | { 226 | SetupDiDestroyDeviceInfoList(hardwareDeviceInfo); 227 | return file; 228 | } 229 | 230 | // 231 | //device was not found so loop around. 232 | // 233 | 234 | } 235 | 236 | printf("Failure: Could not find our HID device \n"); 237 | 238 | SetupDiDestroyDeviceInfoList(hardwareDeviceInfo); 239 | 240 | return INVALID_HANDLE_VALUE; 241 | } 242 | 243 | HANDLE 244 | OpenDeviceInterface( 245 | HDEVINFO hardwareDeviceInfo, 246 | PSP_DEVICE_INTERFACE_DATA deviceInterfaceData, 247 | USHORT vendorID, 248 | USHORT productID, 249 | USAGE myUsagePage, 250 | USAGE myUsage 251 | ) 252 | { 253 | PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; 254 | 255 | DWORD predictedLength = 0; 256 | DWORD requiredLength = 0; 257 | HANDLE file = INVALID_HANDLE_VALUE; 258 | 259 | SetupDiGetDeviceInterfaceDetail( 260 | hardwareDeviceInfo, 261 | deviceInterfaceData, 262 | NULL, // probing so no output buffer yet 263 | 0, // probing so output buffer length of zero 264 | &requiredLength, 265 | NULL 266 | ); // not interested in the specific dev-node 267 | 268 | predictedLength = requiredLength; 269 | 270 | deviceInterfaceDetailData = 271 | (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(predictedLength); 272 | 273 | if (!deviceInterfaceDetailData) 274 | { 275 | printf("Error: OpenDeviceInterface: malloc failed\n"); 276 | goto cleanup; 277 | } 278 | 279 | deviceInterfaceDetailData->cbSize = 280 | sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); 281 | 282 | if (!SetupDiGetDeviceInterfaceDetail( 283 | hardwareDeviceInfo, 284 | deviceInterfaceData, 285 | deviceInterfaceDetailData, 286 | predictedLength, 287 | &requiredLength, 288 | NULL)) 289 | { 290 | printf("Error: SetupDiGetInterfaceDeviceDetail failed\n"); 291 | free(deviceInterfaceDetailData); 292 | goto cleanup; 293 | } 294 | 295 | file = CreateFile(deviceInterfaceDetailData->DevicePath, 296 | GENERIC_READ | GENERIC_WRITE, 297 | FILE_SHARE_READ | FILE_SHARE_WRITE, 298 | NULL, // no SECURITY_ATTRIBUTES structure 299 | OPEN_EXISTING, // No special create flags 300 | 0, // No special attributes 301 | NULL); // No template file 302 | 303 | if (INVALID_HANDLE_VALUE == file) { 304 | printf("Error: CreateFile failed: %d\n", GetLastError()); 305 | goto cleanup; 306 | } 307 | 308 | if (CheckIfOurDevice(file, vendorID, productID, myUsagePage, myUsage)) { 309 | 310 | goto cleanup; 311 | 312 | } 313 | 314 | CloseHandle(file); 315 | 316 | file = INVALID_HANDLE_VALUE; 317 | 318 | cleanup: 319 | 320 | free(deviceInterfaceDetailData); 321 | 322 | return file; 323 | 324 | } 325 | 326 | 327 | BOOLEAN 328 | CheckIfOurDevice( 329 | HANDLE file, 330 | USHORT vendorID, 331 | USHORT productID, 332 | USAGE myUsagePage, 333 | USAGE myUsage) 334 | { 335 | PHIDP_PREPARSED_DATA Ppd = NULL; // The opaque parser info describing this device 336 | HIDD_ATTRIBUTES Attributes; // The Attributes of this hid device. 337 | HIDP_CAPS Caps; // The Capabilities of this hid device. 338 | BOOLEAN result = FALSE; 339 | 340 | if (!HidD_GetPreparsedData(file, &Ppd)) 341 | { 342 | printf("Error: HidD_GetPreparsedData failed \n"); 343 | goto cleanup; 344 | } 345 | 346 | if (!HidD_GetAttributes(file, &Attributes)) 347 | { 348 | printf("Error: HidD_GetAttributes failed \n"); 349 | goto cleanup; 350 | } 351 | 352 | if (Attributes.VendorID == vendorID && Attributes.ProductID == productID) 353 | { 354 | TpVendorID = Attributes.VendorID; 355 | 356 | if (!HidP_GetCaps(Ppd, &Caps)) 357 | { 358 | printf("Error: HidP_GetCaps failed \n"); 359 | goto cleanup; 360 | } 361 | 362 | if ((Caps.UsagePage == myUsagePage) && (Caps.Usage == myUsage)) 363 | { 364 | printf("Success: Found my device.. \n"); 365 | result = TRUE; 366 | } 367 | } 368 | 369 | cleanup: 370 | 371 | if (Ppd != NULL) 372 | { 373 | HidD_FreePreparsedData(Ppd); 374 | } 375 | 376 | return result; 377 | } 378 | 379 | BOOL 380 | HidOutput( 381 | BOOL useSetOutputReport, 382 | HANDLE file, 383 | PCHAR buffer, 384 | ULONG bufferSize 385 | ) 386 | { 387 | ULONG bytesWritten; 388 | if (useSetOutputReport) 389 | { 390 | // 391 | // Send Hid report thru HidD_SetOutputReport API 392 | // 393 | 394 | if (!HidD_SetOutputReport(file, buffer, bufferSize)) 395 | { 396 | printf("failed HidD_SetOutputReport %d\n", GetLastError()); 397 | return FALSE; 398 | } 399 | } 400 | else 401 | { 402 | if (!WriteFile(file, buffer, bufferSize, &bytesWritten, NULL)) 403 | { 404 | printf("failed WriteFile %d\n", GetLastError()); 405 | return FALSE; 406 | } 407 | } 408 | 409 | return TRUE; 410 | } -------------------------------------------------------------------------------- /sys/croskeyboard.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) 1997 Microsoft Corporation 3 | 4 | Module Name: 5 | 6 | kbfilter.h 7 | 8 | Abstract: 9 | 10 | This module contains the common private declarations for the keyboard 11 | packet filter 12 | 13 | Environment: 14 | 15 | kernel mode only 16 | 17 | --*/ 18 | 19 | #ifndef KBFILTER_H 20 | #define KBFILTER_H 21 | 22 | #pragma warning(disable:4201) 23 | 24 | #include "ntddk.h" 25 | #include "kbdmou.h" 26 | #include 27 | #include 28 | 29 | #pragma warning(default:4201) 30 | 31 | #include 32 | 33 | #define NTSTRSAFE_LIB 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #include "public.h" 41 | 42 | #define KBFILTER_POOL_TAG (ULONG) 'tlfK' 43 | 44 | #if DBG 45 | 46 | #define TRAP() DbgBreakPoint() 47 | 48 | #define DebugPrint(_x_) DbgPrint _x_ 49 | 50 | #else // DBG 51 | 52 | #define TRAP() 53 | 54 | #define DebugPrint(_x_) 55 | 56 | #endif 57 | 58 | #define MIN(_A_,_B_) (((_A_) < (_B_)) ? (_A_) : (_B_)) 59 | 60 | #define REPORTID_MEDIA 0x08 61 | 62 | #define CROSKBHID_BRIGHTNESS_UP 0x01 63 | #define CROSKBHID_BRIGHTNESS_DN 0x02 64 | #define CROSKBHID_KBLT_UP 0x04 65 | #define CROSKBHID_KBLT_DN 0x08 66 | #define CROSKBHID_KBLT_TOGGLE 0x10 67 | 68 | #pragma pack(1) 69 | typedef struct _CROSKBHIDREMAPPER_MEDIA_REPORT 70 | { 71 | 72 | BYTE ReportID; 73 | 74 | BYTE ControlCode; 75 | 76 | BYTE Reserved; 77 | 78 | } CrosKBHIDRemapperMediaReport; 79 | 80 | #pragma pack() 81 | 82 | typedef struct KeySetting { 83 | USHORT MakeCode; 84 | USHORT Flags; 85 | } KeySetting, *PKeySetting; 86 | 87 | typedef enum { 88 | CSVivaldiRequestEndpointRegister, 89 | CSVivaldiRequestLoadSettings, 90 | CSVivaldiRequestUpdateTabletMode = 0x102 91 | } CSVivaldiRequest; 92 | 93 | #include 94 | typedef struct CSVivaldiSettingsArg { 95 | UINT32 argSz; 96 | CSVivaldiRequest settingsRequest; 97 | union args { 98 | struct { 99 | UINT8 functionRowCount; 100 | KeySetting functionRowKeys[16]; 101 | } settings; 102 | struct { 103 | UINT8 tabletmode; 104 | } tabletmode; 105 | } args; 106 | } CSVivaldiSettingsArg, *PCSVivaldiSettingsArg; 107 | #include 108 | 109 | typedef NTSTATUS 110 | (*PPROCESS_HID_REPORT)( 111 | IN PVOID Context, 112 | IN PVOID ReportBuffer, 113 | IN ULONG ReportBufferLen, 114 | OUT size_t* BytesWritten 115 | ); 116 | 117 | typedef BOOLEAN 118 | (*PREGISTER_CALLBACK)( 119 | IN PVOID Context, 120 | IN PVOID HIDContext, 121 | IN PPROCESS_HID_REPORT HidReportProcessCallback 122 | ); 123 | 124 | typedef BOOLEAN 125 | (*PUNREGISTER_CALLBACK)( 126 | IN PVOID Context 127 | ); 128 | 129 | typedef void 130 | (*PRELOAD_SETTINGS)( 131 | IN PVOID Context 132 | ); 133 | 134 | DEFINE_GUID(GUID_CROSKBHID_INTERFACE_STANDARD, 135 | 0x74a15a7c, 0x82b5, 0x11ed, 0x8c, 0xd5, 0x00, 0x15, 0x5d, 0xa4, 0x4e, 0x91); 136 | 137 | typedef struct _CROSKBHID_INTERFACE_STANDARD { 138 | INTERFACE InterfaceHeader; 139 | PREGISTER_CALLBACK RegisterCallback; 140 | PUNREGISTER_CALLBACK UnregisterCallback; 141 | PRELOAD_SETTINGS ReloadSettings; 142 | } CROSKBHID_INTERFACE_STANDARD, *PCROSKBHID_INTERFACE_STANDARD; 143 | 144 | #define INTFLAG_NEW 0x1 145 | #define INTFLAG_REMOVED 0x2 146 | 147 | #include 148 | 149 | typedef struct RemapCfgKey { 150 | USHORT MakeCode; 151 | USHORT Flags; 152 | } RemapCfgKey, * PRemapCfgKey; 153 | 154 | typedef enum RemapCfgOverride { 155 | RemapCfgOverrideAutoDetect, 156 | RemapCfgOverrideEnable, 157 | RemapCfgOverrideDisable 158 | } RemapCfgOverride, *PRemapCfgOverride; 159 | 160 | typedef enum RemapCfgKeyState { 161 | RemapCfgKeyStateNoDetect, 162 | RemapCfgKeyStateEnforce, 163 | RemapCfgKeyStateEnforceNot 164 | } RemapCfgKeyState, *PRemapCfgKeyState; 165 | 166 | typedef struct RemapCfg { 167 | RemapCfgKeyState LeftCtrl; 168 | RemapCfgKeyState LeftAlt; 169 | RemapCfgKeyState Search; 170 | RemapCfgKeyState Assistant; 171 | RemapCfgKeyState LeftShift; 172 | RemapCfgKeyState RightCtrl; 173 | RemapCfgKeyState RightAlt; 174 | RemapCfgKeyState RightShift; 175 | RemapCfgKey originalKey; 176 | BOOLEAN remapVivaldiToFnKeys; 177 | RemapCfgKey remappedKey; 178 | RemapCfgKey additionalKeys[8]; 179 | } RemapCfg, * PRemapCfg; 180 | 181 | typedef struct RemapCfgs { 182 | UINT32 magic; 183 | UINT32 remappings; 184 | BOOLEAN FlipSearchAndAssistantOnPixelbook; 185 | RemapCfgOverride HasAssistantKey; 186 | RemapCfgOverride IsNonChromeEC; 187 | RemapCfg cfg[1]; 188 | } RemapCfgs, * PRemapCfgs; 189 | #include 190 | 191 | typedef struct KeyStruct { 192 | USHORT MakeCode; 193 | USHORT Flags; 194 | USHORT InternalFlags; 195 | } KeyStruct, * PKeyStruct; 196 | 197 | typedef struct RemappedKeyStruct { 198 | struct KeyStruct origKey; 199 | struct KeyStruct remappedKey; 200 | } RemappedKeyStruct, * PRemappedKeyStruct; 201 | 202 | #define MAX_CURRENT_KEYS 20 203 | 204 | typedef struct _DEVICE_EXTENSION 205 | { 206 | WDFDEVICE WdfDevice; 207 | 208 | // 209 | // Queue for handling requests that come from the rawPdo 210 | // 211 | WDFQUEUE rawPdoQueue; 212 | 213 | // 214 | // Number of creates sent down 215 | // 216 | LONG EnableCount; 217 | 218 | // 219 | // The real connect data that this driver reports to 220 | // 221 | CONNECT_DATA UpperConnectData; 222 | 223 | // 224 | // Previous initialization and hook routines (and context) 225 | // 226 | PVOID UpperContext; 227 | PI8042_KEYBOARD_INITIALIZATION_ROUTINE UpperInitializationRoutine; 228 | PI8042_KEYBOARD_ISR UpperIsrHook; 229 | 230 | // 231 | // Write function from within KbFilter_IsrHook 232 | // 233 | IN PI8042_ISR_WRITE_PORT IsrWritePort; 234 | 235 | // 236 | // Queue the current packet (ie the one passed into KbFilter_IsrHook) 237 | // 238 | IN PI8042_QUEUE_PACKET QueueKeyboardPacket; 239 | 240 | // 241 | // Context for IsrWritePort, QueueKeyboardPacket 242 | // 243 | IN PVOID CallContext; 244 | 245 | // 246 | // Cached Keyboard Attributes 247 | // 248 | KEYBOARD_ATTRIBUTES KeyboardAttributes; 249 | 250 | BOOLEAN tabletMode; 251 | BOOLEAN hasAssistantKey; 252 | BOOLEAN isNonChromeEC; 253 | 254 | UINT8 legacyTopRowKeys[10]; 255 | UINT8 legacyVivaldi[10]; 256 | 257 | UINT8 functionRowCount; 258 | KeySetting functionRowKeys[16]; 259 | 260 | PRemapCfgs remapCfgs; 261 | 262 | BOOLEAN LeftCtrlPressed; 263 | BOOLEAN LeftAltPressed; 264 | BOOLEAN LeftShiftPressed; 265 | BOOLEAN AssistantPressed; 266 | BOOLEAN SearchPressed; 267 | 268 | BOOLEAN RightCtrlPressed; 269 | BOOLEAN RightAltPressed; 270 | BOOLEAN RightShiftPressed; 271 | 272 | KeyStruct currentKeys[MAX_CURRENT_KEYS]; 273 | KeyStruct lastKeyPressed; 274 | int numKeysPressed; 275 | 276 | RemappedKeyStruct remappedKeys[MAX_CURRENT_KEYS]; 277 | int numRemaps; 278 | 279 | PCALLBACK_OBJECT CSSettingsCallback; 280 | PVOID CSSettingsCallbackObj; 281 | 282 | PVOID HIDContext; 283 | PPROCESS_HID_REPORT HidReportProcessCallback; 284 | } DEVICE_EXTENSION, *PDEVICE_EXTENSION; 285 | 286 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, 287 | FilterGetData) 288 | 289 | 290 | typedef struct _WORKER_ITEM_CONTEXT { 291 | 292 | WDFREQUEST Request; 293 | WDFIOTARGET IoTarget; 294 | 295 | } WORKER_ITEM_CONTEXT, *PWORKER_ITEM_CONTEXT; 296 | 297 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WORKER_ITEM_CONTEXT, GetWorkItemContext) 298 | 299 | // 300 | // Prototypes 301 | // 302 | DRIVER_INITIALIZE DriverEntry; 303 | 304 | EVT_WDF_DRIVER_DEVICE_ADD KbFilter_EvtDeviceAdd; 305 | EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL KbFilter_EvtIoDeviceControlForRawPdo; 306 | EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL KbFilter_EvtIoDeviceControlFromRawPdo; 307 | EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL KbFilter_EvtIoInternalDeviceControl; 308 | 309 | NTSTATUS 310 | KbFilter_InitializationRoutine( 311 | IN PVOID InitializationContext, 312 | IN PVOID SynchFuncContext, 313 | IN PI8042_SYNCH_READ_PORT ReadPort, 314 | IN PI8042_SYNCH_WRITE_PORT WritePort, 315 | OUT PBOOLEAN TurnTranslationOn 316 | ); 317 | 318 | BOOLEAN 319 | KbFilter_IsrHook( 320 | PVOID IsrContext, 321 | PKEYBOARD_INPUT_DATA CurrentInput, 322 | POUTPUT_PACKET CurrentOutput, 323 | UCHAR StatusByte, 324 | PUCHAR DataByte, 325 | PBOOLEAN ContinueProcessing, 326 | PKEYBOARD_SCAN_STATE ScanState 327 | ); 328 | 329 | VOID 330 | KbFilter_ServiceCallback( 331 | IN PDEVICE_OBJECT DeviceObject, 332 | IN PKEYBOARD_INPUT_DATA InputDataStart, 333 | IN PKEYBOARD_INPUT_DATA InputDataEnd, 334 | IN OUT PULONG InputDataConsumed 335 | ); 336 | 337 | EVT_WDF_REQUEST_COMPLETION_ROUTINE 338 | KbFilterRequestCompletionRoutine; 339 | 340 | 341 | // 342 | // IOCTL Related defintions 343 | // 344 | 345 | // 346 | // Used to identify kbfilter bus. This guid is used as the enumeration string 347 | // for the device id. 348 | DEFINE_GUID(GUID_BUS_KBFILTER, 349 | 0xa65c87f9, 0xbe02, 0x4ed9, 0x92, 0xec, 0x1, 0x2d, 0x41, 0x61, 0x69, 0xfa); 350 | // {A65C87F9-BE02-4ed9-92EC-012D416169FA} 351 | 352 | DEFINE_GUID(GUID_DEVINTERFACE_KBFILTER, 353 | 0x3fb7299d, 0x6847, 0x4490, 0xb0, 0xc9, 0x99, 0xe0, 0x98, 0x6a, 0xb8, 0x86); 354 | // {3FB7299D-6847-4490-B0C9-99E0986AB886} 355 | 356 | 357 | #define KBFILTR_DEVICE_ID L"{A65C87F9-BE02-4ed9-92EC-012D416169FA}\\KeyboardFilter\0" 358 | 359 | 360 | typedef struct _RPDO_DEVICE_DATA 361 | { 362 | 363 | ULONG InstanceNo; 364 | 365 | // 366 | // Queue of the parent device we will forward requests to 367 | // 368 | WDFQUEUE ParentQueue; 369 | 370 | } RPDO_DEVICE_DATA, *PRPDO_DEVICE_DATA; 371 | 372 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(RPDO_DEVICE_DATA, PdoGetData) 373 | 374 | 375 | NTSTATUS 376 | KbFiltr_CreateRawPdo( 377 | WDFDEVICE Device, 378 | ULONG InstanceNo 379 | ); 380 | 381 | NTSTATUS 382 | KbFiltr_CreateHIDPdo( 383 | WDFDEVICE Device, 384 | ULONG InstanceNo 385 | ); 386 | 387 | 388 | 389 | #endif // KBFILTER_H 390 | 391 | -------------------------------------------------------------------------------- /croskbhidremapper/croskbhidremapper/croskbhidremapper.h: -------------------------------------------------------------------------------- 1 | #if !defined(_CROSKBHIDREMAPPER_H_) 2 | #define _CROSKBHIDREMAPPER_H_ 3 | 4 | #pragma warning(disable:4200) // suppress nameless struct/union warning 5 | #pragma warning(disable:4201) // suppress nameless struct/union warning 6 | #pragma warning(disable:4214) // suppress bit field types other than int warning 7 | #include 8 | #include 9 | 10 | #pragma warning(default:4200) 11 | #pragma warning(default:4201) 12 | #pragma warning(default:4214) 13 | #include 14 | 15 | #pragma warning(disable:4201) // suppress nameless struct/union warning 16 | #pragma warning(disable:4214) // suppress bit field types other than int warning 17 | #include 18 | 19 | #include "hidcommon.h" 20 | #include "spb.h" 21 | 22 | extern "C" 23 | 24 | NTSTATUS 25 | DriverEntry( 26 | _In_ PDRIVER_OBJECT pDriverObject, 27 | _In_ PUNICODE_STRING pRegistryPath 28 | ); 29 | 30 | EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; 31 | EVT_WDF_OBJECT_CONTEXT_CLEANUP OnDriverCleanup; 32 | 33 | // 34 | // String definitions 35 | // 36 | 37 | #define DRIVERNAME "croskbhidremapper.sys: " 38 | 39 | #define CROSKBHIDREMAPPER_POOL_TAG (ULONG) 'bkrC' 40 | #define CROSKBHIDREMAPPER_HARDWARE_IDS L"CoolStar\\CrosKBHIDRemapper\0\0" 41 | #define CROSKBHIDREMAPPER_HARDWARE_IDS_LENGTH sizeof(CROSKBHIDREMAPPER_HARDWARE_IDS) 42 | 43 | #define NTDEVICE_NAME_STRING L"\\Device\\CrosKBHIDRemapper" 44 | #define SYMBOLIC_NAME_STRING L"\\DosDevices\\CrosKBHIDRemapper" 45 | // 46 | // This is the default report descriptor for the Hid device provided 47 | // by the mini driver in response to IOCTL_HID_GET_REPORT_DESCRIPTOR. 48 | // 49 | 50 | typedef UCHAR HID_REPORT_DESCRIPTOR, *PHID_REPORT_DESCRIPTOR; 51 | 52 | #ifdef DESCRIPTOR_DEF 53 | HID_REPORT_DESCRIPTOR DefaultReportDescriptor[] = { 54 | // 55 | // Keyboard report starts here 56 | // 57 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 58 | 0x09, 0x06, // USAGE (Keyboard) 59 | 0xa1, 0x01, // COLLECTION (Application) 60 | 0x85, REPORTID_KEYBOARD, // REPORT_ID (Keyboard) 61 | 0x05, 0x07, // USAGE_PAGE (Keyboard) 62 | 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 63 | 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 64 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 65 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 66 | 0x75, 0x01, // REPORT_SIZE (1) 67 | 0x95, 0x08, // REPORT_COUNT (8) 68 | 0x81, 0x02, // INPUT (Data,Var,Abs) 69 | 0x95, 0x01, // REPORT_COUNT (1) 70 | 0x75, 0x08, // REPORT_SIZE (8) 71 | 0x81, 0x03, // INPUT (Cnst,Var,Abs) 72 | 0x95, 0x05, // REPORT_COUNT (5) 73 | 0x75, 0x01, // REPORT_SIZE (1) 74 | 0x05, 0x08, // USAGE_PAGE (LEDs) 75 | 0x19, 0x01, // USAGE_MINIMUM (Num Lock) 76 | 0x29, 0x05, // USAGE_MAXIMUM (Kana) 77 | 0x91, 0x02, // OUTPUT (Data,Var,Abs) 78 | 0x95, 0x01, // REPORT_COUNT (1) 79 | 0x75, 0x03, // REPORT_SIZE (3) 80 | 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) 81 | 0x95, 0x06, // REPORT_COUNT (6) 82 | 0x75, 0x08, // REPORT_SIZE (8) 83 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 84 | 0x25, 0x65, // LOGICAL_MAXIMUM (101) 85 | 0x05, 0x07, // USAGE_PAGE (Keyboard) 86 | 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 87 | 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 88 | 0x81, 0x00, // INPUT (Data,Ary,Abs) 89 | 0xc0, // END_COLLECTION 90 | 91 | 0x05, 0x0C, /* Usage Page (Consumer Devices) */ 92 | 0x09, 0x01, /* Usage (Consumer Control) */ 93 | 0xA1, 0x01, /* Collection (Application) */ 94 | 0x85, REPORTID_MEDIA, /* Report ID=2 */ 95 | 0x05, 0x0C, /* Usage Page (Consumer Devices) */ 96 | 0x15, 0x00, /* Logical Minimum (0) */ 97 | 0x25, 0x01, /* Logical Maximum (1) */ 98 | 0x75, 0x01, /* Report Size (1) */ 99 | 0x95, 0x05, /* Report Count (5) */ 100 | 0x09, 0x6F, /* Usage (Brightess Up) */ 101 | 0x09, 0x70, /* Usage (Brightness Down) */ 102 | 0x09, 0x79, /* Usage (Keyboard Brightness Up) */ 103 | 0x09, 0x7A, /* Usage (Keyboard Brightness Down) */ 104 | 0x09, 0xEC, /* Usage (Keyboard Backlight Toggle) */ 105 | 0x81, 0x02, /* Input (Data, Variable, Absolute) */ 106 | 0x95, 0x03, /* Report Count (3) */ 107 | 0x81, 0x01, /* Input (Constant) */ 108 | 0xC0, /* End Collection */ 109 | 110 | 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1) 111 | 0x09, 0x03, // USAGE (Vendor Usage 3) 112 | 0xa1, 0x01, // COLLECTION (Application) 113 | 0x85, REPORTID_SETTINGS, // REPORT_ID (Settings) 114 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 115 | 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (256) 116 | 0x75, 0x08, // REPORT_SIZE (8) - bits 117 | 0x95, 0x01, // REPORT_COUNT (1) - Bytes 118 | 0x09, 0x02, // USAGE (Vendor Usage 1) 119 | 0x91, 0x02, // OUTPUT (Data,Var,Abs) 120 | 0x09, 0x03, // USAGE (Vendor Usage 2) 121 | 0x91, 0x02, // OUTPUT (Data,Var,Abs) 122 | 0xc0, // END_COLLECTION 123 | }; 124 | 125 | 126 | // 127 | // This is the default HID descriptor returned by the mini driver 128 | // in response to IOCTL_HID_GET_DEVICE_DESCRIPTOR. The size 129 | // of report descriptor is currently the size of DefaultReportDescriptor. 130 | // 131 | 132 | CONST HID_DESCRIPTOR DefaultHidDescriptor = { 133 | 0x09, // length of HID descriptor 134 | 0x21, // descriptor type == HID 0x21 135 | 0x0100, // hid spec release 136 | 0x00, // country code == Not Specified 137 | 0x01, // number of HID class descriptors 138 | { 0x22, // descriptor type 139 | sizeof(DefaultReportDescriptor) } // total length of report descriptor 140 | }; 141 | #endif 142 | 143 | #define true 1 144 | #define false 0 145 | 146 | typedef NTSTATUS 147 | (*PPROCESS_HID_REPORT)( 148 | IN PVOID Context, 149 | IN PVOID ReportBuffer, 150 | IN ULONG ReportBufferLen, 151 | OUT size_t* BytesWritten 152 | ); 153 | 154 | typedef BOOLEAN 155 | (*PREGISTER_CALLBACK)( 156 | IN PVOID Context, 157 | IN PVOID HIDContext, 158 | IN PPROCESS_HID_REPORT HidReportProcessCallback 159 | ); 160 | 161 | typedef BOOLEAN 162 | (*PUNREGISTER_CALLBACK)( 163 | IN PVOID Context 164 | ); 165 | 166 | typedef void 167 | (*PRELOAD_SETTINGS)( 168 | IN PVOID Context 169 | ); 170 | 171 | DEFINE_GUID(GUID_CROSKBHID_INTERFACE_STANDARD, 172 | 0x74a15a7c, 0x82b5, 0x11ed, 0x8c, 0xd5, 0x00, 0x15, 0x5d, 0xa4, 0x4e, 0x91); 173 | 174 | typedef struct _CROSKBHID_INTERFACE_STANDARD { 175 | INTERFACE InterfaceHeader; 176 | PREGISTER_CALLBACK RegisterCallback; 177 | PUNREGISTER_CALLBACK UnregisterCallback; 178 | PRELOAD_SETTINGS ReloadSettings; 179 | } CROSKBHID_INTERFACE_STANDARD, * PCROSKBHID_INTERFACE_STANDARD; 180 | 181 | typedef struct _CROSKBHIDREMAPPER_CONTEXT 182 | { 183 | 184 | WDFQUEUE ReportQueue; 185 | 186 | BYTE DeviceMode; 187 | 188 | CROSKBHID_INTERFACE_STANDARD CrosKBHidInterface; 189 | 190 | } CROSKBHIDREMAPPER_CONTEXT, *PCROSKBHIDREMAPPER_CONTEXT; 191 | 192 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CROSKBHIDREMAPPER_CONTEXT, GetDeviceContext) 193 | 194 | // 195 | // Function definitions 196 | // 197 | 198 | DRIVER_INITIALIZE DriverEntry; 199 | 200 | EVT_WDF_DRIVER_UNLOAD CrosKBHIDRemapperDriverUnload; 201 | 202 | EVT_WDF_DRIVER_DEVICE_ADD CrosKBHIDRemapperEvtDeviceAdd; 203 | 204 | EVT_WDFDEVICE_WDM_IRP_PREPROCESS CrosKBHIDRemapperEvtWdmPreprocessMnQueryId; 205 | 206 | EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL CrosKBHIDRemapperEvtInternalDeviceControl; 207 | 208 | NTSTATUS 209 | CrosKBHIDRemapperGetHidDescriptor( 210 | IN WDFDEVICE Device, 211 | IN WDFREQUEST Request 212 | ); 213 | 214 | NTSTATUS 215 | CrosKBHIDRemapperGetReportDescriptor( 216 | IN WDFDEVICE Device, 217 | IN WDFREQUEST Request 218 | ); 219 | 220 | NTSTATUS 221 | CrosKBHIDRemapperGetDeviceAttributes( 222 | IN WDFREQUEST Request 223 | ); 224 | 225 | NTSTATUS 226 | CrosKBHIDRemapperGetString( 227 | IN WDFREQUEST Request 228 | ); 229 | 230 | NTSTATUS 231 | CrosKBHIDRemapperWriteReport( 232 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 233 | IN WDFREQUEST Request 234 | ); 235 | 236 | NTSTATUS 237 | CrosKBHIDRemapperProcessVendorReport( 238 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 239 | IN PVOID ReportBuffer, 240 | IN ULONG ReportBufferLen, 241 | OUT size_t* BytesWritten 242 | ); 243 | 244 | NTSTATUS 245 | CrosKBHIDRemapperReadReport( 246 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 247 | IN WDFREQUEST Request, 248 | OUT BOOLEAN* CompleteRequest 249 | ); 250 | 251 | NTSTATUS 252 | CrosKBHIDRemapperSetFeature( 253 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 254 | IN WDFREQUEST Request, 255 | OUT BOOLEAN* CompleteRequest 256 | ); 257 | 258 | NTSTATUS 259 | CrosKBHIDRemapperGetFeature( 260 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 261 | IN WDFREQUEST Request, 262 | OUT BOOLEAN* CompleteRequest 263 | ); 264 | 265 | PCHAR 266 | DbgHidInternalIoctlString( 267 | IN ULONG IoControlCode 268 | ); 269 | 270 | // 271 | // Helper macros 272 | // 273 | 274 | #define DEBUG_LEVEL_ERROR 1 275 | #define DEBUG_LEVEL_INFO 2 276 | #define DEBUG_LEVEL_VERBOSE 3 277 | 278 | #define DBG_INIT 1 279 | #define DBG_PNP 2 280 | #define DBG_IOCTL 4 281 | 282 | #if DBG 283 | #define CrosKBHIDRemapperPrint(dbglevel, dbgcatagory, fmt, ...) { \ 284 | if (CrosKBHIDRemapperDebugLevel >= dbglevel && \ 285 | (CrosKBHIDRemapperDebugCatagories && dbgcatagory)) \ 286 | { \ 287 | DbgPrint(DRIVERNAME); \ 288 | DbgPrint(fmt, __VA_ARGS__); \ 289 | } \ 290 | } 291 | #else 292 | #define CrosKBHIDRemapperPrint(dbglevel, fmt, ...) { \ 293 | } 294 | #endif 295 | 296 | #endif 297 | #pragma once 298 | -------------------------------------------------------------------------------- /croskbhidremapper/croskbhidremapper/croskbhidremapper.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | {E0C3F023-6A54-419C-9C6E-E0638B55D99F} 51 | {497e31cb-056b-4f31-abb8-447fd55ee5a5} 52 | v4.5 53 | 12.0 54 | Debug 55 | Win32 56 | croskbhidremapper 57 | $(LatestTargetPlatformVersion) 58 | 59 | 60 | 61 | 62 | 63 | true 64 | WindowsKernelModeDriver10.0 65 | Driver 66 | KMDF 67 | Universal 68 | 69 | 70 | 71 | 72 | false 73 | WindowsKernelModeDriver10.0 74 | Driver 75 | KMDF 76 | Universal 77 | 78 | 79 | 80 | 81 | true 82 | WindowsKernelModeDriver10.0 83 | Driver 84 | KMDF 85 | Universal 86 | 87 | 88 | 89 | 90 | false 91 | WindowsKernelModeDriver10.0 92 | Driver 93 | KMDF 94 | Universal 95 | 96 | 97 | 98 | 99 | true 100 | WindowsKernelModeDriver10.0 101 | Driver 102 | KMDF 103 | Universal 104 | 105 | 106 | 107 | 108 | false 109 | WindowsKernelModeDriver10.0 110 | Driver 111 | KMDF 112 | Universal 113 | 114 | 115 | 116 | 117 | true 118 | WindowsKernelModeDriver10.0 119 | Driver 120 | KMDF 121 | Universal 122 | 123 | 124 | 125 | 126 | false 127 | WindowsKernelModeDriver10.0 128 | Driver 129 | KMDF 130 | Universal 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | DbgengKernelDebugger 142 | 143 | 144 | DbgengKernelDebugger 145 | 146 | 147 | DbgengKernelDebugger 148 | 149 | 150 | DbgengKernelDebugger 151 | 152 | 153 | DbgengKernelDebugger 154 | 155 | 156 | DbgengKernelDebugger 157 | 158 | 159 | DbgengKernelDebugger 160 | 161 | 162 | DbgengKernelDebugger 163 | 164 | 165 | 166 | true 167 | true 168 | trace.h 169 | true 170 | 171 | 172 | sha256 173 | 174 | 175 | 4.0.0 176 | 177 | 178 | 179 | 180 | true 181 | true 182 | trace.h 183 | true 184 | 185 | 186 | sha256 187 | 188 | 189 | 4.0.0 190 | 191 | 192 | 193 | 194 | true 195 | true 196 | trace.h 197 | true 198 | false 199 | 200 | 201 | sha256 202 | 203 | 204 | 4.0.0 205 | 206 | 207 | 208 | 209 | true 210 | true 211 | trace.h 212 | true 213 | false 214 | 215 | 216 | 4.0.0 217 | 218 | 219 | sha256 220 | 221 | 222 | 223 | 224 | true 225 | true 226 | trace.h 227 | true 228 | 229 | 230 | 4.0.0 231 | 232 | 233 | 234 | 235 | true 236 | true 237 | trace.h 238 | true 239 | 240 | 241 | 4.0.0 242 | 243 | 244 | 245 | 246 | true 247 | true 248 | trace.h 249 | true 250 | 251 | 252 | 4.0.0 253 | 254 | 255 | 256 | 257 | true 258 | true 259 | trace.h 260 | true 261 | 262 | 263 | 4.0.0 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | -------------------------------------------------------------------------------- /sys/rawpdo.c: -------------------------------------------------------------------------------- 1 | /*-- 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 6 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 7 | IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 8 | PURPOSE. 9 | 10 | 11 | Module Name: 12 | 13 | RawPdo.c 14 | 15 | Abstract: This module have the code enumerate a raw PDO for every device 16 | the filter attaches to so that it can provide a direct 17 | sideband communication with the usermode application. 18 | 19 | The toaster filter driver sample demonstrates an alternation 20 | approach where you can create one control-device for all the 21 | instances of the filter device. 22 | 23 | Environment: 24 | 25 | Kernel mode only. 26 | 27 | --*/ 28 | 29 | #include "croskeyboard.h" 30 | #include "public.h" 31 | 32 | VOID 33 | KbFilter_EvtIoDeviceControlForRawPdo( 34 | IN WDFQUEUE Queue, 35 | IN WDFREQUEST Request, 36 | IN size_t OutputBufferLength, 37 | IN size_t InputBufferLength, 38 | IN ULONG IoControlCode 39 | ) 40 | /*++ 41 | 42 | Routine Description: 43 | 44 | This routine is the dispatch routine for device control requests. 45 | 46 | Arguments: 47 | 48 | Queue - Handle to the framework queue object that is associated 49 | with the I/O request. 50 | Request - Handle to a framework request object. 51 | 52 | OutputBufferLength - length of the request's output buffer, 53 | if an output buffer is available. 54 | InputBufferLength - length of the request's input buffer, 55 | if an input buffer is available. 56 | 57 | IoControlCode - the driver-defined or system-defined I/O control code 58 | (IOCTL) that is associated with the request. 59 | 60 | Return Value: 61 | 62 | VOID 63 | 64 | --*/ 65 | { 66 | NTSTATUS status = STATUS_SUCCESS; 67 | WDFDEVICE parent = WdfIoQueueGetDevice(Queue); 68 | PRPDO_DEVICE_DATA pdoData; 69 | WDF_REQUEST_FORWARD_OPTIONS forwardOptions; 70 | 71 | pdoData = PdoGetData(parent); 72 | 73 | UNREFERENCED_PARAMETER(OutputBufferLength); 74 | UNREFERENCED_PARAMETER(InputBufferLength); 75 | 76 | DebugPrint(("Entered KbFilter_EvtIoDeviceControlForRawPdo\n")); 77 | 78 | // 79 | // Process the ioctl and complete it when you are done. 80 | // Since the queue is configured for serial dispatch, you will 81 | // not receive another ioctl request until you complete this one. 82 | // 83 | 84 | switch (IoControlCode) { 85 | case IOCTL_KBFILTR_GET_KEYBOARD_ATTRIBUTES: 86 | WDF_REQUEST_FORWARD_OPTIONS_INIT(&forwardOptions); 87 | status = WdfRequestForwardToParentDeviceIoQueue(Request, pdoData->ParentQueue, &forwardOptions); 88 | if (!NT_SUCCESS(status)) { 89 | WdfRequestComplete(Request, status); 90 | } 91 | break; 92 | default: 93 | WdfRequestComplete(Request, status); 94 | break; 95 | } 96 | 97 | return; 98 | } 99 | 100 | #define MAX_ID_LEN 128 101 | 102 | NTSTATUS 103 | KbFiltr_CreateRawPdo( 104 | WDFDEVICE Device, 105 | ULONG InstanceNo 106 | ) 107 | /*++ 108 | 109 | Routine Description: 110 | 111 | This routine creates and initialize a PDO. 112 | 113 | Arguments: 114 | 115 | Return Value: 116 | 117 | NT Status code. 118 | 119 | --*/ 120 | { 121 | NTSTATUS status; 122 | PWDFDEVICE_INIT pDeviceInit = NULL; 123 | PRPDO_DEVICE_DATA pdoData = NULL; 124 | WDFDEVICE hChild = NULL; 125 | WDF_OBJECT_ATTRIBUTES pdoAttributes; 126 | WDF_DEVICE_PNP_CAPABILITIES pnpCaps; 127 | WDF_IO_QUEUE_CONFIG ioQueueConfig; 128 | WDFQUEUE queue; 129 | WDF_DEVICE_STATE deviceState; 130 | PDEVICE_EXTENSION devExt; 131 | DECLARE_CONST_UNICODE_STRING(deviceId,KBFILTR_DEVICE_ID ); 132 | DECLARE_CONST_UNICODE_STRING(hardwareId,KBFILTR_DEVICE_ID ); 133 | DECLARE_CONST_UNICODE_STRING(deviceLocation,L"Keyboard Filter\0" ); 134 | DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); 135 | 136 | DebugPrint(("Entered KbFiltr_CreateRawPdo\n")); 137 | 138 | // 139 | // Allocate a WDFDEVICE_INIT structure and set the properties 140 | // so that we can create a device object for the child. 141 | // 142 | pDeviceInit = WdfPdoInitAllocate(Device); 143 | 144 | if (pDeviceInit == NULL) { 145 | status = STATUS_INSUFFICIENT_RESOURCES; 146 | goto Cleanup; 147 | } 148 | 149 | // 150 | // Mark the device RAW so that the child device can be started 151 | // and accessed without requiring a function driver. Since we are 152 | // creating a RAW PDO, we must provide a class guid. 153 | // 154 | status = WdfPdoInitAssignRawDevice(pDeviceInit, &GUID_DEVCLASS_KEYBOARD); 155 | if (!NT_SUCCESS(status)) { 156 | goto Cleanup; 157 | } 158 | 159 | // 160 | // Since keyboard is secure device, we must protect ourselves from random 161 | // users sending ioctls and creating trouble. 162 | // 163 | status = WdfDeviceInitAssignSDDLString(pDeviceInit, 164 | &SDDL_DEVOBJ_SYS_ALL_ADM_ALL); 165 | if (!NT_SUCCESS(status)) { 166 | goto Cleanup; 167 | } 168 | 169 | // 170 | // Assign DeviceID - This will be reported to IRP_MN_QUERY_ID/BusQueryDeviceID 171 | // 172 | status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); 173 | if (!NT_SUCCESS(status)) { 174 | goto Cleanup; 175 | } 176 | 177 | // 178 | // For RAW PDO, there is no need to provide BusQueryHardwareIDs 179 | // and BusQueryCompatibleIDs IDs unless we are running on 180 | // Windows 2000. 181 | // 182 | if (!RtlIsNtDdiVersionAvailable(NTDDI_WINXP)) { 183 | // 184 | // On Win2K, we must provide a HWID for the device to get enumerated. 185 | // Since we are providing a HWID, we will have to provide a NULL inf 186 | // to avoid the "found new device" popup and get the device installed 187 | // silently. 188 | // 189 | status = WdfPdoInitAddHardwareID(pDeviceInit, &hardwareId); 190 | if (!NT_SUCCESS(status)) { 191 | goto Cleanup; 192 | } 193 | } 194 | 195 | // 196 | // We could be enumerating more than one children if the filter attaches 197 | // to multiple instances of keyboard, so we must provide a 198 | // BusQueryInstanceID. If we don't, system will throw CA bugcheck. 199 | // 200 | status = RtlUnicodeStringPrintf(&buffer, L"%02d", InstanceNo); 201 | if (!NT_SUCCESS(status)) { 202 | goto Cleanup; 203 | } 204 | 205 | status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); 206 | if (!NT_SUCCESS(status)) { 207 | goto Cleanup; 208 | } 209 | 210 | // 211 | // Provide a description about the device. This text is usually read from 212 | // the device. In the case of USB device, this text comes from the string 213 | // descriptor. This text is displayed momentarily by the PnP manager while 214 | // it's looking for a matching INF. If it finds one, it uses the Device 215 | // Description from the INF file to display in the device manager. 216 | // Since our device is raw device and we don't provide any hardware ID 217 | // to match with an INF, this text will be displayed in the device manager. 218 | // 219 | status = RtlUnicodeStringPrintf(&buffer,L"Keyboard_Filter_%02d", InstanceNo ); 220 | if (!NT_SUCCESS(status)) { 221 | goto Cleanup; 222 | } 223 | 224 | // 225 | // You can call WdfPdoInitAddDeviceText multiple times, adding device 226 | // text for multiple locales. When the system displays the text, it 227 | // chooses the text that matches the current locale, if available. 228 | // Otherwise it will use the string for the default locale. 229 | // The driver can specify the driver's default locale by calling 230 | // WdfPdoInitSetDefaultLocale. 231 | // 232 | status = WdfPdoInitAddDeviceText(pDeviceInit, 233 | &buffer, 234 | &deviceLocation, 235 | 0x409 236 | ); 237 | if (!NT_SUCCESS(status)) { 238 | goto Cleanup; 239 | } 240 | 241 | WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); 242 | 243 | // 244 | // Initialize the attributes to specify the size of PDO device extension. 245 | // All the state information private to the PDO will be tracked here. 246 | // 247 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, RPDO_DEVICE_DATA); 248 | 249 | // 250 | // Set up our queue to allow forwarding of requests to the parent 251 | // This is done so that the cached Keyboard Attributes can be retrieved 252 | // 253 | WdfPdoInitAllowForwardingRequestToParent(pDeviceInit); 254 | 255 | status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); 256 | if (!NT_SUCCESS(status)) { 257 | goto Cleanup; 258 | } 259 | 260 | // 261 | // Get the device context. 262 | // 263 | pdoData = PdoGetData(hChild); 264 | 265 | pdoData->InstanceNo = InstanceNo; 266 | 267 | // 268 | // Get the parent queue we will be forwarding to 269 | // 270 | devExt = FilterGetData(Device); 271 | pdoData->ParentQueue = devExt->rawPdoQueue; 272 | 273 | // 274 | // Configure the default queue associated with the control device object 275 | // to be Serial so that request passed to EvtIoDeviceControl are serialized. 276 | // A default queue gets all the requests that are not 277 | // configure-fowarded using WdfDeviceConfigureRequestDispatching. 278 | // 279 | 280 | WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, 281 | WdfIoQueueDispatchSequential); 282 | 283 | ioQueueConfig.EvtIoDeviceControl = KbFilter_EvtIoDeviceControlForRawPdo; 284 | 285 | status = WdfIoQueueCreate(hChild, 286 | &ioQueueConfig, 287 | WDF_NO_OBJECT_ATTRIBUTES, 288 | &queue // pointer to default queue 289 | ); 290 | if (!NT_SUCCESS(status)) { 291 | DebugPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); 292 | goto Cleanup; 293 | } 294 | 295 | // 296 | // Set some properties for the child device. 297 | // 298 | WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); 299 | 300 | pnpCaps.Removable = WdfTrue; 301 | pnpCaps.SurpriseRemovalOK = WdfTrue; 302 | pnpCaps.NoDisplayInUI = WdfTrue; 303 | 304 | pnpCaps.Address = InstanceNo; 305 | pnpCaps.UINumber = InstanceNo; 306 | 307 | WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); 308 | 309 | // 310 | // TODO: In addition to setting NoDisplayInUI in DeviceCaps, we 311 | // have to do the following to hide the device. Following call 312 | // tells the framework to report the device state in 313 | // IRP_MN_QUERY_DEVICE_STATE request. 314 | // 315 | WDF_DEVICE_STATE_INIT(&deviceState); 316 | deviceState.DontDisplayInUI = WdfTrue; 317 | WdfDeviceSetDeviceState(hChild, &deviceState); 318 | 319 | // 320 | // Tell the Framework that this device will need an interface so that 321 | // application can find our device and talk to it. 322 | // 323 | status = WdfDeviceCreateDeviceInterface( 324 | hChild, 325 | &GUID_DEVINTERFACE_KBFILTER, 326 | NULL 327 | ); 328 | 329 | if (!NT_SUCCESS (status)) { 330 | DebugPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); 331 | goto Cleanup; 332 | } 333 | 334 | // 335 | // Add this device to the FDO's collection of children. 336 | // After the child device is added to the static collection successfully, 337 | // driver must call WdfPdoMarkMissing to get the device deleted. It 338 | // shouldn't delete the child device directly by calling WdfObjectDelete. 339 | // 340 | status = WdfFdoAddStaticChild(Device, hChild); 341 | if (!NT_SUCCESS(status)) { 342 | goto Cleanup; 343 | } 344 | 345 | // 346 | // pDeviceInit will be freed by WDF. 347 | // 348 | return STATUS_SUCCESS; 349 | 350 | Cleanup: 351 | 352 | DebugPrint(("KbFiltr_CreatePdo failed %x\n", status)); 353 | 354 | // 355 | // Call WdfDeviceInitFree if you encounter an error while initializing 356 | // a new framework device object. If you call WdfDeviceInitFree, 357 | // do not call WdfDeviceCreate. 358 | // 359 | if (pDeviceInit != NULL) { 360 | WdfDeviceInitFree(pDeviceInit); 361 | } 362 | 363 | if(hChild) { 364 | WdfObjectDelete(hChild); 365 | } 366 | 367 | return status; 368 | } 369 | 370 | 371 | BOOLEAN 372 | KBFiltr_RegisterHIDCallback( 373 | IN PVOID Context, 374 | IN PVOID HIDContext, 375 | IN PPROCESS_HID_REPORT HidReportProcessCallback 376 | ) 377 | { 378 | PDEVICE_EXTENSION devExt; 379 | devExt = (PDEVICE_EXTENSION)Context; 380 | if (!devExt) { 381 | return FALSE; 382 | } 383 | 384 | devExt->HIDContext = HIDContext; 385 | devExt->HidReportProcessCallback = HidReportProcessCallback; 386 | return TRUE; 387 | } 388 | 389 | BOOLEAN 390 | KBFiltr_UnregisterHIDCallback( 391 | IN PVOID Context 392 | ) 393 | { 394 | PDEVICE_EXTENSION devExt; 395 | devExt = (PDEVICE_EXTENSION)Context; 396 | if (!devExt) { 397 | return FALSE; 398 | } 399 | 400 | devExt->HIDContext = NULL; 401 | devExt->HidReportProcessCallback = NULL; 402 | return TRUE; 403 | } 404 | 405 | NTSTATUS AutoDetectSettings(PDEVICE_EXTENSION filterExt); 406 | void LoadSettings(PDEVICE_EXTENSION filterExt); 407 | VOID 408 | KbFiltr_ReloadSettings( 409 | IN PVOID Context 410 | ) 411 | { 412 | PDEVICE_EXTENSION devExt; 413 | devExt = (PDEVICE_EXTENSION)Context; 414 | if (!devExt) { 415 | return; 416 | } 417 | 418 | AutoDetectSettings(devExt); 419 | LoadSettings(devExt); 420 | } 421 | 422 | NTSTATUS 423 | KbFiltr_CreateHIDPdo( 424 | WDFDEVICE Device, 425 | ULONG InstanceNo 426 | ) 427 | /*++ 428 | 429 | Routine Description: 430 | 431 | This routine creates and initialize a PDO. 432 | 433 | Arguments: 434 | 435 | Return Value: 436 | 437 | NT Status code. 438 | 439 | --*/ 440 | { 441 | NTSTATUS status; 442 | PWDFDEVICE_INIT pDeviceInit = NULL; 443 | PRPDO_DEVICE_DATA pdoData = NULL; 444 | WDFDEVICE hChild = NULL; 445 | WDF_OBJECT_ATTRIBUTES pdoAttributes; 446 | WDF_DEVICE_PNP_CAPABILITIES pnpCaps; 447 | WDF_DEVICE_STATE deviceState; 448 | PDEVICE_EXTENSION devExt; 449 | WDF_QUERY_INTERFACE_CONFIG qiConfig; 450 | DECLARE_CONST_UNICODE_STRING(deviceId, L"CROSKB\\HID0000"); 451 | DECLARE_CONST_UNICODE_STRING(hardwareId, L"CROSKB\\HID0000"); 452 | DECLARE_CONST_UNICODE_STRING(deviceLocation, L"HID Keyboard Helper\0"); 453 | DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); 454 | 455 | DebugPrint(("Entered KbFiltr_CreateHIDPdo\n")); 456 | 457 | // 458 | // Allocate a WDFDEVICE_INIT structure and set the properties 459 | // so that we can create a device object for the child. 460 | // 461 | pDeviceInit = WdfPdoInitAllocate(Device); 462 | 463 | if (pDeviceInit == NULL) { 464 | status = STATUS_INSUFFICIENT_RESOURCES; 465 | goto Cleanup; 466 | } 467 | 468 | WdfDeviceInitSetDeviceType(pDeviceInit, FILE_DEVICE_BUS_EXTENDER); 469 | 470 | // 471 | // Assign DeviceID - This will be reported to IRP_MN_QUERY_ID/BusQueryDeviceID 472 | // 473 | status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); 474 | if (!NT_SUCCESS(status)) { 475 | goto Cleanup; 476 | } 477 | 478 | //Add Hardware ID to allow the HID driver to attach 479 | status = WdfPdoInitAddHardwareID(pDeviceInit, &hardwareId); 480 | if (!NT_SUCCESS(status)) { 481 | goto Cleanup; 482 | } 483 | 484 | // 485 | // We could be enumerating more than one children if the filter attaches 486 | // to multiple instances of keyboard, so we must provide a 487 | // BusQueryInstanceID. If we don't, system will throw CA bugcheck. 488 | // 489 | status = RtlUnicodeStringPrintf(&buffer, L"%02d", InstanceNo); 490 | if (!NT_SUCCESS(status)) { 491 | goto Cleanup; 492 | } 493 | 494 | status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); 495 | if (!NT_SUCCESS(status)) { 496 | goto Cleanup; 497 | } 498 | 499 | // 500 | // Provide a description about the device. This text is usually read from 501 | // the device. In the case of USB device, this text comes from the string 502 | // descriptor. This text is displayed momentarily by the PnP manager while 503 | // it's looking for a matching INF. If it finds one, it uses the Device 504 | // Description from the INF file to display in the device manager. 505 | // Since our device is raw device and we don't provide any hardware ID 506 | // to match with an INF, this text will be displayed in the device manager. 507 | // 508 | status = RtlUnicodeStringPrintf(&buffer, L"Chromebook Keyboard HID Helper"); 509 | if (!NT_SUCCESS(status)) { 510 | goto Cleanup; 511 | } 512 | 513 | // 514 | // You can call WdfPdoInitAddDeviceText multiple times, adding device 515 | // text for multiple locales. When the system displays the text, it 516 | // chooses the text that matches the current locale, if available. 517 | // Otherwise it will use the string for the default locale. 518 | // The driver can specify the driver's default locale by calling 519 | // WdfPdoInitSetDefaultLocale. 520 | // 521 | status = WdfPdoInitAddDeviceText(pDeviceInit, 522 | &buffer, 523 | &deviceLocation, 524 | 0x409 525 | ); 526 | if (!NT_SUCCESS(status)) { 527 | goto Cleanup; 528 | } 529 | 530 | WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); 531 | 532 | // 533 | // Initialize the attributes to specify the size of PDO device extension. 534 | // All the state information private to the PDO will be tracked here. 535 | // 536 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, RPDO_DEVICE_DATA); 537 | 538 | // 539 | // Set up our queue to allow forwarding of requests to the parent 540 | // This is done so that the cached Keyboard Attributes can be retrieved 541 | // 542 | WdfPdoInitAllowForwardingRequestToParent(pDeviceInit); 543 | 544 | status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); 545 | if (!NT_SUCCESS(status)) { 546 | goto Cleanup; 547 | } 548 | 549 | // 550 | // Get the device context. 551 | // 552 | pdoData = PdoGetData(hChild); 553 | 554 | pdoData->InstanceNo = InstanceNo; 555 | 556 | // 557 | // Set some properties for the child device. 558 | // 559 | WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); 560 | 561 | pnpCaps.Removable = WdfTrue; 562 | pnpCaps.SurpriseRemovalOK = WdfTrue; 563 | 564 | pnpCaps.Address = InstanceNo; 565 | pnpCaps.UINumber = InstanceNo; 566 | 567 | WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); 568 | 569 | // 570 | // TODO: In addition to setting NoDisplayInUI in DeviceCaps, we 571 | // have to do the following to hide the device. Following call 572 | // tells the framework to report the device state in 573 | // IRP_MN_QUERY_DEVICE_STATE request. 574 | // 575 | WDF_DEVICE_STATE_INIT(&deviceState); 576 | deviceState.NotDisableable = WdfFalse; 577 | WdfDeviceSetDeviceState(hChild, &deviceState); 578 | 579 | devExt = FilterGetData(Device); 580 | 581 | CROSKBHID_INTERFACE_STANDARD CrosKBHIDInterface; 582 | RtlZeroMemory(&CrosKBHIDInterface, sizeof(CrosKBHIDInterface)); 583 | 584 | CrosKBHIDInterface.InterfaceHeader.Size = sizeof(CrosKBHIDInterface); 585 | CrosKBHIDInterface.InterfaceHeader.Version = 1; 586 | CrosKBHIDInterface.InterfaceHeader.Context = (PVOID)devExt; 587 | CrosKBHIDInterface.RegisterCallback = KBFiltr_RegisterHIDCallback; 588 | CrosKBHIDInterface.UnregisterCallback = KBFiltr_UnregisterHIDCallback; 589 | CrosKBHIDInterface.ReloadSettings = KbFiltr_ReloadSettings; 590 | 591 | WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig, 592 | (PINTERFACE)&CrosKBHIDInterface, 593 | &GUID_CROSKBHID_INTERFACE_STANDARD, 594 | NULL); 595 | 596 | // 597 | // Tell the Framework that this device will need an interface so that 598 | // the HID driver can talk to our device. 599 | // 600 | status = WdfDeviceAddQueryInterface( 601 | hChild, 602 | &qiConfig 603 | ); 604 | 605 | if (!NT_SUCCESS(status)) { 606 | DebugPrint(("WdfDeviceAddQueryInterface failed 0x%x\n", status)); 607 | goto Cleanup; 608 | } 609 | 610 | // 611 | // Add this device to the FDO's collection of children. 612 | // After the child device is added to the static collection successfully, 613 | // driver must call WdfPdoMarkMissing to get the device deleted. It 614 | // shouldn't delete the child device directly by calling WdfObjectDelete. 615 | // 616 | status = WdfFdoAddStaticChild(Device, hChild); 617 | if (!NT_SUCCESS(status)) { 618 | goto Cleanup; 619 | } 620 | 621 | // 622 | // pDeviceInit will be freed by WDF. 623 | // 624 | return STATUS_SUCCESS; 625 | 626 | Cleanup: 627 | 628 | DebugPrint(("KbFiltr_CreatePdo failed %x\n", status)); 629 | 630 | // 631 | // Call WdfDeviceInitFree if you encounter an error while initializing 632 | // a new framework device object. If you call WdfDeviceInitFree, 633 | // do not call WdfDeviceCreate. 634 | // 635 | if (pDeviceInit != NULL) { 636 | WdfDeviceInitFree(pDeviceInit); 637 | } 638 | 639 | if (hChild) { 640 | WdfObjectDelete(hChild); 641 | } 642 | 643 | return status; 644 | } -------------------------------------------------------------------------------- /croskbhidremapper/croskbhidremapper/croskbhidremapper.cpp: -------------------------------------------------------------------------------- 1 | #define DESCRIPTOR_DEF 2 | #include "croskbhidremapper.h" 3 | 4 | static ULONG CrosKBHIDRemapperDebugLevel = 100; 5 | static ULONG CrosKBHIDRemapperDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 6 | 7 | NTSTATUS 8 | DriverEntry( 9 | __in PDRIVER_OBJECT DriverObject, 10 | __in PUNICODE_STRING RegistryPath 11 | ) 12 | { 13 | NTSTATUS status = STATUS_SUCCESS; 14 | WDF_DRIVER_CONFIG config; 15 | WDF_OBJECT_ATTRIBUTES attributes; 16 | 17 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_INFO, DBG_INIT, 18 | "Driver Entry"); 19 | 20 | WDF_DRIVER_CONFIG_INIT(&config, CrosKBHIDRemapperEvtDeviceAdd); 21 | 22 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 23 | 24 | // 25 | // Create a framework driver object to represent our driver. 26 | // 27 | 28 | status = WdfDriverCreate(DriverObject, 29 | RegistryPath, 30 | &attributes, 31 | &config, 32 | WDF_NO_HANDLE 33 | ); 34 | 35 | if (!NT_SUCCESS(status)) 36 | { 37 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_INIT, 38 | "WdfDriverCreate failed with status 0x%x\n", status); 39 | } 40 | 41 | return status; 42 | } 43 | 44 | NTSTATUS 45 | OnPrepareHardware( 46 | _In_ WDFDEVICE FxDevice, 47 | _In_ WDFCMRESLIST FxResourcesRaw, 48 | _In_ WDFCMRESLIST FxResourcesTranslated 49 | ) 50 | /*++ 51 | 52 | Routine Description: 53 | 54 | This routine caches the SPB resource connection ID. 55 | 56 | Arguments: 57 | 58 | FxDevice - a handle to the framework device object 59 | FxResourcesRaw - list of translated hardware resources that 60 | the PnP manager has assigned to the device 61 | FxResourcesTranslated - list of raw hardware resources that 62 | the PnP manager has assigned to the device 63 | 64 | Return Value: 65 | 66 | Status 67 | 68 | --*/ 69 | { 70 | PCROSKBHIDREMAPPER_CONTEXT pDevice = GetDeviceContext(FxDevice); 71 | NTSTATUS status = STATUS_SUCCESS; 72 | 73 | UNREFERENCED_PARAMETER(FxResourcesRaw); 74 | UNREFERENCED_PARAMETER(FxResourcesTranslated); 75 | 76 | CROSKBHID_INTERFACE_STANDARD CrosKBHIDInterface; 77 | status = WdfFdoQueryForInterface(FxDevice, &GUID_CROSKBHID_INTERFACE_STANDARD, 78 | (PINTERFACE)&CrosKBHIDInterface, sizeof(CrosKBHIDInterface), 1, NULL); 79 | if (!NT_SUCCESS(status)) { 80 | return status; 81 | } 82 | 83 | memcpy(&pDevice->CrosKBHidInterface, &CrosKBHIDInterface, sizeof(CrosKBHIDInterface)); 84 | 85 | return status; 86 | } 87 | 88 | NTSTATUS 89 | OnReleaseHardware( 90 | _In_ WDFDEVICE FxDevice, 91 | _In_ WDFCMRESLIST FxResourcesTranslated 92 | ) 93 | /*++ 94 | 95 | Routine Description: 96 | 97 | Arguments: 98 | 99 | FxDevice - a handle to the framework device object 100 | FxResourcesTranslated - list of raw hardware resources that 101 | the PnP manager has assigned to the device 102 | 103 | Return Value: 104 | 105 | Status 106 | 107 | --*/ 108 | { 109 | NTSTATUS status = STATUS_SUCCESS; 110 | 111 | UNREFERENCED_PARAMETER(FxDevice); 112 | UNREFERENCED_PARAMETER(FxResourcesTranslated); 113 | 114 | return status; 115 | } 116 | 117 | NTSTATUS 118 | OnD0Entry( 119 | _In_ WDFDEVICE FxDevice, 120 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 121 | ) 122 | /*++ 123 | 124 | Routine Description: 125 | 126 | This routine allocates objects needed by the driver. 127 | 128 | Arguments: 129 | 130 | FxDevice - a handle to the framework device object 131 | FxPreviousState - previous power state 132 | 133 | Return Value: 134 | 135 | Status 136 | 137 | --*/ 138 | { 139 | UNREFERENCED_PARAMETER(FxPreviousState); 140 | 141 | PCROSKBHIDREMAPPER_CONTEXT pDevice = GetDeviceContext(FxDevice); 142 | 143 | if (!pDevice->CrosKBHidInterface.RegisterCallback) { 144 | return STATUS_NOINTERFACE; 145 | } 146 | 147 | BOOLEAN success = (*pDevice->CrosKBHidInterface.RegisterCallback)( 148 | pDevice->CrosKBHidInterface.InterfaceHeader.Context, 149 | pDevice, 150 | (PPROCESS_HID_REPORT)&CrosKBHIDRemapperProcessVendorReport 151 | ); 152 | 153 | return success ? STATUS_SUCCESS : STATUS_INVALID_DEVICE_REQUEST; 154 | } 155 | 156 | NTSTATUS 157 | OnD0Exit( 158 | _In_ WDFDEVICE FxDevice, 159 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 160 | ) 161 | /*++ 162 | 163 | Routine Description: 164 | 165 | This routine destroys objects needed by the driver. 166 | 167 | Arguments: 168 | 169 | FxDevice - a handle to the framework device object 170 | FxPreviousState - previous power state 171 | 172 | Return Value: 173 | 174 | Status 175 | 176 | --*/ 177 | { 178 | UNREFERENCED_PARAMETER(FxPreviousState); 179 | 180 | PCROSKBHIDREMAPPER_CONTEXT pDevice = GetDeviceContext(FxDevice); 181 | 182 | if (!pDevice->CrosKBHidInterface.UnregisterCallback) { 183 | return STATUS_NOINTERFACE; 184 | } 185 | 186 | BOOLEAN success = (*pDevice->CrosKBHidInterface.UnregisterCallback)(pDevice->CrosKBHidInterface.InterfaceHeader.Context); 187 | 188 | return success ? STATUS_SUCCESS : STATUS_INVALID_DEVICE_REQUEST; 189 | } 190 | 191 | NTSTATUS 192 | CrosKBHIDRemapperEvtDeviceAdd( 193 | IN WDFDRIVER Driver, 194 | IN PWDFDEVICE_INIT DeviceInit 195 | ) 196 | { 197 | NTSTATUS status = STATUS_SUCCESS; 198 | WDF_IO_QUEUE_CONFIG queueConfig; 199 | WDF_OBJECT_ATTRIBUTES attributes; 200 | WDFDEVICE device; 201 | WDFQUEUE queue; 202 | UCHAR minorFunction; 203 | PCROSKBHIDREMAPPER_CONTEXT devContext; 204 | 205 | UNREFERENCED_PARAMETER(Driver); 206 | 207 | PAGED_CODE(); 208 | 209 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_INFO, DBG_PNP, 210 | "CrosKBHIDRemapperEvtDeviceAdd called\n"); 211 | 212 | // 213 | // Tell framework this is a filter driver. Filter drivers by default are 214 | // not power policy owners. This works well for this driver because 215 | // HIDclass driver is the power policy owner for HID minidrivers. 216 | // 217 | 218 | WdfFdoInitSetFilter(DeviceInit); 219 | 220 | { 221 | WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; 222 | WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); 223 | 224 | pnpCallbacks.EvtDevicePrepareHardware = OnPrepareHardware; 225 | pnpCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware; 226 | pnpCallbacks.EvtDeviceD0Entry = OnD0Entry; 227 | pnpCallbacks.EvtDeviceD0Exit = OnD0Exit; 228 | 229 | WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); 230 | } 231 | 232 | // 233 | // Because we are a virtual device the root enumerator would just put null values 234 | // in response to IRP_MN_QUERY_ID. Lets override that. 235 | // 236 | 237 | minorFunction = IRP_MN_QUERY_ID; 238 | 239 | status = WdfDeviceInitAssignWdmIrpPreprocessCallback( 240 | DeviceInit, 241 | CrosKBHIDRemapperEvtWdmPreprocessMnQueryId, 242 | IRP_MJ_PNP, 243 | &minorFunction, 244 | 1 245 | ); 246 | if (!NT_SUCCESS(status)) 247 | { 248 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 249 | "WdfDeviceInitAssignWdmIrpPreprocessCallback failed Status 0x%x\n", status); 250 | 251 | return status; 252 | } 253 | 254 | // 255 | // Setup the device context 256 | // 257 | 258 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CROSKBHIDREMAPPER_CONTEXT); 259 | 260 | // 261 | // Create a framework device object.This call will in turn create 262 | // a WDM device object, attach to the lower stack, and set the 263 | // appropriate flags and attributes. 264 | // 265 | 266 | status = WdfDeviceCreate(&DeviceInit, &attributes, &device); 267 | 268 | if (!NT_SUCCESS(status)) 269 | { 270 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 271 | "WdfDeviceCreate failed with status code 0x%x\n", status); 272 | 273 | return status; 274 | } 275 | 276 | { 277 | WDF_DEVICE_STATE deviceState; 278 | WDF_DEVICE_STATE_INIT(&deviceState); 279 | 280 | deviceState.NotDisableable = WdfFalse; 281 | WdfDeviceSetDeviceState(device, &deviceState); 282 | } 283 | 284 | WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); 285 | 286 | queueConfig.EvtIoInternalDeviceControl = CrosKBHIDRemapperEvtInternalDeviceControl; 287 | 288 | status = WdfIoQueueCreate(device, 289 | &queueConfig, 290 | WDF_NO_OBJECT_ATTRIBUTES, 291 | &queue 292 | ); 293 | 294 | if (!NT_SUCCESS(status)) 295 | { 296 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 297 | "WdfIoQueueCreate failed 0x%x\n", status); 298 | 299 | return status; 300 | } 301 | 302 | // 303 | // Create manual I/O queue to take care of hid report read requests 304 | // 305 | 306 | devContext = GetDeviceContext(device); 307 | 308 | WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); 309 | 310 | queueConfig.PowerManaged = WdfTrue; 311 | 312 | status = WdfIoQueueCreate(device, 313 | &queueConfig, 314 | WDF_NO_OBJECT_ATTRIBUTES, 315 | &devContext->ReportQueue 316 | ); 317 | 318 | if (!NT_SUCCESS(status)) 319 | { 320 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 321 | "WdfIoQueueCreate failed 0x%x\n", status); 322 | 323 | return status; 324 | } 325 | 326 | // 327 | // Initialize DeviceMode 328 | // 329 | 330 | devContext->DeviceMode = DEVICE_MODE_MOUSE; 331 | 332 | return status; 333 | } 334 | 335 | NTSTATUS 336 | CrosKBHIDRemapperEvtWdmPreprocessMnQueryId( 337 | WDFDEVICE Device, 338 | PIRP Irp 339 | ) 340 | { 341 | NTSTATUS status; 342 | PIO_STACK_LOCATION IrpStack, previousSp; 343 | PDEVICE_OBJECT DeviceObject; 344 | PWCHAR buffer; 345 | 346 | PAGED_CODE(); 347 | 348 | // 349 | // Get a pointer to the current location in the Irp 350 | // 351 | 352 | IrpStack = IoGetCurrentIrpStackLocation(Irp); 353 | 354 | // 355 | // Get the device object 356 | // 357 | DeviceObject = WdfDeviceWdmGetDeviceObject(Device); 358 | 359 | 360 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_PNP, 361 | "CrosKBHIDRemapperEvtWdmPreprocessMnQueryId Entry\n"); 362 | 363 | // 364 | // This check is required to filter out QUERY_IDs forwarded 365 | // by the HIDCLASS for the parent FDO. These IDs are sent 366 | // by PNP manager for the parent FDO if you root-enumerate this driver. 367 | // 368 | previousSp = ((PIO_STACK_LOCATION)((UCHAR *)(IrpStack)+ 369 | sizeof(IO_STACK_LOCATION))); 370 | 371 | if (previousSp->DeviceObject == DeviceObject) 372 | { 373 | // 374 | // Filtering out this basically prevents the Found New Hardware 375 | // popup for the root-enumerated CrosKBHIDRemapper on reboot. 376 | // 377 | status = Irp->IoStatus.Status; 378 | } 379 | else 380 | { 381 | switch (IrpStack->Parameters.QueryId.IdType) 382 | { 383 | case BusQueryDeviceID: 384 | case BusQueryHardwareIDs: 385 | // 386 | // HIDClass is asking for child deviceid & hardwareids. 387 | // Let us just make up some id for our child device. 388 | // 389 | buffer = (PWCHAR)ExAllocatePoolWithTag( 390 | NonPagedPool, 391 | CROSKBHIDREMAPPER_HARDWARE_IDS_LENGTH, 392 | CROSKBHIDREMAPPER_POOL_TAG 393 | ); 394 | 395 | if (buffer) 396 | { 397 | // 398 | // Do the copy, store the buffer in the Irp 399 | // 400 | RtlCopyMemory(buffer, 401 | CROSKBHIDREMAPPER_HARDWARE_IDS, 402 | CROSKBHIDREMAPPER_HARDWARE_IDS_LENGTH 403 | ); 404 | 405 | Irp->IoStatus.Information = (ULONG_PTR)buffer; 406 | status = STATUS_SUCCESS; 407 | } 408 | else 409 | { 410 | // 411 | // No memory 412 | // 413 | status = STATUS_INSUFFICIENT_RESOURCES; 414 | } 415 | 416 | Irp->IoStatus.Status = status; 417 | // 418 | // We don't need to forward this to our bus. This query 419 | // is for our child so we should complete it right here. 420 | // fallthru. 421 | // 422 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 423 | 424 | break; 425 | 426 | default: 427 | status = Irp->IoStatus.Status; 428 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 429 | break; 430 | } 431 | } 432 | 433 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 434 | "CrosKBHIDRemapperEvtWdmPreprocessMnQueryId Exit = 0x%x\n", status); 435 | 436 | return status; 437 | } 438 | 439 | VOID 440 | CrosKBHIDRemapperEvtInternalDeviceControl( 441 | IN WDFQUEUE Queue, 442 | IN WDFREQUEST Request, 443 | IN size_t OutputBufferLength, 444 | IN size_t InputBufferLength, 445 | IN ULONG IoControlCode 446 | ) 447 | { 448 | NTSTATUS status = STATUS_SUCCESS; 449 | WDFDEVICE device; 450 | PCROSKBHIDREMAPPER_CONTEXT devContext; 451 | BOOLEAN completeRequest = TRUE; 452 | 453 | UNREFERENCED_PARAMETER(OutputBufferLength); 454 | UNREFERENCED_PARAMETER(InputBufferLength); 455 | 456 | device = WdfIoQueueGetDevice(Queue); 457 | devContext = GetDeviceContext(device); 458 | 459 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 460 | "%s, Queue:0x%p, Request:0x%p\n", 461 | DbgHidInternalIoctlString(IoControlCode), 462 | Queue, 463 | Request 464 | ); 465 | 466 | // 467 | // Please note that HIDCLASS provides the buffer in the Irp->UserBuffer 468 | // field irrespective of the ioctl buffer type. However, framework is very 469 | // strict about type checking. You cannot get Irp->UserBuffer by using 470 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 471 | // internal ioctl. So depending on the ioctl code, we will either 472 | // use retreive function or escape to WDM to get the UserBuffer. 473 | // 474 | 475 | switch (IoControlCode) 476 | { 477 | 478 | case IOCTL_HID_GET_DEVICE_DESCRIPTOR: 479 | // 480 | // Retrieves the device's HID descriptor. 481 | // 482 | status = CrosKBHIDRemapperGetHidDescriptor(device, Request); 483 | break; 484 | 485 | case IOCTL_HID_GET_DEVICE_ATTRIBUTES: 486 | // 487 | //Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure. 488 | // 489 | status = CrosKBHIDRemapperGetDeviceAttributes(Request); 490 | break; 491 | 492 | case IOCTL_HID_GET_REPORT_DESCRIPTOR: 493 | // 494 | //Obtains the report descriptor for the HID device. 495 | // 496 | status = CrosKBHIDRemapperGetReportDescriptor(device, Request); 497 | break; 498 | 499 | case IOCTL_HID_GET_STRING: 500 | // 501 | // Requests that the HID minidriver retrieve a human-readable string 502 | // for either the manufacturer ID, the product ID, or the serial number 503 | // from the string descriptor of the device. The minidriver must send 504 | // a Get String Descriptor request to the device, in order to retrieve 505 | // the string descriptor, then it must extract the string at the 506 | // appropriate index from the string descriptor and return it in the 507 | // output buffer indicated by the IRP. Before sending the Get String 508 | // Descriptor request, the minidriver must retrieve the appropriate 509 | // index for the manufacturer ID, the product ID or the serial number 510 | // from the device extension of a top level collection associated with 511 | // the device. 512 | // 513 | status = CrosKBHIDRemapperGetString(Request); 514 | break; 515 | 516 | case IOCTL_HID_WRITE_REPORT: 517 | case IOCTL_HID_SET_OUTPUT_REPORT: 518 | // 519 | //Transmits a class driver-supplied report to the device. 520 | // 521 | status = CrosKBHIDRemapperWriteReport(devContext, Request); 522 | break; 523 | 524 | case IOCTL_HID_READ_REPORT: 525 | case IOCTL_HID_GET_INPUT_REPORT: 526 | // 527 | // Returns a report from the device into a class driver-supplied buffer. 528 | // 529 | status = CrosKBHIDRemapperReadReport(devContext, Request, &completeRequest); 530 | break; 531 | 532 | case IOCTL_HID_SET_FEATURE: 533 | // 534 | // This sends a HID class feature report to a top-level collection of 535 | // a HID class device. 536 | // 537 | status = CrosKBHIDRemapperSetFeature(devContext, Request, &completeRequest); 538 | break; 539 | 540 | case IOCTL_HID_GET_FEATURE: 541 | // 542 | // returns a feature report associated with a top-level collection 543 | // 544 | status = CrosKBHIDRemapperGetFeature(devContext, Request, &completeRequest); 545 | break; 546 | 547 | case IOCTL_HID_ACTIVATE_DEVICE: 548 | // 549 | // Makes the device ready for I/O operations. 550 | // 551 | case IOCTL_HID_DEACTIVATE_DEVICE: 552 | // 553 | // Causes the device to cease operations and terminate all outstanding 554 | // I/O requests. 555 | // 556 | default: 557 | status = STATUS_NOT_SUPPORTED; 558 | break; 559 | } 560 | 561 | if (completeRequest) 562 | { 563 | WdfRequestComplete(Request, status); 564 | 565 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 566 | "%s completed, Queue:0x%p, Request:0x%p\n", 567 | DbgHidInternalIoctlString(IoControlCode), 568 | Queue, 569 | Request 570 | ); 571 | } 572 | else 573 | { 574 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 575 | "%s deferred, Queue:0x%p, Request:0x%p\n", 576 | DbgHidInternalIoctlString(IoControlCode), 577 | Queue, 578 | Request 579 | ); 580 | } 581 | 582 | return; 583 | } 584 | 585 | NTSTATUS 586 | CrosKBHIDRemapperGetHidDescriptor( 587 | IN WDFDEVICE Device, 588 | IN WDFREQUEST Request 589 | ) 590 | { 591 | NTSTATUS status = STATUS_SUCCESS; 592 | size_t bytesToCopy = 0; 593 | WDFMEMORY memory; 594 | 595 | UNREFERENCED_PARAMETER(Device); 596 | 597 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 598 | "CrosKBHIDRemapperGetHidDescriptor Entry\n"); 599 | 600 | // 601 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 602 | // will correctly retrieve buffer from Irp->UserBuffer. 603 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 604 | // field irrespective of the ioctl buffer type. However, framework is very 605 | // strict about type checking. You cannot get Irp->UserBuffer by using 606 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 607 | // internal ioctl. 608 | // 609 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 610 | 611 | if (!NT_SUCCESS(status)) 612 | { 613 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 614 | "WdfRequestRetrieveOutputMemory failed 0x%x\n", status); 615 | 616 | return status; 617 | } 618 | 619 | // 620 | // Use hardcoded "HID Descriptor" 621 | // 622 | bytesToCopy = DefaultHidDescriptor.bLength; 623 | 624 | if (bytesToCopy == 0) 625 | { 626 | status = STATUS_INVALID_DEVICE_STATE; 627 | 628 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 629 | "DefaultHidDescriptor is zero, 0x%x\n", status); 630 | 631 | return status; 632 | } 633 | 634 | status = WdfMemoryCopyFromBuffer(memory, 635 | 0, // Offset 636 | (PVOID)&DefaultHidDescriptor, 637 | bytesToCopy); 638 | 639 | if (!NT_SUCCESS(status)) 640 | { 641 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 642 | "WdfMemoryCopyFromBuffer failed 0x%x\n", status); 643 | 644 | return status; 645 | } 646 | 647 | // 648 | // Report how many bytes were copied 649 | // 650 | WdfRequestSetInformation(Request, bytesToCopy); 651 | 652 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 653 | "CrosKBHIDRemapperGetHidDescriptor Exit = 0x%x\n", status); 654 | 655 | return status; 656 | } 657 | 658 | NTSTATUS 659 | CrosKBHIDRemapperGetReportDescriptor( 660 | IN WDFDEVICE Device, 661 | IN WDFREQUEST Request 662 | ) 663 | { 664 | NTSTATUS status = STATUS_SUCCESS; 665 | ULONG_PTR bytesToCopy; 666 | WDFMEMORY memory; 667 | 668 | UNREFERENCED_PARAMETER(Device); 669 | 670 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 671 | "CrosKBHIDRemapperGetReportDescriptor Entry\n"); 672 | 673 | // 674 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 675 | // will correctly retrieve buffer from Irp->UserBuffer. 676 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 677 | // field irrespective of the ioctl buffer type. However, framework is very 678 | // strict about type checking. You cannot get Irp->UserBuffer by using 679 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 680 | // internal ioctl. 681 | // 682 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 683 | if (!NT_SUCCESS(status)) 684 | { 685 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 686 | "WdfRequestRetrieveOutputMemory failed 0x%x\n", status); 687 | 688 | return status; 689 | } 690 | 691 | // 692 | // Use hardcoded Report descriptor 693 | // 694 | bytesToCopy = DefaultHidDescriptor.DescriptorList[0].wReportLength; 695 | 696 | if (bytesToCopy == 0) 697 | { 698 | status = STATUS_INVALID_DEVICE_STATE; 699 | 700 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 701 | "DefaultHidDescriptor's reportLength is zero, 0x%x\n", status); 702 | 703 | return status; 704 | } 705 | 706 | status = WdfMemoryCopyFromBuffer(memory, 707 | 0, 708 | (PVOID)DefaultReportDescriptor, 709 | bytesToCopy); 710 | if (!NT_SUCCESS(status)) 711 | { 712 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 713 | "WdfMemoryCopyFromBuffer failed 0x%x\n", status); 714 | 715 | return status; 716 | } 717 | 718 | // 719 | // Report how many bytes were copied 720 | // 721 | WdfRequestSetInformation(Request, bytesToCopy); 722 | 723 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 724 | "CrosKBHIDRemapperGetReportDescriptor Exit = 0x%x\n", status); 725 | 726 | return status; 727 | } 728 | 729 | 730 | NTSTATUS 731 | CrosKBHIDRemapperGetDeviceAttributes( 732 | IN WDFREQUEST Request 733 | ) 734 | { 735 | NTSTATUS status = STATUS_SUCCESS; 736 | PHID_DEVICE_ATTRIBUTES deviceAttributes = NULL; 737 | 738 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 739 | "CrosKBHIDRemapperGetDeviceAttributes Entry\n"); 740 | 741 | // 742 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 743 | // will correctly retrieve buffer from Irp->UserBuffer. 744 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 745 | // field irrespective of the ioctl buffer type. However, framework is very 746 | // strict about type checking. You cannot get Irp->UserBuffer by using 747 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 748 | // internal ioctl. 749 | // 750 | status = WdfRequestRetrieveOutputBuffer(Request, 751 | sizeof(HID_DEVICE_ATTRIBUTES), 752 | (PVOID *)&deviceAttributes, 753 | NULL); 754 | if (!NT_SUCCESS(status)) 755 | { 756 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 757 | "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); 758 | 759 | return status; 760 | } 761 | 762 | // 763 | // Set USB device descriptor 764 | // 765 | 766 | deviceAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES); 767 | deviceAttributes->VendorID = CROSKBHIDREMAPPER_VID; 768 | deviceAttributes->ProductID = CROSKBHIDREMAPPER_PID; 769 | deviceAttributes->VersionNumber = CROSKBHIDREMAPPER_VERSION; 770 | 771 | // 772 | // Report how many bytes were copied 773 | // 774 | WdfRequestSetInformation(Request, sizeof(HID_DEVICE_ATTRIBUTES)); 775 | 776 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 777 | "CrosKBHIDRemapperGetDeviceAttributes Exit = 0x%x\n", status); 778 | 779 | return status; 780 | } 781 | 782 | NTSTATUS 783 | CrosKBHIDRemapperGetString( 784 | IN WDFREQUEST Request 785 | ) 786 | { 787 | 788 | NTSTATUS status = STATUS_SUCCESS; 789 | PWSTR pwstrID; 790 | size_t lenID; 791 | WDF_REQUEST_PARAMETERS params; 792 | void *pStringBuffer = NULL; 793 | 794 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 795 | "CrosKBHIDRemapperGetString Entry\n"); 796 | 797 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 798 | WdfRequestGetParameters(Request, ¶ms); 799 | 800 | switch ((ULONG_PTR)params.Parameters.DeviceIoControl.Type3InputBuffer & 0xFFFF) 801 | { 802 | case HID_STRING_ID_IMANUFACTURER: 803 | pwstrID = L"CrosKBHIDRemapper.\0"; 804 | break; 805 | 806 | case HID_STRING_ID_IPRODUCT: 807 | pwstrID = L"MaxTouch Touch Screen\0"; 808 | break; 809 | 810 | case HID_STRING_ID_ISERIALNUMBER: 811 | pwstrID = L"123123123\0"; 812 | break; 813 | 814 | default: 815 | pwstrID = NULL; 816 | break; 817 | } 818 | 819 | lenID = pwstrID ? wcslen(pwstrID)*sizeof(WCHAR) + sizeof(UNICODE_NULL) : 0; 820 | 821 | if (pwstrID == NULL) 822 | { 823 | 824 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 825 | "CrosKBHIDRemapperGetString Invalid request type\n"); 826 | 827 | status = STATUS_INVALID_PARAMETER; 828 | 829 | return status; 830 | } 831 | 832 | status = WdfRequestRetrieveOutputBuffer(Request, 833 | lenID, 834 | &pStringBuffer, 835 | &lenID); 836 | 837 | if (!NT_SUCCESS(status)) 838 | { 839 | 840 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 841 | "CrosKBHIDRemapperGetString WdfRequestRetrieveOutputBuffer failed Status 0x%x\n", status); 842 | 843 | return status; 844 | } 845 | 846 | RtlCopyMemory(pStringBuffer, pwstrID, lenID); 847 | 848 | WdfRequestSetInformation(Request, lenID); 849 | 850 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 851 | "CrosKBHIDRemapperGetString Exit = 0x%x\n", status); 852 | 853 | return status; 854 | } 855 | 856 | NTSTATUS 857 | CrosKBHIDRemapperWriteReport( 858 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 859 | IN WDFREQUEST Request 860 | ) 861 | { 862 | NTSTATUS status = STATUS_SUCCESS; 863 | WDF_REQUEST_PARAMETERS params; 864 | PHID_XFER_PACKET transferPacket = NULL; 865 | 866 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 867 | "CrosKBHIDRemapperWriteReport Entry\n"); 868 | 869 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 870 | WdfRequestGetParameters(Request, ¶ms); 871 | 872 | if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) 873 | { 874 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 875 | "CrosKBHIDRemapperWriteReport Xfer packet too small\n"); 876 | 877 | status = STATUS_BUFFER_TOO_SMALL; 878 | } 879 | else 880 | { 881 | 882 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 883 | 884 | if (transferPacket == NULL) 885 | { 886 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 887 | "CrosKBHIDRemapperWriteReport No xfer packet\n"); 888 | 889 | status = STATUS_INVALID_DEVICE_REQUEST; 890 | } 891 | else 892 | { 893 | // 894 | // switch on the report id 895 | // 896 | 897 | switch (transferPacket->reportId) 898 | { 899 | case REPORTID_SETTINGS: { 900 | CrosKBHIDRemapperSettingsReport *pReport = (CrosKBHIDRemapperSettingsReport *)transferPacket->reportBuffer; 901 | 902 | int reg = pReport->SettingsRegister; 903 | int val = pReport->SettingsValue; 904 | UNREFERENCED_PARAMETER(val); 905 | 906 | if (reg == SETTINGS_REG_RELOADSETTINGS) { 907 | DbgPrint("Vivaldi: Sending Reload Settings!\n"); 908 | 909 | (*DevContext->CrosKBHidInterface.ReloadSettings)( 910 | DevContext->CrosKBHidInterface.InterfaceHeader.Context 911 | ); 912 | } 913 | } 914 | default: 915 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 916 | "CrosKBHIDRemapperWriteReport Unhandled report type %d\n", transferPacket->reportId); 917 | 918 | status = STATUS_INVALID_PARAMETER; 919 | 920 | break; 921 | } 922 | } 923 | } 924 | 925 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 926 | "CrosKBHIDRemapperWriteReport Exit = 0x%x\n", status); 927 | 928 | return status; 929 | 930 | } 931 | 932 | NTSTATUS 933 | CrosKBHIDRemapperProcessVendorReport( 934 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 935 | IN PVOID ReportBuffer, 936 | IN ULONG ReportBufferLen, 937 | OUT size_t* BytesWritten 938 | ) 939 | { 940 | NTSTATUS status = STATUS_SUCCESS; 941 | WDFREQUEST reqRead; 942 | PVOID pReadReport = NULL; 943 | size_t bytesReturned = 0; 944 | 945 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 946 | "CrosKBHIDRemapperProcessVendorReport Entry\n"); 947 | 948 | status = WdfIoQueueRetrieveNextRequest(DevContext->ReportQueue, 949 | &reqRead); 950 | 951 | if (NT_SUCCESS(status)) 952 | { 953 | status = WdfRequestRetrieveOutputBuffer(reqRead, 954 | ReportBufferLen, 955 | &pReadReport, 956 | &bytesReturned); 957 | 958 | if (NT_SUCCESS(status)) 959 | { 960 | // 961 | // Copy ReportBuffer into read request 962 | // 963 | 964 | if (bytesReturned > ReportBufferLen) 965 | { 966 | bytesReturned = ReportBufferLen; 967 | } 968 | 969 | RtlCopyMemory(pReadReport, 970 | ReportBuffer, 971 | bytesReturned); 972 | 973 | // 974 | // Complete read with the number of bytes returned as info 975 | // 976 | 977 | WdfRequestCompleteWithInformation(reqRead, 978 | status, 979 | bytesReturned); 980 | 981 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 982 | "CrosKBHIDRemapperProcessVendorReport %d bytes returned\n", bytesReturned); 983 | 984 | // 985 | // Return the number of bytes written for the write request completion 986 | // 987 | 988 | *BytesWritten = bytesReturned; 989 | 990 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 991 | "%s completed, Queue:0x%p, Request:0x%p\n", 992 | DbgHidInternalIoctlString(IOCTL_HID_READ_REPORT), 993 | DevContext->ReportQueue, 994 | reqRead); 995 | } 996 | else 997 | { 998 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 999 | "WdfRequestRetrieveOutputBuffer failed Status 0x%x\n", status); 1000 | } 1001 | } 1002 | else 1003 | { 1004 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1005 | "WdfIoQueueRetrieveNextRequest failed Status 0x%x\n", status); 1006 | } 1007 | 1008 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1009 | "CrosKBHIDRemapperProcessVendorReport Exit = 0x%x\n", status); 1010 | 1011 | return status; 1012 | } 1013 | 1014 | NTSTATUS 1015 | CrosKBHIDRemapperReadReport( 1016 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 1017 | IN WDFREQUEST Request, 1018 | OUT BOOLEAN* CompleteRequest 1019 | ) 1020 | { 1021 | NTSTATUS status = STATUS_SUCCESS; 1022 | 1023 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1024 | "CrosKBHIDRemapperReadReport Entry\n"); 1025 | 1026 | // 1027 | // Forward this read request to our manual queue 1028 | // (in other words, we are going to defer this request 1029 | // until we have a corresponding write request to 1030 | // match it with) 1031 | // 1032 | 1033 | status = WdfRequestForwardToIoQueue(Request, DevContext->ReportQueue); 1034 | 1035 | if (!NT_SUCCESS(status)) 1036 | { 1037 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1038 | "WdfRequestForwardToIoQueue failed Status 0x%x\n", status); 1039 | } 1040 | else 1041 | { 1042 | *CompleteRequest = FALSE; 1043 | } 1044 | 1045 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1046 | "CrosKBHIDRemapperReadReport Exit = 0x%x\n", status); 1047 | 1048 | return status; 1049 | } 1050 | 1051 | NTSTATUS 1052 | CrosKBHIDRemapperSetFeature( 1053 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 1054 | IN WDFREQUEST Request, 1055 | OUT BOOLEAN* CompleteRequest 1056 | ) 1057 | { 1058 | NTSTATUS status = STATUS_SUCCESS; 1059 | WDF_REQUEST_PARAMETERS params; 1060 | PHID_XFER_PACKET transferPacket = NULL; 1061 | 1062 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1063 | "CrosKBHIDRemapperSetFeature Entry\n"); 1064 | 1065 | UNREFERENCED_PARAMETER(DevContext); 1066 | UNREFERENCED_PARAMETER(CompleteRequest); 1067 | 1068 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1069 | WdfRequestGetParameters(Request, ¶ms); 1070 | 1071 | if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) 1072 | { 1073 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1074 | "CrosKBHIDRemapperSetFeature Xfer packet too small\n"); 1075 | 1076 | status = STATUS_BUFFER_TOO_SMALL; 1077 | } 1078 | else 1079 | { 1080 | 1081 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1082 | 1083 | if (transferPacket == NULL) 1084 | { 1085 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1086 | "CrosKBHIDRemapperWriteReport No xfer packet\n"); 1087 | 1088 | status = STATUS_INVALID_DEVICE_REQUEST; 1089 | } 1090 | else 1091 | { 1092 | // 1093 | // switch on the report id 1094 | // 1095 | 1096 | switch (transferPacket->reportId) 1097 | { 1098 | default: 1099 | 1100 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1101 | "CrosKBHIDRemapperSetFeature Unhandled report type %d\n", transferPacket->reportId); 1102 | 1103 | status = STATUS_INVALID_PARAMETER; 1104 | 1105 | break; 1106 | } 1107 | } 1108 | } 1109 | 1110 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1111 | "CrosKBHIDRemapperSetFeature Exit = 0x%x\n", status); 1112 | 1113 | return status; 1114 | } 1115 | 1116 | NTSTATUS 1117 | CrosKBHIDRemapperGetFeature( 1118 | IN PCROSKBHIDREMAPPER_CONTEXT DevContext, 1119 | IN WDFREQUEST Request, 1120 | OUT BOOLEAN* CompleteRequest 1121 | ) 1122 | { 1123 | NTSTATUS status = STATUS_SUCCESS; 1124 | WDF_REQUEST_PARAMETERS params; 1125 | PHID_XFER_PACKET transferPacket = NULL; 1126 | 1127 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1128 | "CrosKBHIDRemapperGetFeature Entry\n"); 1129 | 1130 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1131 | WdfRequestGetParameters(Request, ¶ms); 1132 | 1133 | UNREFERENCED_PARAMETER(DevContext); 1134 | UNREFERENCED_PARAMETER(CompleteRequest); 1135 | 1136 | if (params.Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_XFER_PACKET)) 1137 | { 1138 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1139 | "CrosKBHIDRemapperGetFeature Xfer packet too small\n"); 1140 | 1141 | status = STATUS_BUFFER_TOO_SMALL; 1142 | } 1143 | else 1144 | { 1145 | 1146 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1147 | 1148 | if (transferPacket == NULL) 1149 | { 1150 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1151 | "CrosKBHIDRemapperGetFeature No xfer packet\n"); 1152 | 1153 | status = STATUS_INVALID_DEVICE_REQUEST; 1154 | } 1155 | else 1156 | { 1157 | // 1158 | // switch on the report id 1159 | // 1160 | 1161 | switch (transferPacket->reportId) 1162 | { 1163 | default: 1164 | 1165 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1166 | "CrosKBHIDRemapperGetFeature Unhandled report type %d\n", transferPacket->reportId); 1167 | 1168 | status = STATUS_INVALID_PARAMETER; 1169 | 1170 | break; 1171 | } 1172 | } 1173 | } 1174 | 1175 | CrosKBHIDRemapperPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1176 | "CrosKBHIDRemapperGetFeature Exit = 0x%x\n", status); 1177 | 1178 | return status; 1179 | } 1180 | 1181 | PCHAR 1182 | DbgHidInternalIoctlString( 1183 | IN ULONG IoControlCode 1184 | ) 1185 | { 1186 | switch (IoControlCode) 1187 | { 1188 | case IOCTL_HID_GET_DEVICE_DESCRIPTOR: 1189 | return "IOCTL_HID_GET_DEVICE_DESCRIPTOR"; 1190 | case IOCTL_HID_GET_REPORT_DESCRIPTOR: 1191 | return "IOCTL_HID_GET_REPORT_DESCRIPTOR"; 1192 | case IOCTL_HID_READ_REPORT: 1193 | return "IOCTL_HID_READ_REPORT"; 1194 | case IOCTL_HID_GET_DEVICE_ATTRIBUTES: 1195 | return "IOCTL_HID_GET_DEVICE_ATTRIBUTES"; 1196 | case IOCTL_HID_WRITE_REPORT: 1197 | return "IOCTL_HID_WRITE_REPORT"; 1198 | case IOCTL_HID_SET_FEATURE: 1199 | return "IOCTL_HID_SET_FEATURE"; 1200 | case IOCTL_HID_GET_FEATURE: 1201 | return "IOCTL_HID_GET_FEATURE"; 1202 | case IOCTL_HID_GET_STRING: 1203 | return "IOCTL_HID_GET_STRING"; 1204 | case IOCTL_HID_ACTIVATE_DEVICE: 1205 | return "IOCTL_HID_ACTIVATE_DEVICE"; 1206 | case IOCTL_HID_DEACTIVATE_DEVICE: 1207 | return "IOCTL_HID_DEACTIVATE_DEVICE"; 1208 | case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: 1209 | return "IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST"; 1210 | case IOCTL_HID_SET_OUTPUT_REPORT: 1211 | return "IOCTL_HID_SET_OUTPUT_REPORT"; 1212 | case IOCTL_HID_GET_INPUT_REPORT: 1213 | return "IOCTL_HID_GET_INPUT_REPORT"; 1214 | default: 1215 | return "Unknown IOCTL"; 1216 | } 1217 | } 1218 | --------------------------------------------------------------------------------