Add Support for USB programmable buttons (#12950)

This commit is contained in:
Thomas Weißschuh 2021-09-15 17:40:22 +02:00 committed by GitHub
parent 1a68feb842
commit 83988597f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 436 additions and 14 deletions

View file

@ -127,6 +127,12 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/pointing_device.c
endif
ifeq ($(strip $(PROGRAMMABLE_BUTTON_ENABLE)), yes)
OPT_DEFS += -DPROGRAMMABLE_BUTTON_ENABLE
SRC += $(QUANTUM_DIR)/programmable_button.c
SRC += $(QUANTUM_DIR)/process_keycode/process_programmable_button.c
endif
VALID_EEPROM_DRIVER_TYPES := vendor custom transient i2c spi
EEPROM_DRIVER ?= vendor
ifeq ($(filter $(EEPROM_DRIVER),$(VALID_EEPROM_DRIVER_TYPES)),)

View file

@ -72,6 +72,7 @@
* [Mod-Tap](mod_tap.md)
* [Macros](feature_macros.md)
* [Mouse Keys](feature_mouse_keys.md)
* [Programmable Button](feature_programmable_button.md)
* [Space Cadet Shift](feature_space_cadet.md)
* [US ANSI Shifted Keys](keycodes_us_ansi_shifted.md)

View file

@ -0,0 +1,74 @@
## Programmable Button
Programmable button is a feature that can be used to send keys that have no
predefined meaning.
This means they can be processed on the host side by custom software without
colliding without the operating system trying to interpret these keys.
The keycodes are emitted according to the HID usage
"Telephony Device Page" (0x0B), "Programmable button usage" (0x07).
On Linux (> 5.14) they are handled automatically and translated to `KEY_MACRO#`
keycodes.
(Up to `KEY_MACRO30`)
### Enabling Programmable Button support
To enable Programmable Button, add the following line to your keymaps `rules.mk`:
```c
PROGRAMMABLE_BUTTON_ENABLE = yes
```
### Mapping
In your keymap you can use the following keycodes to map key presses to Programmable Buttons:
|Key |Description |
|------------------------|----------------------|
|`PROGRAMMABLE_BUTTON_1` |Programmable button 1 |
|`PROGRAMMABLE_BUTTON_2` |Programmable button 2 |
|`PROGRAMMABLE_BUTTON_3` |Programmable button 3 |
|`PROGRAMMABLE_BUTTON_4` |Programmable button 4 |
|`PROGRAMMABLE_BUTTON_5` |Programmable button 5 |
|`PROGRAMMABLE_BUTTON_6` |Programmable button 6 |
|`PROGRAMMABLE_BUTTON_7` |Programmable button 7 |
|`PROGRAMMABLE_BUTTON_8` |Programmable button 8 |
|`PROGRAMMABLE_BUTTON_9` |Programmable button 9 |
|`PROGRAMMABLE_BUTTON_10`|Programmable button 10|
|`PROGRAMMABLE_BUTTON_11`|Programmable button 11|
|`PROGRAMMABLE_BUTTON_12`|Programmable button 12|
|`PROGRAMMABLE_BUTTON_13`|Programmable button 13|
|`PROGRAMMABLE_BUTTON_14`|Programmable button 14|
|`PROGRAMMABLE_BUTTON_15`|Programmable button 15|
|`PROGRAMMABLE_BUTTON_16`|Programmable button 16|
|`PROGRAMMABLE_BUTTON_17`|Programmable button 17|
|`PROGRAMMABLE_BUTTON_18`|Programmable button 18|
|`PROGRAMMABLE_BUTTON_19`|Programmable button 19|
|`PROGRAMMABLE_BUTTON_20`|Programmable button 20|
|`PROGRAMMABLE_BUTTON_21`|Programmable button 21|
|`PROGRAMMABLE_BUTTON_22`|Programmable button 22|
|`PROGRAMMABLE_BUTTON_23`|Programmable button 23|
|`PROGRAMMABLE_BUTTON_24`|Programmable button 24|
|`PROGRAMMABLE_BUTTON_25`|Programmable button 25|
|`PROGRAMMABLE_BUTTON_26`|Programmable button 26|
|`PROGRAMMABLE_BUTTON_27`|Programmable button 27|
|`PROGRAMMABLE_BUTTON_28`|Programmable button 28|
|`PROGRAMMABLE_BUTTON_29`|Programmable button 29|
|`PROGRAMMABLE_BUTTON_30`|Programmable button 30|
|`PROGRAMMABLE_BUTTON_31`|Programmable button 31|
|`PROGRAMMABLE_BUTTON_32`|Programmable button 32|
|`PB_1` to `PB_32` |Aliases for keymaps |
### API
You can also use a dedicated API defined in `programmable_button.h` to interact with this feature:
```
void programmable_button_clear(void);
void programmable_button_send(void);
void programmable_button_on(uint8_t code);
void programmable_button_off(uint8_t code);
bool programmable_button_is_on(uint8_t code);
uint32_t programmable_button_get_report(void);
void programmable_button_set_report(uint32_t report);
```

View file

@ -677,6 +677,46 @@ See also: [One Shot Keys](one_shot_keys.md)
|`OS_OFF` |Turns One Shot keys off |
|`OS_TOGG` |Toggles One Shot keys status |
## Programmable Button Support :id=programmable-button
See also: [Programmable Button](feature_programmable_button.md)
|Key |Description |
|------------------------|----------------------|
|`PROGRAMMABLE_BUTTON_1` |Programmable button 1 |
|`PROGRAMMABLE_BUTTON_2` |Programmable button 2 |
|`PROGRAMMABLE_BUTTON_3` |Programmable button 3 |
|`PROGRAMMABLE_BUTTON_4` |Programmable button 4 |
|`PROGRAMMABLE_BUTTON_5` |Programmable button 5 |
|`PROGRAMMABLE_BUTTON_6` |Programmable button 6 |
|`PROGRAMMABLE_BUTTON_7` |Programmable button 7 |
|`PROGRAMMABLE_BUTTON_8` |Programmable button 8 |
|`PROGRAMMABLE_BUTTON_9` |Programmable button 9 |
|`PROGRAMMABLE_BUTTON_10`|Programmable button 10|
|`PROGRAMMABLE_BUTTON_11`|Programmable button 11|
|`PROGRAMMABLE_BUTTON_12`|Programmable button 12|
|`PROGRAMMABLE_BUTTON_13`|Programmable button 13|
|`PROGRAMMABLE_BUTTON_14`|Programmable button 14|
|`PROGRAMMABLE_BUTTON_15`|Programmable button 15|
|`PROGRAMMABLE_BUTTON_16`|Programmable button 16|
|`PROGRAMMABLE_BUTTON_17`|Programmable button 17|
|`PROGRAMMABLE_BUTTON_18`|Programmable button 18|
|`PROGRAMMABLE_BUTTON_19`|Programmable button 19|
|`PROGRAMMABLE_BUTTON_20`|Programmable button 20|
|`PROGRAMMABLE_BUTTON_21`|Programmable button 21|
|`PROGRAMMABLE_BUTTON_22`|Programmable button 22|
|`PROGRAMMABLE_BUTTON_23`|Programmable button 23|
|`PROGRAMMABLE_BUTTON_24`|Programmable button 24|
|`PROGRAMMABLE_BUTTON_25`|Programmable button 25|
|`PROGRAMMABLE_BUTTON_26`|Programmable button 26|
|`PROGRAMMABLE_BUTTON_27`|Programmable button 27|
|`PROGRAMMABLE_BUTTON_28`|Programmable button 28|
|`PROGRAMMABLE_BUTTON_29`|Programmable button 29|
|`PROGRAMMABLE_BUTTON_30`|Programmable button 30|
|`PROGRAMMABLE_BUTTON_31`|Programmable button 31|
|`PROGRAMMABLE_BUTTON_32`|Programmable button 32|
|`PB_1` to `PB_32` |Aliases for keymaps |
## Space Cadet :id=space-cadet
See also: [Space Cadet](feature_space_cadet.md)

View file

@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "keycode.h"
#include "keyboard.h"
#include "mousekey.h"
#include "programmable_button.h"
#include "command.h"
#include "led.h"
#include "action_layer.h"
@ -988,6 +989,10 @@ void clear_keyboard_but_mods_and_keys() {
mousekey_clear();
mousekey_send();
#endif
#ifdef PROGRAMMABLE_BUTTON_ENABLE
programmable_button_clear();
programmable_button_send();
#endif
}
/** \brief Utilities for actions. (FIXME: Needs better description)

View file

@ -76,6 +76,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef JOYSTICK_ENABLE
# include "process_joystick.h"
#endif
#ifdef PROGRAMMABLE_BUTTON_ENABLE
# include "programmable_button.h"
#endif
#ifdef HD44780_ENABLE
# include "hd44780.h"
#endif
@ -542,6 +545,10 @@ MATRIX_LOOP_END:
digitizer_task();
#endif
#ifdef PROGRAMMABLE_BUTTON_ENABLE
programmable_button_send();
#endif
// update LED
if (led_status != host_keyboard_leds()) {
led_status = host_keyboard_leds();

View file

@ -0,0 +1,31 @@
/*
Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de>
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 <http://www.gnu.org/licenses/>.
*/
#include "process_programmable_button.h"
#include "programmable_button.h"
bool process_programmable_button(uint16_t keycode, keyrecord_t *record) {
if (keycode >= PROGRAMMABLE_BUTTON_MIN && keycode <= PROGRAMMABLE_BUTTON_MAX) {
uint8_t button = keycode - PROGRAMMABLE_BUTTON_MIN + 1;
if (record->event.pressed) {
programmable_button_on(button);
} else {
programmable_button_off(button);
}
}
return true;
}

View file

@ -0,0 +1,23 @@
/*
Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de>
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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include "quantum.h"
bool process_programmable_button(uint16_t keycode, keyrecord_t *record);

View file

@ -0,0 +1,37 @@
/*
Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de>
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 <http://www.gnu.org/licenses/>.
*/
#include "programmable_button.h"
#include "host.h"
#define REPORT_BIT(index) (((uint32_t)1) << (index - 1))
static uint32_t programmable_button_report = 0;
void programmable_button_clear(void) { programmable_button_report = 0; }
void programmable_button_send(void) { host_programmable_button_send(programmable_button_report); }
void programmable_button_on(uint8_t index) { programmable_button_report |= REPORT_BIT(index); }
void programmable_button_off(uint8_t index) { programmable_button_report &= ~REPORT_BIT(index); }
bool programmable_button_is_on(uint8_t index) { return !!(programmable_button_report & REPORT_BIT(index)); };
uint32_t programmable_button_get_report(void) { return programmable_button_report; };
void programmable_button_set_report(uint32_t report) { programmable_button_report = report; }

View file

@ -0,0 +1,30 @@
/*
Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de>
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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "report.h"
void programmable_button_clear(void);
void programmable_button_send(void);
void programmable_button_on(uint8_t index);
void programmable_button_off(uint8_t index);
bool programmable_button_is_on(uint8_t index);
uint32_t programmable_button_get_report(void);
void programmable_button_set_report(uint32_t report);

View file

@ -295,6 +295,9 @@ bool process_record_quantum(keyrecord_t *record) {
#endif
#ifdef JOYSTICK_ENABLE
process_joystick(keycode, record) &&
#endif
#ifdef PROGRAMMABLE_BUTTON_ENABLE
process_programmable_button(keycode, record) &&
#endif
true)) {
return false;

View file

@ -147,6 +147,10 @@ extern layer_state_t layer_state;
# include "process_joystick.h"
#endif
#ifdef PROGRAMMABLE_BUTTON_ENABLE
# include "process_programmable_button.h"
#endif
#ifdef GRAVE_ESC_ENABLE
# include "process_grave_esc.h"
#endif

View file

@ -524,6 +524,40 @@ enum quantum_keycodes {
// Additional magic key
MAGIC_TOGGLE_GUI,
// Programmable Button
PROGRAMMABLE_BUTTON_1,
PROGRAMMABLE_BUTTON_2,
PROGRAMMABLE_BUTTON_3,
PROGRAMMABLE_BUTTON_4,
PROGRAMMABLE_BUTTON_5,
PROGRAMMABLE_BUTTON_6,
PROGRAMMABLE_BUTTON_7,
PROGRAMMABLE_BUTTON_8,
PROGRAMMABLE_BUTTON_9,
PROGRAMMABLE_BUTTON_10,
PROGRAMMABLE_BUTTON_11,
PROGRAMMABLE_BUTTON_12,
PROGRAMMABLE_BUTTON_13,
PROGRAMMABLE_BUTTON_14,
PROGRAMMABLE_BUTTON_15,
PROGRAMMABLE_BUTTON_16,
PROGRAMMABLE_BUTTON_17,
PROGRAMMABLE_BUTTON_18,
PROGRAMMABLE_BUTTON_19,
PROGRAMMABLE_BUTTON_20,
PROGRAMMABLE_BUTTON_21,
PROGRAMMABLE_BUTTON_22,
PROGRAMMABLE_BUTTON_23,
PROGRAMMABLE_BUTTON_24,
PROGRAMMABLE_BUTTON_25,
PROGRAMMABLE_BUTTON_26,
PROGRAMMABLE_BUTTON_27,
PROGRAMMABLE_BUTTON_28,
PROGRAMMABLE_BUTTON_29,
PROGRAMMABLE_BUTTON_30,
PROGRAMMABLE_BUTTON_31,
PROGRAMMABLE_BUTTON_32,
// Start of custom keycode range for keyboards and keymaps - always leave at the end
SAFE_RANGE
};
@ -854,3 +888,39 @@ enum quantum_keycodes {
#define OS_TOGG ONESHOT_TOGGLE
#define OS_ON ONESHOT_ENABLE
#define OS_OFF ONESHOT_DISABLE
// Programmable Button aliases
#define PB_1 PROGRAMMABLE_BUTTON_1
#define PB_2 PROGRAMMABLE_BUTTON_2
#define PB_3 PROGRAMMABLE_BUTTON_3
#define PB_4 PROGRAMMABLE_BUTTON_4
#define PB_5 PROGRAMMABLE_BUTTON_5
#define PB_6 PROGRAMMABLE_BUTTON_6
#define PB_7 PROGRAMMABLE_BUTTON_7
#define PB_8 PROGRAMMABLE_BUTTON_8
#define PB_9 PROGRAMMABLE_BUTTON_9
#define PB_10 PROGRAMMABLE_BUTTON_10
#define PB_11 PROGRAMMABLE_BUTTON_11
#define PB_12 PROGRAMMABLE_BUTTON_12
#define PB_13 PROGRAMMABLE_BUTTON_13
#define PB_14 PROGRAMMABLE_BUTTON_14
#define PB_15 PROGRAMMABLE_BUTTON_15
#define PB_16 PROGRAMMABLE_BUTTON_16
#define PB_17 PROGRAMMABLE_BUTTON_17
#define PB_18 PROGRAMMABLE_BUTTON_18
#define PB_19 PROGRAMMABLE_BUTTON_19
#define PB_20 PROGRAMMABLE_BUTTON_20
#define PB_21 PROGRAMMABLE_BUTTON_21
#define PB_22 PROGRAMMABLE_BUTTON_22
#define PB_23 PROGRAMMABLE_BUTTON_23
#define PB_24 PROGRAMMABLE_BUTTON_24
#define PB_25 PROGRAMMABLE_BUTTON_25
#define PB_26 PROGRAMMABLE_BUTTON_26
#define PB_27 PROGRAMMABLE_BUTTON_27
#define PB_28 PROGRAMMABLE_BUTTON_28
#define PB_29 PROGRAMMABLE_BUTTON_29
#define PB_30 PROGRAMMABLE_BUTTON_30
#define PB_31 PROGRAMMABLE_BUTTON_31
#define PB_32 PROGRAMMABLE_BUTTON_32
#define PROGRAMMABLE_BUTTON_MIN PROGRAMMABLE_BUTTON_1
#define PROGRAMMABLE_BUTTON_MAX PROGRAMMABLE_BUTTON_32

View file

@ -83,7 +83,8 @@ OTHER_OPTION_NAMES = \
RGB_MATRIX_KEYPRESSES \
LED_MIRRORED \
RGBLIGHT_FULL_POWER \
LTO_ENABLE
LTO_ENABLE \
PROGRAMMABLE_BUTTON_ENABLE
define NAME_ECHO
@printf " %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)"

View file

@ -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);

View file

@ -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; }

View file

@ -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
}

View file

@ -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);

View file

@ -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;

View file

@ -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
******************************************************************************/

View file

@ -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

View file

@ -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