From 92dc82ae08195335e6f9986b1c11be5838f2fd0c Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Mon, 15 Jun 2026 08:33:35 +1000 Subject: [PATCH] Plover HID cleanup. (#26262) --- builddefs/common_features.mk | 5 --- builddefs/generic_features.mk | 1 + quantum/plover_hid.c | 46 +++++++++++++++++++++++ quantum/plover_hid.h | 3 ++ tmk_core/protocol/chibios/usb_endpoints.c | 8 ++-- tmk_core/protocol/chibios/usb_main.c | 28 +++----------- tmk_core/protocol/host.c | 8 ++++ tmk_core/protocol/host.h | 1 + tmk_core/protocol/host_driver.h | 1 + tmk_core/protocol/lufa/lufa.c | 36 +++--------------- tmk_core/protocol/report.h | 10 +++++ tmk_core/protocol/usb_descriptor.c | 5 +++ 12 files changed, 91 insertions(+), 61 deletions(-) create mode 100644 quantum/plover_hid.c diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index e65cbc0d071..30da0f8f6e4 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -99,11 +99,6 @@ endif VALID_STENO_PROTOCOL_TYPES := geminipr txbolt all STENO_PROTOCOL ?= all -ifeq ($(strip $(PLOVER_HID_ENABLE)), yes) - OPT_DEFS += -DPLOVER_HID_ENABLE - SRC += $(QUANTUM_DIR)/process_keycode/process_plover_hid.c -endif - ifeq ($(strip $(STENO_ENABLE)), yes) ifeq ($(filter $(STENO_PROTOCOL),$(VALID_STENO_PROTOCOL_TYPES)),) $(call CATASTROPHIC_ERROR,Invalid STENO_PROTOCOL,STENO_PROTOCOL="$(STENO_PROTOCOL)" is not a valid stenography protocol) diff --git a/builddefs/generic_features.mk b/builddefs/generic_features.mk index 6d394977bd0..92fecf030e7 100644 --- a/builddefs/generic_features.mk +++ b/builddefs/generic_features.mk @@ -45,6 +45,7 @@ GENERIC_FEATURES = \ MOUSEKEY \ MUSIC \ OS_DETECTION \ + PLOVER_HID \ PROGRAMMABLE_BUTTON \ REPEAT_KEY \ SECURE \ diff --git a/quantum/plover_hid.c b/quantum/plover_hid.c new file mode 100644 index 00000000000..436d0bb828b --- /dev/null +++ b/quantum/plover_hid.c @@ -0,0 +1,46 @@ +/* Copyright 2021 dnaq + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "plover_hid.h" +#include "report.h" +#include "host.h" +#include "compiler_support.h" + +// The button index handed to plover_hid_update() is `keycode - QK_PLOVER_HID`, so the report's +// data field must hold a bit for every keycode in the range or the bit-packing below overflows. +STATIC_ASSERT(sizeof(((report_plover_hid_t *)0)->data) * CHAR_BIT >= (QK_PLOVER_HID_MAX - QK_PLOVER_HID + 1), "Plover HID report data too small for the QK_PLOVER_HID keycode range"); + +static report_plover_hid_t plover_hid_report = {.report_id = REPORT_ID_PLOVER_HID}; +static bool plover_hid_report_updated = false; + +void plover_hid_update(uint8_t button, bool pressed) { + if (pressed) { + plover_hid_report.data[button / 8] |= (1 << (7 - (button % 8))); + } else { + plover_hid_report.data[button / 8] &= ~(1 << (7 - (button % 8))); + } + plover_hid_report_updated = true; +} + +void plover_hid_task(void) { + if (!plover_hid_report_updated) { + return; + } + host_plover_hid_send(&plover_hid_report); + plover_hid_report_updated = false; +} diff --git a/quantum/plover_hid.h b/quantum/plover_hid.h index 855ceb9a3c5..8deb4955a70 100644 --- a/quantum/plover_hid.h +++ b/quantum/plover_hid.h @@ -16,5 +16,8 @@ #pragma once +#include +#include + void plover_hid_update(uint8_t button, bool pressed); void plover_hid_task(void); diff --git a/tmk_core/protocol/chibios/usb_endpoints.c b/tmk_core/protocol/chibios/usb_endpoints.c index 2c30a4a54de..58872673365 100644 --- a/tmk_core/protocol/chibios/usb_endpoints.c +++ b/tmk_core/protocol/chibios/usb_endpoints.c @@ -81,11 +81,7 @@ usb_endpoint_in_t usb_endpoints_in[USB_ENDPOINT_IN_COUNT] = { #endif #if defined(PLOVER_HID_ENABLE) -# if defined(USB_ENDPOINTS_ARE_REORDERABLE) - [USB_ENDPOINT_IN_PLOVER_HID] = QMK_USB_ENDPOINT_IN_SHARED(USB_EP_MODE_TYPE_INTR, PLOVER_HID_EPSIZE, PLOVER_HID_IN_EPNUM, PLOVER_HID_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(PLOVER_HID_EPSIZE)), -# else [USB_ENDPOINT_IN_PLOVER_HID] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, PLOVER_HID_EPSIZE, PLOVER_HID_IN_EPNUM, PLOVER_HID_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(PLOVER_HID_EPSIZE)), -# endif #endif #if defined(MIDI_ENABLE) @@ -115,6 +111,10 @@ usb_endpoint_in_lut_t usb_endpoint_interface_lut[TOTAL_INTERFACES] = { [RAW_INTERFACE] = USB_ENDPOINT_IN_RAW, #endif +#if defined(PLOVER_HID_ENABLE) + [PLOVER_HID_INTERFACE] = USB_ENDPOINT_IN_PLOVER_HID, +#endif + #if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) [MOUSE_INTERFACE] = USB_ENDPOINT_IN_MOUSE, #endif diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c index 261d796d38e..f1b977c17f7 100644 --- a/tmk_core/protocol/chibios/usb_main.c +++ b/tmk_core/protocol/chibios/usb_main.c @@ -489,6 +489,12 @@ void send_digitizer(report_digitizer_t *report) { #endif } +void send_plover_hid(report_plover_hid_t *report) { +#ifdef PLOVER_HID_ENABLE + send_report(USB_ENDPOINT_IN_PLOVER_HID, report, sizeof(report_plover_hid_t)); +#endif +} + /* --------------------------------------------------------- * Console functions * --------------------------------------------------------- @@ -523,28 +529,6 @@ void raw_hid_task(void) { #endif -#ifdef PLOVER_HID_ENABLE -static bool plover_hid_report_updated = false; -static uint8_t plover_hid_current_report[PLOVER_HID_EPSIZE] = {0x50}; - -void plover_hid_update(uint8_t button, bool pressed) { - if (pressed) { - plover_hid_current_report[1 + button / 8] |= (1 << (7 - (button % 8))); - } else { - plover_hid_current_report[1 + button / 8] &= ~(1 << (7 - (button % 8))); - } - plover_hid_report_updated = true; -} - -void plover_hid_task(void) { - if (!plover_hid_report_updated) { - return; - } - send_report(USB_ENDPOINT_IN_PLOVER_HID, plover_hid_current_report, sizeof(plover_hid_current_report)); - plover_hid_report_updated = false; -} -#endif - #ifdef MIDI_ENABLE void send_midi_packet(MIDI_EventPacket_t *event) { diff --git a/tmk_core/protocol/host.c b/tmk_core/protocol/host.c index f4fa9064e03..8d326026074 100644 --- a/tmk_core/protocol/host.c +++ b/tmk_core/protocol/host.c @@ -342,6 +342,14 @@ void host_programmable_button_send(uint32_t data) { __attribute__((weak)) void send_programmable_button(report_programmable_button_t *report) {} +#ifdef PLOVER_HID_ENABLE +void host_plover_hid_send(report_plover_hid_t *report) { + send_plover_hid(report); +} +#endif + +__attribute__((weak)) void send_plover_hid(report_plover_hid_t *report) {} + #ifdef RAW_ENABLE void host_raw_hid_send(uint8_t *data, uint8_t length) { host_driver_t *driver = host_get_active_driver(); diff --git a/tmk_core/protocol/host.h b/tmk_core/protocol/host.h index 7ff6d0df08d..c34a3f927c4 100644 --- a/tmk_core/protocol/host.h +++ b/tmk_core/protocol/host.h @@ -44,6 +44,7 @@ void host_mouse_send(report_mouse_t *report); void host_system_send(uint16_t usage); void host_consumer_send(uint16_t usage); void host_programmable_button_send(uint32_t data); +void host_plover_hid_send(report_plover_hid_t *report); void host_raw_hid_send(uint8_t *data, uint8_t length); uint16_t host_last_system_usage(void); diff --git a/tmk_core/protocol/host_driver.h b/tmk_core/protocol/host_driver.h index c2835aaa99f..f65c367e020 100644 --- a/tmk_core/protocol/host_driver.h +++ b/tmk_core/protocol/host_driver.h @@ -37,3 +37,4 @@ typedef struct { void send_joystick(report_joystick_t *report); void send_digitizer(report_digitizer_t *report); void send_programmable_button(report_programmable_button_t *report); +void send_plover_hid(report_plover_hid_t *report); diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 544b90b31af..827dd4d69a4 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -64,10 +64,6 @@ # include "raw_hid.h" #endif -#ifdef PLOVER_HID_ENABLE -# include "plover_hid.h" -#endif - #ifdef WAIT_FOR_USB // TODO: Remove backwards compatibility with old define # define USB_WAIT_FOR_ENUMERATION @@ -183,28 +179,6 @@ void raw_hid_task(void) { } #endif -#ifdef PLOVER_HID_ENABLE -static bool plover_hid_report_updated = false; -static uint8_t plover_hid_current_report[PLOVER_HID_EPSIZE] = {0x50}; - -void plover_hid_update(uint8_t button, bool pressed) { - if (pressed) { - plover_hid_current_report[1 + button / 8] |= (1 << (7 - (button % 8))); - } else { - plover_hid_current_report[1 + button / 8] &= ~(1 << (7 - (button % 8))); - } - plover_hid_report_updated = true; -} - -void plover_hid_task(void) { - if (!plover_hid_report_updated) { - return; - } - send_report(PLOVER_HID_IN_EPNUM, plover_hid_current_report, sizeof(plover_hid_current_report)); - plover_hid_report_updated = false; -} -#endif - /******************************************************************************* * Console ******************************************************************************/ @@ -602,6 +576,12 @@ void send_digitizer(report_digitizer_t *report) { #endif } +void send_plover_hid(report_plover_hid_t *report) { +#ifdef PLOVER_HID_ENABLE + send_report(PLOVER_HID_IN_EPNUM, report, sizeof(report_plover_hid_t)); +#endif +} + /******************************************************************************* * sendchar ******************************************************************************/ @@ -877,10 +857,6 @@ void protocol_post_task(void) { MIDI_Device_USBTask(&USB_MIDI_Interface); #endif -#ifdef PLOVER_HID_ENABLE - plover_hid_task(); -#endif - #ifdef VIRTSER_ENABLE virtser_task(); CDC_Device_USBTask(&cdc_device); diff --git a/tmk_core/protocol/report.h b/tmk_core/protocol/report.h index ec220c6938d..805f8a91745 100644 --- a/tmk_core/protocol/report.h +++ b/tmk_core/protocol/report.h @@ -44,6 +44,11 @@ enum hid_report_ids { #define IS_VALID_REPORT_ID(id) ((id) >= REPORT_ID_ALL && (id) <= REPORT_ID_COUNT) +// Plover HID has its own dedicated interface rather than the shared endpoint, so its report ID +// is fixed by the protocol at 0x50 ('P') and is intentionally NOT a member of enum +// hid_report_ids above (which only enumerates shared-endpoint reports up to REPORT_ID_COUNT). +#define REPORT_ID_PLOVER_HID 0x50 + /* Mouse buttons */ #define MOUSE_BTN_MASK(n) (1 << (n)) enum mouse_buttons { @@ -193,6 +198,11 @@ typedef struct { uint32_t usage; } PACKED report_programmable_button_t; +typedef struct { + uint8_t report_id; // REPORT_ID_PLOVER_HID + uint8_t data[8]; +} PACKED report_plover_hid_t; + #ifdef MOUSE_EXTENDED_REPORT # define MOUSE_REPORT_XY_MIN (INT16_MIN + 1) # define MOUSE_REPORT_XY_MAX INT16_MAX diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c index 9d94fef9737..ff85e82f5c1 100644 --- a/tmk_core/protocol/usb_descriptor.c +++ b/tmk_core/protocol/usb_descriptor.c @@ -40,6 +40,7 @@ #include "report.h" #include "usb_descriptor.h" #include "usb_descriptor_common.h" +#include "compiler_support.h" #ifdef JOYSTICK_ENABLE # include "joystick.h" @@ -494,6 +495,10 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM PloverReport[] = { HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_RI_END_COLLECTION(0), }; + +// The Plover HID report is sent with sizeof(report_plover_hid_t), but the endpoint and descriptor +// are sized with PLOVER_HID_EPSIZE; they must match or reports get truncated/padded. +STATIC_ASSERT(sizeof(report_plover_hid_t) == PLOVER_HID_EPSIZE, "report_plover_hid_t size must match PLOVER_HID_EPSIZE"); #endif #ifdef CONSOLE_ENABLE