#include "usb_hid.h" #include #include #include // ── HID Report Descriptor: Keyboard + Consumer Control ─────────────────────── // Host-Kommunikation außerhalb von HID läuft separat über USB CDC (SerialUSB). static const uint8_t k_hid_descriptor[] = { // ── Report ID 1: Keyboard ───────────────────────────────────────────────── 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x06, // Usage (Keyboard) 0xA1, 0x01, // Collection (Application) 0x85, HID_REPORT_ID_KEYBOARD, 0x05, 0x07, // Usage Page (Key Codes) 0x19, 0xE0, // Usage Minimum (Left Ctrl) 0x29, 0xE7, // Usage Maximum (Right GUI) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1 Bit) 0x95, 0x08, // Report Count (8) 0x81, 0x02, // Input (Data, Variable, Absolute) 0x95, 0x01, // Report Count (1) 0x75, 0x08, // Report Size (8 Bit) 0x81, 0x01, // Input (Constant) 0x95, 0x06, // Report Count (6) 0x75, 0x08, // Report Size (8 Bit) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x65, // Logical Maximum (101) 0x05, 0x07, // Usage Page (Key Codes) 0x19, 0x00, // Usage Minimum (0) 0x29, 0x65, // Usage Maximum (101) 0x81, 0x00, // Input (Data, Array) 0xC0, // End Collection // ── Report ID 2: Consumer Control ───────────────────────────────────────── 0x05, 0x0C, // Usage Page (Consumer Devices) 0x09, 0x01, // Usage (Consumer Control) 0xA1, 0x01, // Collection (Application) 0x85, HID_REPORT_ID_CONSUMER, 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x03, // Logical Maximum (1023) 0x19, 0x00, // Usage Minimum (0) 0x2A, 0xFF, 0x03, // Usage Maximum (1023) 0x75, 0x10, // Report Size (16 Bit) 0x95, 0x01, // Report Count (1) 0x81, 0x00, // Input (Data, Array) 0xC0, // End Collection }; namespace { struct HIDRegistrar { HIDSubDescriptor node; HIDRegistrar() : node(k_hid_descriptor, sizeof(k_hid_descriptor)) { HID().AppendDescriptor(&node); } } s_hid_registrar; } struct KeyboardReport { uint8_t modifier; uint8_t reserved; uint8_t keycodes[6]; }; struct ConsumerReport { uint16_t usage; }; static uint8_t s_key_refcount[256] = {}; static uint8_t s_modifier_refcount[8] = {}; struct ConsumerState { uint16_t usage; uint8_t refcount; uint32_t order; }; static constexpr uint8_t CONSUMER_STATE_SLOTS = 8; static ConsumerState s_consumer_state[CONSUMER_STATE_SLOTS] = {}; static uint32_t s_consumer_order = 0; static void send_keyboard_state() { KeyboardReport report = {}; for (uint8_t bit = 0; bit < 8; bit++) { if (s_modifier_refcount[bit] > 0) report.modifier |= static_cast(1u << bit); } uint8_t out = 0; for (uint16_t key = 1; key < 256 && out < 6; key++) { if (s_key_refcount[key] > 0) report.keycodes[out++] = static_cast(key); } HID().SendReport(HID_REPORT_ID_KEYBOARD, &report, sizeof(report)); } static void send_consumer_state() { uint16_t usage = 0; uint32_t newest = 0; for (uint8_t i = 0; i < CONSUMER_STATE_SLOTS; i++) { if (s_consumer_state[i].refcount > 0 && s_consumer_state[i].order >= newest) { newest = s_consumer_state[i].order; usage = s_consumer_state[i].usage; } } ConsumerReport report = { usage }; HID().SendReport(HID_REPORT_ID_CONSUMER, &report, sizeof(report)); } void usb_hid_init() { memset(s_key_refcount, 0, sizeof(s_key_refcount)); memset(s_modifier_refcount, 0, sizeof(s_modifier_refcount)); memset(s_consumer_state, 0, sizeof(s_consumer_state)); s_consumer_order = 0; } void usb_hid_send_key(uint8_t keycode, uint8_t modifier) { if (keycode != 0 && s_key_refcount[keycode] < 0xFF) s_key_refcount[keycode]++; for (uint8_t bit = 0; bit < 8; bit++) { if ((modifier & (1u << bit)) != 0 && s_modifier_refcount[bit] < 0xFF) s_modifier_refcount[bit]++; } send_keyboard_state(); } void usb_hid_release_key(uint8_t keycode, uint8_t modifier) { if (keycode != 0 && s_key_refcount[keycode] > 0) s_key_refcount[keycode]--; for (uint8_t bit = 0; bit < 8; bit++) { if ((modifier & (1u << bit)) != 0 && s_modifier_refcount[bit] > 0) s_modifier_refcount[bit]--; } send_keyboard_state(); } void usb_hid_release_all_keys() { memset(s_key_refcount, 0, sizeof(s_key_refcount)); memset(s_modifier_refcount, 0, sizeof(s_modifier_refcount)); send_keyboard_state(); } void usb_hid_send_consumer(uint16_t usage) { ConsumerState* free_slot = nullptr; for (uint8_t i = 0; i < CONSUMER_STATE_SLOTS; i++) { ConsumerState& state = s_consumer_state[i]; if (state.refcount > 0 && state.usage == usage) { if (state.refcount < 0xFF) state.refcount++; state.order = ++s_consumer_order; send_consumer_state(); return; } if (state.refcount == 0 && free_slot == nullptr) free_slot = &state; } if (free_slot != nullptr) { free_slot->usage = usage; free_slot->refcount = 1; free_slot->order = ++s_consumer_order; } send_consumer_state(); } void usb_hid_release_consumer(uint16_t usage) { for (uint8_t i = 0; i < CONSUMER_STATE_SLOTS; i++) { ConsumerState& state = s_consumer_state[i]; if (state.refcount > 0 && state.usage == usage) { state.refcount--; if (state.refcount == 0) { state.usage = 0; state.order = 0; } break; } } send_consumer_state(); } void usb_hid_release_all_consumers() { memset(s_consumer_state, 0, sizeof(s_consumer_state)); send_consumer_state(); }