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;
|
size_t reportCount;
|
||||||
uint32_t relativeButtons;
|
uint32_t relativeButtons;
|
||||||
uint32_t absoluteButtons;
|
uint32_t absoluteButtons;
|
||||||
|
uint16_t consumerUsage;
|
||||||
bool absoluteValid;
|
bool absoluteValid;
|
||||||
uint16_t absoluteX;
|
uint16_t absoluteX;
|
||||||
uint16_t absoluteY;
|
uint16_t absoluteY;
|
||||||
@@ -329,6 +330,7 @@ static NTSTATUS DeactivateDevice(_Inout_ HIDDeviceContext * context)
|
|||||||
context->active = false;
|
context->active = false;
|
||||||
context->reportHead = 0;
|
context->reportHead = 0;
|
||||||
context->reportCount = 0;
|
context->reportCount = 0;
|
||||||
|
context->consumerUsage = UINT16_MAX;
|
||||||
}
|
}
|
||||||
WdfIoQueuePurgeSynchronously(context->reportQueue);
|
WdfIoQueuePurgeSynchronously(context->reportQueue);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
@@ -449,6 +451,11 @@ NTSTATUS CHIDDevice::SubmitReport(
|
|||||||
status = STATUS_DEVICE_NOT_READY;
|
status = STATUS_DEVICE_NOT_READY;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (reportId == HID_REPORT_ID_CONSUMER &&
|
||||||
|
context->consumerUsage ==
|
||||||
|
static_cast<const HIDConsumerReport *>(report)->usage)
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
bool pureMotion = false;
|
bool pureMotion = false;
|
||||||
switch (reportId)
|
switch (reportId)
|
||||||
{
|
{
|
||||||
@@ -510,6 +517,11 @@ NTSTATUS CHIDDevice::SubmitReport(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case HID_REPORT_ID_CONSUMER:
|
||||||
|
context->consumerUsage =
|
||||||
|
static_cast<const HIDConsumerReport *>(report)->usage;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -546,6 +558,7 @@ NTSTATUS CHIDDevice::ResetReports()
|
|||||||
context->mouseMode = 0;
|
context->mouseMode = 0;
|
||||||
context->relativeButtons = 0;
|
context->relativeButtons = 0;
|
||||||
context->absoluteButtons = 0;
|
context->absoluteButtons = 0;
|
||||||
|
context->consumerUsage = UINT16_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HIDMouseRelativeReport relative = {
|
const HIDMouseRelativeReport relative = {
|
||||||
@@ -558,6 +571,9 @@ NTSTATUS CHIDDevice::ResetReports()
|
|||||||
const HIDKeyboardReport keyboard = {
|
const HIDKeyboardReport keyboard = {
|
||||||
HID_REPORT_ID_KEYBOARD,
|
HID_REPORT_ID_KEYBOARD,
|
||||||
};
|
};
|
||||||
|
const HIDConsumerReport consumer = {
|
||||||
|
HID_REPORT_ID_CONSUMER,
|
||||||
|
};
|
||||||
|
|
||||||
NTSTATUS status = SubmitReport(&relative, sizeof(relative));
|
NTSTATUS status = SubmitReport(&relative, sizeof(relative));
|
||||||
if (absoluteValid)
|
if (absoluteValid)
|
||||||
@@ -578,6 +594,10 @@ NTSTATUS CHIDDevice::ResetReports()
|
|||||||
SubmitReport(&keyboard, sizeof(keyboard));
|
SubmitReport(&keyboard, sizeof(keyboard));
|
||||||
if (NT_SUCCESS(status))
|
if (NT_SUCCESS(status))
|
||||||
status = keyboardStatus;
|
status = keyboardStatus;
|
||||||
|
const NTSTATUS consumerStatus =
|
||||||
|
SubmitReport(&consumer, sizeof(consumer));
|
||||||
|
if (NT_SUCCESS(status))
|
||||||
|
status = consumerStatus;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,6 +120,20 @@ static const uint8_t REPORT_DESCRIPTOR[] =
|
|||||||
0x95, 0x06, // Report Count (6)
|
0x95, 0x06, // Report Count (6)
|
||||||
0x81, 0x00, // Input (Data, Array, Absolute)
|
0x81, 0x00, // Input (Data, Array, Absolute)
|
||||||
0xC0, // End Collection
|
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()
|
const uint8_t * HIDGetReportDescriptor()
|
||||||
@@ -145,6 +159,9 @@ size_t HIDGetInputReportSize(uint8_t reportId)
|
|||||||
case HID_REPORT_ID_KEYBOARD:
|
case HID_REPORT_ID_KEYBOARD:
|
||||||
return sizeof(HIDKeyboardReport);
|
return sizeof(HIDKeyboardReport);
|
||||||
|
|
||||||
|
case HID_REPORT_ID_CONSUMER:
|
||||||
|
return sizeof(HIDConsumerReport);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ enum HIDReportId : uint8_t
|
|||||||
HID_REPORT_ID_MOUSE_ABSOLUTE = 1,
|
HID_REPORT_ID_MOUSE_ABSOLUTE = 1,
|
||||||
HID_REPORT_ID_MOUSE_RELATIVE = 2,
|
HID_REPORT_ID_MOUSE_RELATIVE = 2,
|
||||||
HID_REPORT_ID_KEYBOARD = 3,
|
HID_REPORT_ID_KEYBOARD = 3,
|
||||||
|
HID_REPORT_ID_CONSUMER = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
@@ -64,12 +65,19 @@ struct HIDKeyboardLedsReport
|
|||||||
uint8_t leds;
|
uint8_t leds;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HIDConsumerReport
|
||||||
|
{
|
||||||
|
uint8_t reportId;
|
||||||
|
uint16_t usage;
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
static_assert(sizeof(HIDMouseAbsoluteReport) == 10);
|
static_assert(sizeof(HIDMouseAbsoluteReport) == 10);
|
||||||
static_assert(sizeof(HIDMouseRelativeReport) == 10);
|
static_assert(sizeof(HIDMouseRelativeReport) == 10);
|
||||||
static_assert(sizeof(HIDKeyboardReport) == 9);
|
static_assert(sizeof(HIDKeyboardReport) == 9);
|
||||||
static_assert(sizeof(HIDKeyboardLedsReport) == 2);
|
static_assert(sizeof(HIDKeyboardLedsReport) == 2);
|
||||||
|
static_assert(sizeof(HIDConsumerReport) == 3);
|
||||||
|
|
||||||
static constexpr size_t HID_MAX_INPUT_REPORT_SIZE =
|
static constexpr size_t HID_MAX_INPUT_REPORT_SIZE =
|
||||||
sizeof(HIDMouseAbsoluteReport);
|
sizeof(HIDMouseAbsoluteReport);
|
||||||
|
|||||||
@@ -27,6 +27,14 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#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()
|
bool CInputPipeClient::Start()
|
||||||
{
|
{
|
||||||
m_lastSequence = 0;
|
m_lastSequence = 0;
|
||||||
@@ -209,14 +217,45 @@ bool CInputPipeClient::HandleKeyboard(
|
|||||||
HIDKeyboardReport report = {};
|
HIDKeyboardReport report = {};
|
||||||
report.reportId = HID_REPORT_ID_KEYBOARD;
|
report.reportId = HID_REPORT_ID_KEYBOARD;
|
||||||
report.modifiers = input.modifiers;
|
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)
|
for (size_t i = 0; i < LG_INPUT_KEYBOARD_KEY_COUNT; ++i)
|
||||||
{
|
{
|
||||||
if (input.keys[i] > LG_INPUT_KEYBOARD_USAGE_MAX)
|
if (input.keys[i] > LG_INPUT_KEYBOARD_USAGE_MAX)
|
||||||
return false;
|
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(
|
bool CInputPipeClient::SubmitReport(
|
||||||
|
|||||||
Reference in New Issue
Block a user