Reputation: 72
I came across a problem while I was coding a test application (WPF, C#, .NET 4.7) for my homemade keyboard. The keyboard connects via USB and shows up as a HID-device of the keyboard type. Now I want to send some data (config, backlight info, ...) to the keyboard.
On the keyboard side there is an ARM microcontroller, which initializes itself with a HID-Report-Descriptor for a keyboard, containing an extra OUTPUT tag for some config data to be sent to the keyboard. (4 bytes)
Here is the current report descriptor of the MCU:
__ALIGN_BEGIN static uint8_t
JKP_HID_ReportDesc_FS[USBD_JKP_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs) ; Modifier Byte (1 byte)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs) ; Reserved Byte (1 byte)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x91, 0x02, // OUTPUT (Data,Var,Abs) ; LED Report
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs) ; LED Report Padding (LEDs 1 byte)
0x95, USBD_JKP_HID_REPORT_KEY_ROLLOVER, // REPORT_COUNT (USBD_JKP_HID_REPORT_KEY_ROLLOVER)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs) ; Key Arrays (6 bytes)
0x06, 0x00, 0xff, // USAGE_PAGE(Vendor Defined Page 1)
0x09, 0x01, // USAGE(Venor Usage 1)
0x15, 0x00, // LOGICAL_MINIMUM(0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM(255)
0x75, 0x08, // REPORT_SIZE(8)
0x95, 0x04, // REPORT_COUNT(4)
0x91, 0x02, // OUTPUT(Data,Var,Abs) ; JKP Config Info (4 bytes)
0xc0 // END_COLLECTION
};
On the side of the PC, I have a WPF application, written in C# and utilizing the Windows.Devices.HumanInterfaceDevice API.
Here is the code of the WPF app:
Console.WriteLine("Init HID Device Write...");
byte[] data = new byte[] { 0x00, 0xaa, 0xaa, 0xaa, 0xaa};
string device_selector = HidDevice.GetDeviceSelector(0x01, 0x06, 1155, 1024);
var devices = await DeviceInformation.FindAllAsync(device_selector);
if (devices.Any())
{
Console.WriteLine("HID Devices Found: " + devices.Count);
DeviceInformation devinfo = devices[0];
Console.WriteLine($"HID Selected Device Info: ID: {devinfo.Id}, Name: {devinfo.Name}");
HidDevice device = await HidDevice.FromIdAsync(devinfo.Id, Windows.Storage.FileAccessMode.ReadWrite);
if (device != null)
{
Console.WriteLine("HID Device writing...");
HidOutputReport report = device.CreateOutputReport(2);
DataWriter dataWriter = new DataWriter();
dataWriter.WriteBytes(data);
report.Data = dataWriter.DetachBuffer();
await device.SendOutputReportAsync(report);
}
else
{
Console.WriteLine("Failed to open HID device.");
}
}
else
{
Console.WriteLine("No devices found.");
}
Although the keyboard device is found, the Windows.Devices.HumanInterfaceDevice API blocks all connections to keyboard-type HID devices.
Is there an alternative to the Windows API that will support such connections?
I've already tried HIDSharp and hidlibrary. Also, I do not want to use an USB-Composite-Device.
Thanks in advance.
Upvotes: 2
Views: 2681
Reputation: 1421
You cannot communicate with HID devices with keyboard usage (with 0x01 Usage Page and 0x06 Usage ID) on Windows because they are opened in Exclusive mode by RIM (Raw Input Manager). This is done as security measure against keyloggers. See https://learn.microsoft.com/windows-hardware/drivers/hid/hid-architecture#hid-clients-supported-in-windows
As a workaround I can recommend to add another top level collection within 0xFF00 Usage Page (Vendor specific) in your HID descriptor and send\receive your custom data in it. This way system HID driver will create two device interfaces - one for keyboard (that you cannot read/write) and other for your custom device usage (can be freely used from apps). See https://learn.microsoft.com/windows-hardware/drivers/hid/top-level-collections
This is how Logitech Unifying Receiver have showed in Windows Device Manager with its Usage Page 0xFFBC and Usage 0x0088 vendor-defined device:
Upvotes: 1