#26363·qmk_firmware

[Feature Request] Support configurable additional HID interfaces

Author: BelonitCreated Jul 27, 2026Updated Sep 6, 2026
Labelsenhancementhelp wanted

Feature Request Type

  • Core functionality
  • Add-on hardware support (eg. audio, RGB, OLED screen, etc.)
  • Alteration (enhancement/optimization) of existing feature(s)
  • New behavior

Description

Description

I would like to discuss adding an opt-in core feature that allows a keyboard to expose one or more additional bidirectional HID interfaces. Each interface would have its own report descriptor, fixed report size, interrupt IN and OUT endpoints, receive callback, and send function.

This would cover host protocols that require a specific HID report format while allowing existing QMK interfaces, including VIA, to continue working unchanged.

Motivation

QMK Raw HID provides one interface with fixed 32-byte Input and Output reports. Its report descriptor is provided by QMK; a keyboard can change RAW_USAGE_PAGE and RAW_USAGE_ID, but cannot supply a different descriptor or report size. The interface also has a single raw_hid_receive() handler.

VIA uses Raw HID as its transport and provides that handler when enabled. VIA extension hooks can carry keyboard-specific commands, but the resulting protocol remains part of VIA's 32-byte Raw HID channel.

This leaves no independent transport for host software that requires:

  • a report size other than 32 bytes;
  • a particular Usage Page, Usage, or report layout;
  • an interface that can be discovered and opened separately from VIA;
  • multiple independent host communication channels.

Proposed behavior

A keyboard would declare additional interfaces at compile time. One possible API is an X-macro list in config.h:

c
#define CUSTOM_HID_INTERFACES(X) \
    X(VENDOR, vendor, 64, 34)     \
    X(CONFIG, config, 32, 34)

Each entry specifies an internal identifier, a public API suffix, the fixed Input/Output report size, and the report descriptor size.

The keyboard supplies the descriptor and implements the generated receive callback:

c
const uint8_t PROGMEM custom_hid_vendor_report_descriptor[34] = {
    /* HID report descriptor */
};

void custom_hid_vendor_receive(uint8_t *data, uint8_t length) {
    /* Handle an Output report from the host. */
}

QMK provides the corresponding send function:

c
bool custom_hid_vendor_send(uint8_t *data, uint8_t length);

The exact configuration syntax and naming are open for discussion.

Compatibility and constraints

The feature would be disabled by default and would not change Raw HID or VIA. Existing firmware would therefore be unaffected.

Each additional interface consumes an interface number, interrupt IN and OUT endpoints, endpoint buffers, and descriptor space. Some controllers can use the same endpoint number for both directions, while others require separate numbers. The build should fail clearly when a configuration exceeds the controller's limits.

An initial implementation could support LUFA and ChibiOS. V-USB would remain unsupported because of its endpoint and transfer constraints.

The current prototype supports one fixed-size Input report and one fixed-size Output report per interface, without Report IDs. Report IDs and reports larger than a single endpoint transaction are outside the initial scope.

Alternatives and prior discussion

Namespaced multiplexing over Raw HID, discussed in #11567, avoids consuming additional endpoints and remains preferable when every protocol can use the existing descriptor and 32-byte reports. It does not support host software that requires another descriptor, report size, or independently discoverable interface. Depending on the host API, sharing one interface between applications may also be unreliable.

VIA extension hooks solve custom VIA command handling, but do not create an independent transport. Making Raw HID itself configurable would still provide only one interface and changing its format would break VIA compatibility.

The collision between VIA and another protocol using Raw HID was also encountered in #10961.

Relevant documentation: https://docs.qmk.fm/features/rawhid

Prototype

A proof-of-concept implementation is available for review.

It supports multiple compile-time-defined interfaces with keyboard-supplied descriptors and generated send/receive APIs on LUFA and ChibiOS. It leaves Raw HID and VIA unchanged and rejects custom-interface configurations on V-USB.

The prototype is intended to make the proposal concrete. I would like to confirm the architecture and API with the QMK maintainers before preparing a core pull request.

Questions

  1. Is this functionality suitable for QMK core?
  2. Should it use a generic list of additional interfaces, extend Raw HID, or use another configuration model?
  3. Is fixed-size Input/Output without Report IDs a reasonable initial scope?
  4. Are LUFA and ChibiOS sufficient initially, with V-USB explicitly unsupported?
  5. Which build targets or tests should accompany a core PR?