From 83988597f4d916a37b2b0987f393ceaa007532eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 15 Sep 2021 17:40:22 +0200 Subject: Add Support for USB programmable buttons (#12950) --- tmk_core/common/chibios/suspend.c | 4 ++++ tmk_core/common/host.c | 15 +++++++++++++-- tmk_core/common/host.h | 2 ++ tmk_core/common/host_driver.h | 1 + tmk_core/common/report.h | 6 ++++++ tmk_core/protocol/lufa/lufa.c | 33 +++++++++++++++++++++++---------- tmk_core/protocol/usb_descriptor.c | 19 +++++++++++++++++++ tmk_core/protocol/vusb/vusb.c | 36 +++++++++++++++++++++++++++++++++++- 8 files changed, 103 insertions(+), 13 deletions(-) (limited to 'tmk_core') diff --git a/tmk_core/common/chibios/suspend.c b/tmk_core/common/chibios/suspend.c index 991fe6e08b..9310a99920 100644 --- a/tmk_core/common/chibios/suspend.c +++ b/tmk_core/common/chibios/suspend.c @@ -7,6 +7,7 @@ #include "action.h" #include "action_util.h" #include "mousekey.h" +#include "programmable_button.h" #include "host.h" #include "suspend.h" #include "led.h" @@ -79,6 +80,9 @@ void suspend_wakeup_init(void) { #ifdef MOUSEKEY_ENABLE mousekey_clear(); #endif /* MOUSEKEY_ENABLE */ +#ifdef PROGRAMMABLE_BUTTON_ENABLE + programmable_button_clear(); +#endif /* PROGRAMMABLE_BUTTON_ENABLE */ #ifdef EXTRAKEY_ENABLE host_system_send(0); host_consumer_send(0); diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c index f0c396b189..56d4bb0847 100644 --- a/tmk_core/common/host.c +++ b/tmk_core/common/host.c @@ -30,8 +30,9 @@ extern keymap_config_t keymap_config; #endif static host_driver_t *driver; -static uint16_t last_system_report = 0; -static uint16_t last_consumer_report = 0; +static uint16_t last_system_report = 0; +static uint16_t last_consumer_report = 0; +static uint32_t last_programmable_button_report = 0; void host_set_driver(host_driver_t *d) { driver = d; } @@ -122,6 +123,16 @@ void host_digitizer_send(digitizer_t *digitizer) { __attribute__((weak)) void send_digitizer(report_digitizer_t *report) {} +void host_programmable_button_send(uint32_t report) { + if (report == last_programmable_button_report) return; + last_programmable_button_report = report; + + if (!driver) return; + (*driver->send_programmable_button)(report); +} + uint16_t host_last_system_report(void) { return last_system_report; } uint16_t host_last_consumer_report(void) { return last_consumer_report; } + +uint32_t host_last_programmable_button_report(void) { return last_programmable_button_report; } diff --git a/tmk_core/common/host.h b/tmk_core/common/host.h index 2cffef6e15..6b15f0d0c1 100644 --- a/tmk_core/common/host.h +++ b/tmk_core/common/host.h @@ -47,9 +47,11 @@ void host_keyboard_send(report_keyboard_t *report); void host_mouse_send(report_mouse_t *report); void host_system_send(uint16_t data); void host_consumer_send(uint16_t data); +void host_programmable_button_send(uint32_t data); uint16_t host_last_system_report(void); uint16_t host_last_consumer_report(void); +uint32_t host_last_programmable_button_report(void); #ifdef __cplusplus } diff --git a/tmk_core/common/host_driver.h b/tmk_core/common/host_driver.h index 2aebca043d..affd0dcb34 100644 --- a/tmk_core/common/host_driver.h +++ b/tmk_core/common/host_driver.h @@ -29,6 +29,7 @@ typedef struct { void (*send_mouse)(report_mouse_t *); void (*send_system)(uint16_t); void (*send_consumer)(uint16_t); + void (*send_programmable_button)(uint32_t); } host_driver_t; void send_digitizer(report_digitizer_t *report); \ No newline at end of file diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h index f2223e8063..1adc892f3b 100644 --- a/tmk_core/common/report.h +++ b/tmk_core/common/report.h @@ -29,6 +29,7 @@ enum hid_report_ids { REPORT_ID_MOUSE, REPORT_ID_SYSTEM, REPORT_ID_CONSUMER, + REPORT_ID_PROGRAMMABLE_BUTTON, REPORT_ID_NKRO, REPORT_ID_JOYSTICK, REPORT_ID_DIGITIZER @@ -195,6 +196,11 @@ typedef struct { uint16_t usage; } __attribute__((packed)) report_extra_t; +typedef struct { + uint8_t report_id; + uint32_t usage; +} __attribute__((packed)) report_programmable_button_t; + typedef struct { #ifdef MOUSE_SHARED_EP uint8_t report_id; diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 5b56e8a03c..cb3aa693b5 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -142,7 +142,8 @@ static void send_keyboard(report_keyboard_t *report); static void send_mouse(report_mouse_t *report); static void send_system(uint16_t data); static void send_consumer(uint16_t data); -host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; +static void send_programmable_button(uint32_t data); +host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button}; #ifdef VIRTSER_ENABLE // clang-format off @@ -760,27 +761,31 @@ static void send_mouse(report_mouse_t *report) { #endif } -/** \brief Send Extra - * - * FIXME: Needs doc - */ -#ifdef EXTRAKEY_ENABLE -static void send_extra(uint8_t report_id, uint16_t data) { +static void send_report(void *report, size_t size) { uint8_t timeout = 255; if (USB_DeviceState != DEVICE_STATE_Configured) return; - static report_extra_t r; - r = (report_extra_t){.report_id = report_id, .usage = data}; Endpoint_SelectEndpoint(SHARED_IN_EPNUM); /* Check if write ready for a polling interval around 10ms */ while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); if (!Endpoint_IsReadWriteAllowed()) return; - Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); + Endpoint_Write_Stream_LE(report, size, NULL); Endpoint_ClearIN(); } + +/** \brief Send Extra + * + * FIXME: Needs doc + */ +#ifdef EXTRAKEY_ENABLE +static void send_extra(uint8_t report_id, uint16_t data) { + static report_extra_t r; + r = (report_extra_t){.report_id = report_id, .usage = data}; + send_report(&r, sizeof(r)); +} #endif /** \brief Send System @@ -822,6 +827,14 @@ static void send_consumer(uint16_t data) { #endif } +static void send_programmable_button(uint32_t data) { +#ifdef PROGRAMMABLE_BUTTON_ENABLE + static report_programmable_button_t r; + r = (report_programmable_button_t){.report_id = REPORT_ID_PROGRAMMABLE_BUTTON, .usage = data}; + send_report(&r, sizeof(r)); +#endif +} + /******************************************************************************* * sendchar ******************************************************************************/ diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c index 099964ae56..f720eea8d9 100644 --- a/tmk_core/protocol/usb_descriptor.c +++ b/tmk_core/protocol/usb_descriptor.c @@ -237,6 +237,25 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { HID_RI_END_COLLECTION(0), #endif +#ifdef PROGRAMMABLE_BUTTON_ENABLE + HID_RI_USAGE_PAGE(8, 0x0C), // Consumer + HID_RI_USAGE(8, 0x01), // Consumer Control + HID_RI_COLLECTION(8, 0x01), // Application + HID_RI_REPORT_ID(8, REPORT_ID_PROGRAMMABLE_BUTTON), + HID_RI_USAGE(8, 0x09), // Programmable Buttons + HID_RI_COLLECTION(8, 0x04), // Named Array + HID_RI_USAGE_PAGE(8, 0x09), // Button + HID_RI_USAGE_MINIMUM(8, 0x01), // Button 1 + HID_RI_USAGE_MAXIMUM(8, 0x20), // Button 32 + HID_RI_LOGICAL_MINIMUM(8, 0x01), + HID_RI_LOGICAL_MAXIMUM(8, 0x01), + HID_RI_REPORT_COUNT(8, 32), + HID_RI_REPORT_SIZE(8, 1), + HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_RI_END_COLLECTION(0), + HID_RI_END_COLLECTION(0), +#endif + #ifdef NKRO_ENABLE HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop HID_RI_USAGE(8, 0x06), // Keyboard diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c index 485b20c900..e4db5d0654 100644 --- a/tmk_core/protocol/vusb/vusb.c +++ b/tmk_core/protocol/vusb/vusb.c @@ -226,8 +226,9 @@ static void send_keyboard(report_keyboard_t *report); static void send_mouse(report_mouse_t *report); static void send_system(uint16_t data); static void send_consumer(uint16_t data); +static void send_programmable_button(uint32_t data); -static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; +static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button}; host_driver_t *vusb_driver(void) { return &driver; } @@ -296,6 +297,19 @@ void send_digitizer(report_digitizer_t *report) { #ifdef DIGITIZER_ENABLE if (usbInterruptIsReadyShared()) { usbSetInterruptShared((void *)report, sizeof(report_digitizer_t)); +#endif +} + +static void send_programmable_button(uint32_t data) { +#ifdef PROGRAMMABLE_BUTTON_ENABLE + static report_programmable_button_t report = { + .report_id = REPORT_ID_PROGRAMMABLE_BUTTON, + }; + + report.usage = data; + + if (usbInterruptIsReadyShared()) { + usbSetInterruptShared((void *)&report, sizeof(report)); } #endif } @@ -558,6 +572,26 @@ const PROGMEM uchar shared_hid_report[] = { 0xC0 // End Collection #endif +#ifdef PROGRAMMABLE_BUTTON_ENABLE + // Programmable buttons report descriptor + 0x05, 0x0C, // Usage Page (Consumer) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, REPORT_ID_PROGRAMMABLE_BUTTON, // Report ID + 0x09, 0x03, // Usage (Programmable Buttons) + 0xA1, 0x04, // Collection (Named Array) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (Button 1) + 0x29, 0x20, // Usage Maximum (Button 32) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x20, // Report Count (32) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0xC0, // End Collection + 0xC0 // End Collection +#endif + #ifdef SHARED_EP_ENABLE }; #endif -- cgit v1.2.3