diff --git a/idd/LGInput/CHIDDevice.cpp b/idd/LGInput/CHIDDevice.cpp index 16d2f670..f98839cd 100644 --- a/idd/LGInput/CHIDDevice.cpp +++ b/idd/LGInput/CHIDDevice.cpp @@ -59,6 +59,7 @@ struct HIDDeviceContext size_t reportCount; uint32_t relativeButtons; uint32_t absoluteButtons; + uint16_t consumerUsage; bool absoluteValid; uint16_t absoluteX; uint16_t absoluteY; @@ -326,9 +327,10 @@ static NTSTATUS DeactivateDevice(_Inout_ HIDDeviceContext * context) if (context->stopping) return STATUS_DEVICE_NOT_READY; - context->active = false; - context->reportHead = 0; - context->reportCount = 0; + context->active = false; + context->reportHead = 0; + context->reportCount = 0; + context->consumerUsage = UINT16_MAX; } WdfIoQueuePurgeSynchronously(context->reportQueue); return STATUS_SUCCESS; @@ -449,6 +451,11 @@ NTSTATUS CHIDDevice::SubmitReport( status = STATUS_DEVICE_NOT_READY; else { + if (reportId == HID_REPORT_ID_CONSUMER && + context->consumerUsage == + static_cast(report)->usage) + return STATUS_SUCCESS; + bool pureMotion = false; switch (reportId) { @@ -510,6 +517,11 @@ NTSTATUS CHIDDevice::SubmitReport( break; } + case HID_REPORT_ID_CONSUMER: + context->consumerUsage = + static_cast(report)->usage; + break; + default: break; } @@ -546,6 +558,7 @@ NTSTATUS CHIDDevice::ResetReports() context->mouseMode = 0; context->relativeButtons = 0; context->absoluteButtons = 0; + context->consumerUsage = UINT16_MAX; } const HIDMouseRelativeReport relative = { @@ -558,6 +571,9 @@ NTSTATUS CHIDDevice::ResetReports() const HIDKeyboardReport keyboard = { HID_REPORT_ID_KEYBOARD, }; + const HIDConsumerReport consumer = { + HID_REPORT_ID_CONSUMER, + }; NTSTATUS status = SubmitReport(&relative, sizeof(relative)); if (absoluteValid) @@ -578,6 +594,10 @@ NTSTATUS CHIDDevice::ResetReports() SubmitReport(&keyboard, sizeof(keyboard)); if (NT_SUCCESS(status)) status = keyboardStatus; + const NTSTATUS consumerStatus = + SubmitReport(&consumer, sizeof(consumer)); + if (NT_SUCCESS(status)) + status = consumerStatus; return status; } diff --git a/idd/LGInput/HIDReports.cpp b/idd/LGInput/HIDReports.cpp index 472570e1..f17d8e5d 100644 --- a/idd/LGInput/HIDReports.cpp +++ b/idd/LGInput/HIDReports.cpp @@ -120,6 +120,20 @@ static const uint8_t REPORT_DESCRIPTOR[] = 0x95, 0x06, // Report Count (6) 0x81, 0x00, // Input (Data, Array, Absolute) 0xC0, // End Collection + + // Consumer control, report ID 4. + 0x05, 0x0C, // Usage Page (Consumer) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, HID_REPORT_ID_CONSUMER, + 0x19, 0x00, // Usage Minimum (Unassigned) + 0x2A, 0xFF, 0x03, // Usage Maximum (1023) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x75, 0x10, // Report Size (16) + 0x95, 0x01, // Report Count (1) + 0x81, 0x00, // Input (Data, Array, Absolute) + 0xC0, // End Collection }; const uint8_t * HIDGetReportDescriptor() @@ -145,6 +159,9 @@ size_t HIDGetInputReportSize(uint8_t reportId) case HID_REPORT_ID_KEYBOARD: return sizeof(HIDKeyboardReport); + case HID_REPORT_ID_CONSUMER: + return sizeof(HIDConsumerReport); + default: return 0; } diff --git a/idd/LGInput/HIDReports.h b/idd/LGInput/HIDReports.h index 8781c142..ef7986b3 100644 --- a/idd/LGInput/HIDReports.h +++ b/idd/LGInput/HIDReports.h @@ -28,6 +28,7 @@ enum HIDReportId : uint8_t HID_REPORT_ID_MOUSE_ABSOLUTE = 1, HID_REPORT_ID_MOUSE_RELATIVE = 2, HID_REPORT_ID_KEYBOARD = 3, + HID_REPORT_ID_CONSUMER = 4, }; #pragma pack(push, 1) @@ -64,12 +65,19 @@ struct HIDKeyboardLedsReport uint8_t leds; }; +struct HIDConsumerReport +{ + uint8_t reportId; + uint16_t usage; +}; + #pragma pack(pop) static_assert(sizeof(HIDMouseAbsoluteReport) == 10); static_assert(sizeof(HIDMouseRelativeReport) == 10); static_assert(sizeof(HIDKeyboardReport) == 9); static_assert(sizeof(HIDKeyboardLedsReport) == 2); +static_assert(sizeof(HIDConsumerReport) == 3); static constexpr size_t HID_MAX_INPUT_REPORT_SIZE = sizeof(HIDMouseAbsoluteReport); diff --git a/idd/LGInput/ipc/CInputPipeClient.cpp b/idd/LGInput/ipc/CInputPipeClient.cpp index 54857c12..3f84faed 100644 --- a/idd/LGInput/ipc/CInputPipeClient.cpp +++ b/idd/LGInput/ipc/CInputPipeClient.cpp @@ -27,6 +27,14 @@ #include +static constexpr uint8_t HID_KEYBOARD_USAGE_MUTE = 0x7f; +static constexpr uint8_t HID_KEYBOARD_USAGE_VOLUME_UP = 0x80; +static constexpr uint8_t HID_KEYBOARD_USAGE_VOLUME_DOWN = 0x81; + +static constexpr uint16_t HID_CONSUMER_USAGE_MUTE = 0xe2; +static constexpr uint16_t HID_CONSUMER_USAGE_VOLUME_UP = 0xe9; +static constexpr uint16_t HID_CONSUMER_USAGE_VOLUME_DOWN = 0xea; + bool CInputPipeClient::Start() { m_lastSequence = 0; @@ -209,14 +217,45 @@ bool CInputPipeClient::HandleKeyboard( HIDKeyboardReport report = {}; report.reportId = HID_REPORT_ID_KEYBOARD; report.modifiers = input.modifiers; + // The Consumer Control report carries one active array usage. + uint16_t consumerUsage = 0; + size_t keyIndex = 0; for (size_t i = 0; i < LG_INPUT_KEYBOARD_KEY_COUNT; ++i) { if (input.keys[i] > LG_INPUT_KEYBOARD_USAGE_MAX) return false; - report.keys[i] = input.keys[i]; + + switch (input.keys[i]) + { + case HID_KEYBOARD_USAGE_MUTE: + if (!consumerUsage) + consumerUsage = HID_CONSUMER_USAGE_MUTE; + break; + + case HID_KEYBOARD_USAGE_VOLUME_UP: + if (!consumerUsage) + consumerUsage = HID_CONSUMER_USAGE_VOLUME_UP; + break; + + case HID_KEYBOARD_USAGE_VOLUME_DOWN: + if (!consumerUsage) + consumerUsage = HID_CONSUMER_USAGE_VOLUME_DOWN; + break; + + default: + report.keys[keyIndex++] = input.keys[i]; + break; + } } - return SubmitReport(&report, sizeof(report)); + if (!SubmitReport(&report, sizeof(report))) + return false; + + const HIDConsumerReport consumer = { + HID_REPORT_ID_CONSUMER, + consumerUsage, + }; + return SubmitReport(&consumer, sizeof(consumer)); } bool CInputPipeClient::SubmitReport( diff --git a/idd/LGInput/ipc/CInputPipeClient.h b/idd/LGInput/ipc/CInputPipeClient.h index 79f70aff..fcc4a6ec 100644 --- a/idd/LGInput/ipc/CInputPipeClient.h +++ b/idd/LGInput/ipc/CInputPipeClient.h @@ -43,5 +43,5 @@ private: bool SubmitReport(const void * report, size_t size); CPipeEndpoint m_endpoint; - uint64_t m_lastSequence = 0; + uint64_t m_lastSequence = 0; };