mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 00:31:31 +00:00
[idd] input: report volume keys as consumer controls
Expose a Consumer Control HID report for the system volume usages that Windows does not handle through the Keyboard/Keypad usage page. Translate the existing mute and volume keyboard usages at the LGInput boundary, preserve normal keyboard state, and force a neutral consumer report across resets and HID device reactivation.
This commit is contained in:
@@ -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;
|
||||
@@ -329,6 +330,7 @@ static NTSTATUS DeactivateDevice(_Inout_ HIDDeviceContext * context)
|
||||
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<const HIDConsumerReport *>(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<const HIDConsumerReport *>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -27,6 +27,14 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user