aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common_features.mk6
-rw-r--r--docs/_summary.md1
-rw-r--r--docs/feature_programmable_button.md74
-rw-r--r--docs/keycodes.md40
-rw-r--r--quantum/action.c5
-rw-r--r--quantum/keyboard.c7
-rw-r--r--quantum/process_keycode/process_programmable_button.c31
-rw-r--r--quantum/process_keycode/process_programmable_button.h23
-rw-r--r--quantum/programmable_button.c37
-rw-r--r--quantum/programmable_button.h30
-rw-r--r--quantum/quantum.c3
-rw-r--r--quantum/quantum.h4
-rw-r--r--quantum/quantum_keycodes.h70
-rw-r--r--show_options.mk3
-rw-r--r--tmk_core/common/chibios/suspend.c4
-rw-r--r--tmk_core/common/host.c15
-rw-r--r--tmk_core/common/host.h2
-rw-r--r--tmk_core/common/host_driver.h1
-rw-r--r--tmk_core/common/report.h6
-rw-r--r--tmk_core/protocol/lufa/lufa.c33
-rw-r--r--tmk_core/protocol/usb_descriptor.c19
-rw-r--r--tmk_core/protocol/vusb/vusb.c36
22 files changed, 436 insertions, 14 deletions
diff --git a/common_features.mk b/common_features.mk
index 2cd78ceb6..4633ccce1 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -127,6 +127,12 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
127 SRC += $(QUANTUM_DIR)/pointing_device.c 127 SRC += $(QUANTUM_DIR)/pointing_device.c
128endif 128endif
129 129
130ifeq ($(strip $(PROGRAMMABLE_BUTTON_ENABLE)), yes)
131 OPT_DEFS += -DPROGRAMMABLE_BUTTON_ENABLE
132 SRC += $(QUANTUM_DIR)/programmable_button.c
133 SRC += $(QUANTUM_DIR)/process_keycode/process_programmable_button.c
134endif
135
130VALID_EEPROM_DRIVER_TYPES := vendor custom transient i2c spi 136VALID_EEPROM_DRIVER_TYPES := vendor custom transient i2c spi
131EEPROM_DRIVER ?= vendor 137EEPROM_DRIVER ?= vendor
132ifeq ($(filter $(EEPROM_DRIVER),$(VALID_EEPROM_DRIVER_TYPES)),) 138ifeq ($(filter $(EEPROM_DRIVER),$(VALID_EEPROM_DRIVER_TYPES)),)
diff --git a/docs/_summary.md b/docs/_summary.md
index 2f6309e41..4b528d996 100644
--- a/docs/_summary.md
+++ b/docs/_summary.md
@@ -72,6 +72,7 @@
72 * [Mod-Tap](mod_tap.md) 72 * [Mod-Tap](mod_tap.md)
73 * [Macros](feature_macros.md) 73 * [Macros](feature_macros.md)
74 * [Mouse Keys](feature_mouse_keys.md) 74 * [Mouse Keys](feature_mouse_keys.md)
75 * [Programmable Button](feature_programmable_button.md)
75 * [Space Cadet Shift](feature_space_cadet.md) 76 * [Space Cadet Shift](feature_space_cadet.md)
76 * [US ANSI Shifted Keys](keycodes_us_ansi_shifted.md) 77 * [US ANSI Shifted Keys](keycodes_us_ansi_shifted.md)
77 78
diff --git a/docs/feature_programmable_button.md b/docs/feature_programmable_button.md
new file mode 100644
index 000000000..b1ef555d1
--- /dev/null
+++ b/docs/feature_programmable_button.md
@@ -0,0 +1,74 @@
1## Programmable Button
2
3Programmable button is a feature that can be used to send keys that have no
4predefined meaning.
5This means they can be processed on the host side by custom software without
6colliding without the operating system trying to interpret these keys.
7
8The keycodes are emitted according to the HID usage
9"Telephony Device Page" (0x0B), "Programmable button usage" (0x07).
10On Linux (> 5.14) they are handled automatically and translated to `KEY_MACRO#`
11keycodes.
12(Up to `KEY_MACRO30`)
13
14### Enabling Programmable Button support
15
16To enable Programmable Button, add the following line to your keymap’s `rules.mk`:
17
18```c
19PROGRAMMABLE_BUTTON_ENABLE = yes
20```
21
22### Mapping
23
24In your keymap you can use the following keycodes to map key presses to Programmable Buttons:
25
26|Key |Description |
27|------------------------|----------------------|
28|`PROGRAMMABLE_BUTTON_1` |Programmable button 1 |
29|`PROGRAMMABLE_BUTTON_2` |Programmable button 2 |
30|`PROGRAMMABLE_BUTTON_3` |Programmable button 3 |
31|`PROGRAMMABLE_BUTTON_4` |Programmable button 4 |
32|`PROGRAMMABLE_BUTTON_5` |Programmable button 5 |
33|`PROGRAMMABLE_BUTTON_6` |Programmable button 6 |
34|`PROGRAMMABLE_BUTTON_7` |Programmable button 7 |
35|`PROGRAMMABLE_BUTTON_8` |Programmable button 8 |
36|`PROGRAMMABLE_BUTTON_9` |Programmable button 9 |
37|`PROGRAMMABLE_BUTTON_10`|Programmable button 10|
38|`PROGRAMMABLE_BUTTON_11`|Programmable button 11|
39|`PROGRAMMABLE_BUTTON_12`|Programmable button 12|
40|`PROGRAMMABLE_BUTTON_13`|Programmable button 13|
41|`PROGRAMMABLE_BUTTON_14`|Programmable button 14|
42|`PROGRAMMABLE_BUTTON_15`|Programmable button 15|
43|`PROGRAMMABLE_BUTTON_16`|Programmable button 16|
44|`PROGRAMMABLE_BUTTON_17`|Programmable button 17|
45|`PROGRAMMABLE_BUTTON_18`|Programmable button 18|
46|`PROGRAMMABLE_BUTTON_19`|Programmable button 19|
47|`PROGRAMMABLE_BUTTON_20`|Programmable button 20|
48|`PROGRAMMABLE_BUTTON_21`|Programmable button 21|
49|`PROGRAMMABLE_BUTTON_22`|Programmable button 22|
50|`PROGRAMMABLE_BUTTON_23`|Programmable button 23|
51|`PROGRAMMABLE_BUTTON_24`|Programmable button 24|
52|`PROGRAMMABLE_BUTTON_25`|Programmable button 25|
53|`PROGRAMMABLE_BUTTON_26`|Programmable button 26|
54|`PROGRAMMABLE_BUTTON_27`|Programmable button 27|
55|`PROGRAMMABLE_BUTTON_28`|Programmable button 28|
56|`PROGRAMMABLE_BUTTON_29`|Programmable button 29|
57|`PROGRAMMABLE_BUTTON_30`|Programmable button 30|
58|`PROGRAMMABLE_BUTTON_31`|Programmable button 31|
59|`PROGRAMMABLE_BUTTON_32`|Programmable button 32|
60|`PB_1` to `PB_32` |Aliases for keymaps |
61
62### API
63
64You can also use a dedicated API defined in `programmable_button.h` to interact with this feature:
65
66```
67void programmable_button_clear(void);
68void programmable_button_send(void);
69void programmable_button_on(uint8_t code);
70void programmable_button_off(uint8_t code);
71bool programmable_button_is_on(uint8_t code);
72uint32_t programmable_button_get_report(void);
73void programmable_button_set_report(uint32_t report);
74```
diff --git a/docs/keycodes.md b/docs/keycodes.md
index a134c5a1b..770a4525a 100644
--- a/docs/keycodes.md
+++ b/docs/keycodes.md
@@ -677,6 +677,46 @@ See also: [One Shot Keys](one_shot_keys.md)
677|`OS_OFF` |Turns One Shot keys off | 677|`OS_OFF` |Turns One Shot keys off |
678|`OS_TOGG` |Toggles One Shot keys status | 678|`OS_TOGG` |Toggles One Shot keys status |
679 679
680## Programmable Button Support :id=programmable-button
681
682See also: [Programmable Button](feature_programmable_button.md)
683
684|Key |Description |
685|------------------------|----------------------|
686|`PROGRAMMABLE_BUTTON_1` |Programmable button 1 |
687|`PROGRAMMABLE_BUTTON_2` |Programmable button 2 |
688|`PROGRAMMABLE_BUTTON_3` |Programmable button 3 |
689|`PROGRAMMABLE_BUTTON_4` |Programmable button 4 |
690|`PROGRAMMABLE_BUTTON_5` |Programmable button 5 |
691|`PROGRAMMABLE_BUTTON_6` |Programmable button 6 |
692|`PROGRAMMABLE_BUTTON_7` |Programmable button 7 |
693|`PROGRAMMABLE_BUTTON_8` |Programmable button 8 |
694|`PROGRAMMABLE_BUTTON_9` |Programmable button 9 |
695|`PROGRAMMABLE_BUTTON_10`|Programmable button 10|
696|`PROGRAMMABLE_BUTTON_11`|Programmable button 11|
697|`PROGRAMMABLE_BUTTON_12`|Programmable button 12|
698|`PROGRAMMABLE_BUTTON_13`|Programmable button 13|
699|`PROGRAMMABLE_BUTTON_14`|Programmable button 14|
700|`PROGRAMMABLE_BUTTON_15`|Programmable button 15|
701|`PROGRAMMABLE_BUTTON_16`|Programmable button 16|
702|`PROGRAMMABLE_BUTTON_17`|Programmable button 17|
703|`PROGRAMMABLE_BUTTON_18`|Programmable button 18|
704|`PROGRAMMABLE_BUTTON_19`|Programmable button 19|
705|`PROGRAMMABLE_BUTTON_20`|Programmable button 20|
706|`PROGRAMMABLE_BUTTON_21`|Programmable button 21|
707|`PROGRAMMABLE_BUTTON_22`|Programmable button 22|
708|`PROGRAMMABLE_BUTTON_23`|Programmable button 23|
709|`PROGRAMMABLE_BUTTON_24`|Programmable button 24|
710|`PROGRAMMABLE_BUTTON_25`|Programmable button 25|
711|`PROGRAMMABLE_BUTTON_26`|Programmable button 26|
712|`PROGRAMMABLE_BUTTON_27`|Programmable button 27|
713|`PROGRAMMABLE_BUTTON_28`|Programmable button 28|
714|`PROGRAMMABLE_BUTTON_29`|Programmable button 29|
715|`PROGRAMMABLE_BUTTON_30`|Programmable button 30|
716|`PROGRAMMABLE_BUTTON_31`|Programmable button 31|
717|`PROGRAMMABLE_BUTTON_32`|Programmable button 32|
718|`PB_1` to `PB_32` |Aliases for keymaps |
719
680## Space Cadet :id=space-cadet 720## Space Cadet :id=space-cadet
681 721
682See also: [Space Cadet](feature_space_cadet.md) 722See also: [Space Cadet](feature_space_cadet.md)
diff --git a/quantum/action.c b/quantum/action.c
index be135f18f..95f39d23d 100644
--- a/quantum/action.c
+++ b/quantum/action.c
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
18#include "keycode.h" 18#include "keycode.h"
19#include "keyboard.h" 19#include "keyboard.h"
20#include "mousekey.h" 20#include "mousekey.h"
21#include "programmable_button.h"
21#include "command.h" 22#include "command.h"
22#include "led.h" 23#include "led.h"
23#include "action_layer.h" 24#include "action_layer.h"
@@ -988,6 +989,10 @@ void clear_keyboard_but_mods_and_keys() {
988 mousekey_clear(); 989 mousekey_clear();
989 mousekey_send(); 990 mousekey_send();
990#endif 991#endif
992#ifdef PROGRAMMABLE_BUTTON_ENABLE
993 programmable_button_clear();
994 programmable_button_send();
995#endif
991} 996}
992 997
993/** \brief Utilities for actions. (FIXME: Needs better description) 998/** \brief Utilities for actions. (FIXME: Needs better description)
diff --git a/quantum/keyboard.c b/quantum/keyboard.c
index 5846507b3..6054faa03 100644
--- a/quantum/keyboard.c
+++ b/quantum/keyboard.c
@@ -76,6 +76,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
76#ifdef JOYSTICK_ENABLE 76#ifdef JOYSTICK_ENABLE
77# include "process_joystick.h" 77# include "process_joystick.h"
78#endif 78#endif
79#ifdef PROGRAMMABLE_BUTTON_ENABLE
80# include "programmable_button.h"
81#endif
79#ifdef HD44780_ENABLE 82#ifdef HD44780_ENABLE
80# include "hd44780.h" 83# include "hd44780.h"
81#endif 84#endif
@@ -542,6 +545,10 @@ MATRIX_LOOP_END:
542 digitizer_task(); 545 digitizer_task();
543#endif 546#endif
544 547
548#ifdef PROGRAMMABLE_BUTTON_ENABLE
549 programmable_button_send();
550#endif
551
545 // update LED 552 // update LED
546 if (led_status != host_keyboard_leds()) { 553 if (led_status != host_keyboard_leds()) {
547 led_status = host_keyboard_leds(); 554 led_status = host_keyboard_leds();
diff --git a/quantum/process_keycode/process_programmable_button.c b/quantum/process_keycode/process_programmable_button.c
new file mode 100644
index 000000000..c6e77faac
--- /dev/null
+++ b/quantum/process_keycode/process_programmable_button.c
@@ -0,0 +1,31 @@
1/*
2Copyright 2021 Thomas WeiĂźschuh <thomas@t-8ch.de>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "process_programmable_button.h"
19#include "programmable_button.h"
20
21bool process_programmable_button(uint16_t keycode, keyrecord_t *record) {
22 if (keycode >= PROGRAMMABLE_BUTTON_MIN && keycode <= PROGRAMMABLE_BUTTON_MAX) {
23 uint8_t button = keycode - PROGRAMMABLE_BUTTON_MIN + 1;
24 if (record->event.pressed) {
25 programmable_button_on(button);
26 } else {
27 programmable_button_off(button);
28 }
29 }
30 return true;
31}
diff --git a/quantum/process_keycode/process_programmable_button.h b/quantum/process_keycode/process_programmable_button.h
new file mode 100644
index 000000000..47c6ce561
--- /dev/null
+++ b/quantum/process_keycode/process_programmable_button.h
@@ -0,0 +1,23 @@
1/*
2Copyright 2021 Thomas WeiĂźschuh <thomas@t-8ch.de>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20#include <stdint.h>
21#include "quantum.h"
22
23bool process_programmable_button(uint16_t keycode, keyrecord_t *record);
diff --git a/quantum/programmable_button.c b/quantum/programmable_button.c
new file mode 100644
index 000000000..be828fd17
--- /dev/null
+++ b/quantum/programmable_button.c
@@ -0,0 +1,37 @@
1/*
2Copyright 2021 Thomas WeiĂźschuh <thomas@t-8ch.de>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "programmable_button.h"
19#include "host.h"
20
21#define REPORT_BIT(index) (((uint32_t)1) << (index - 1))
22
23static uint32_t programmable_button_report = 0;
24
25void programmable_button_clear(void) { programmable_button_report = 0; }
26
27void programmable_button_send(void) { host_programmable_button_send(programmable_button_report); }
28
29void programmable_button_on(uint8_t index) { programmable_button_report |= REPORT_BIT(index); }
30
31void programmable_button_off(uint8_t index) { programmable_button_report &= ~REPORT_BIT(index); }
32
33bool programmable_button_is_on(uint8_t index) { return !!(programmable_button_report & REPORT_BIT(index)); };
34
35uint32_t programmable_button_get_report(void) { return programmable_button_report; };
36
37void programmable_button_set_report(uint32_t report) { programmable_button_report = report; }
diff --git a/quantum/programmable_button.h b/quantum/programmable_button.h
new file mode 100644
index 000000000..e89b8b9fd
--- /dev/null
+++ b/quantum/programmable_button.h
@@ -0,0 +1,30 @@
1/*
2Copyright 2021 Thomas WeiĂźschuh <thomas@t-8ch.de>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20#include <stdint.h>
21#include <stdbool.h>
22#include "report.h"
23
24void programmable_button_clear(void);
25void programmable_button_send(void);
26void programmable_button_on(uint8_t index);
27void programmable_button_off(uint8_t index);
28bool programmable_button_is_on(uint8_t index);
29uint32_t programmable_button_get_report(void);
30void programmable_button_set_report(uint32_t report);
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 9d77fa438..326c8370b 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -296,6 +296,9 @@ bool process_record_quantum(keyrecord_t *record) {
296#ifdef JOYSTICK_ENABLE 296#ifdef JOYSTICK_ENABLE
297 process_joystick(keycode, record) && 297 process_joystick(keycode, record) &&
298#endif 298#endif
299#ifdef PROGRAMMABLE_BUTTON_ENABLE
300 process_programmable_button(keycode, record) &&
301#endif
299 true)) { 302 true)) {
300 return false; 303 return false;
301 } 304 }
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 86b717e44..5cbe84d0c 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -147,6 +147,10 @@ extern layer_state_t layer_state;
147# include "process_joystick.h" 147# include "process_joystick.h"
148#endif 148#endif
149 149
150#ifdef PROGRAMMABLE_BUTTON_ENABLE
151# include "process_programmable_button.h"
152#endif
153
150#ifdef GRAVE_ESC_ENABLE 154#ifdef GRAVE_ESC_ENABLE
151# include "process_grave_esc.h" 155# include "process_grave_esc.h"
152#endif 156#endif
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index ef4b0f457..2ea81dd4c 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -524,6 +524,40 @@ enum quantum_keycodes {
524 // Additional magic key 524 // Additional magic key
525 MAGIC_TOGGLE_GUI, 525 MAGIC_TOGGLE_GUI,
526 526
527 // Programmable Button
528 PROGRAMMABLE_BUTTON_1,
529 PROGRAMMABLE_BUTTON_2,
530 PROGRAMMABLE_BUTTON_3,
531 PROGRAMMABLE_BUTTON_4,
532 PROGRAMMABLE_BUTTON_5,
533 PROGRAMMABLE_BUTTON_6,
534 PROGRAMMABLE_BUTTON_7,
535 PROGRAMMABLE_BUTTON_8,
536 PROGRAMMABLE_BUTTON_9,
537 PROGRAMMABLE_BUTTON_10,
538 PROGRAMMABLE_BUTTON_11,
539 PROGRAMMABLE_BUTTON_12,
540 PROGRAMMABLE_BUTTON_13,
541 PROGRAMMABLE_BUTTON_14,
542 PROGRAMMABLE_BUTTON_15,
543 PROGRAMMABLE_BUTTON_16,
544 PROGRAMMABLE_BUTTON_17,
545 PROGRAMMABLE_BUTTON_18,
546 PROGRAMMABLE_BUTTON_19,
547 PROGRAMMABLE_BUTTON_20,
548 PROGRAMMABLE_BUTTON_21,
549 PROGRAMMABLE_BUTTON_22,
550 PROGRAMMABLE_BUTTON_23,
551 PROGRAMMABLE_BUTTON_24,
552 PROGRAMMABLE_BUTTON_25,
553 PROGRAMMABLE_BUTTON_26,
554 PROGRAMMABLE_BUTTON_27,
555 PROGRAMMABLE_BUTTON_28,
556 PROGRAMMABLE_BUTTON_29,
557 PROGRAMMABLE_BUTTON_30,
558 PROGRAMMABLE_BUTTON_31,
559 PROGRAMMABLE_BUTTON_32,
560
527 // Start of custom keycode range for keyboards and keymaps - always leave at the end 561 // Start of custom keycode range for keyboards and keymaps - always leave at the end
528 SAFE_RANGE 562 SAFE_RANGE
529}; 563};
@@ -854,3 +888,39 @@ enum quantum_keycodes {
854#define OS_TOGG ONESHOT_TOGGLE 888#define OS_TOGG ONESHOT_TOGGLE
855#define OS_ON ONESHOT_ENABLE 889#define OS_ON ONESHOT_ENABLE
856#define OS_OFF ONESHOT_DISABLE 890#define OS_OFF ONESHOT_DISABLE
891
892// Programmable Button aliases
893#define PB_1 PROGRAMMABLE_BUTTON_1
894#define PB_2 PROGRAMMABLE_BUTTON_2
895#define PB_3 PROGRAMMABLE_BUTTON_3
896#define PB_4 PROGRAMMABLE_BUTTON_4
897#define PB_5 PROGRAMMABLE_BUTTON_5
898#define PB_6 PROGRAMMABLE_BUTTON_6
899#define PB_7 PROGRAMMABLE_BUTTON_7
900#define PB_8 PROGRAMMABLE_BUTTON_8
901#define PB_9 PROGRAMMABLE_BUTTON_9
902#define PB_10 PROGRAMMABLE_BUTTON_10
903#define PB_11 PROGRAMMABLE_BUTTON_11
904#define PB_12 PROGRAMMABLE_BUTTON_12
905#define PB_13 PROGRAMMABLE_BUTTON_13
906#define PB_14 PROGRAMMABLE_BUTTON_14
907#define PB_15 PROGRAMMABLE_BUTTON_15
908#define PB_16 PROGRAMMABLE_BUTTON_16
909#define PB_17 PROGRAMMABLE_BUTTON_17
910#define PB_18 PROGRAMMABLE_BUTTON_18
911#define PB_19 PROGRAMMABLE_BUTTON_19
912#define PB_20 PROGRAMMABLE_BUTTON_20
913#define PB_21 PROGRAMMABLE_BUTTON_21
914#define PB_22 PROGRAMMABLE_BUTTON_22
915#define PB_23 PROGRAMMABLE_BUTTON_23
916#define PB_24 PROGRAMMABLE_BUTTON_24
917#define PB_25 PROGRAMMABLE_BUTTON_25
918#define PB_26 PROGRAMMABLE_BUTTON_26
919#define PB_27 PROGRAMMABLE_BUTTON_27
920#define PB_28 PROGRAMMABLE_BUTTON_28
921#define PB_29 PROGRAMMABLE_BUTTON_29
922#define PB_30 PROGRAMMABLE_BUTTON_30
923#define PB_31 PROGRAMMABLE_BUTTON_31
924#define PB_32 PROGRAMMABLE_BUTTON_32
925#define PROGRAMMABLE_BUTTON_MIN PROGRAMMABLE_BUTTON_1
926#define PROGRAMMABLE_BUTTON_MAX PROGRAMMABLE_BUTTON_32
diff --git a/show_options.mk b/show_options.mk
index cb3a32d39..35d0c2daa 100644
--- a/show_options.mk
+++ b/show_options.mk
@@ -83,7 +83,8 @@ OTHER_OPTION_NAMES = \
83 RGB_MATRIX_KEYPRESSES \ 83 RGB_MATRIX_KEYPRESSES \
84 LED_MIRRORED \ 84 LED_MIRRORED \
85 RGBLIGHT_FULL_POWER \ 85 RGBLIGHT_FULL_POWER \
86 LTO_ENABLE 86 LTO_ENABLE \
87 PROGRAMMABLE_BUTTON_ENABLE
87 88
88define NAME_ECHO 89define NAME_ECHO
89 @printf " %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)" 90 @printf " %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)"
diff --git a/tmk_core/common/chibios/suspend.c b/tmk_core/common/chibios/suspend.c
index 991fe6e08..9310a9992 100644
--- a/tmk_core/common/chibios/suspend.c
+++ b/tmk_core/common/chibios/suspend.c
@@ -7,6 +7,7 @@
7#include "action.h" 7#include "action.h"
8#include "action_util.h" 8#include "action_util.h"
9#include "mousekey.h" 9#include "mousekey.h"
10#include "programmable_button.h"
10#include "host.h" 11#include "host.h"
11#include "suspend.h" 12#include "suspend.h"
12#include "led.h" 13#include "led.h"
@@ -79,6 +80,9 @@ void suspend_wakeup_init(void) {
79#ifdef MOUSEKEY_ENABLE 80#ifdef MOUSEKEY_ENABLE
80 mousekey_clear(); 81 mousekey_clear();
81#endif /* MOUSEKEY_ENABLE */ 82#endif /* MOUSEKEY_ENABLE */
83#ifdef PROGRAMMABLE_BUTTON_ENABLE
84 programmable_button_clear();
85#endif /* PROGRAMMABLE_BUTTON_ENABLE */
82#ifdef EXTRAKEY_ENABLE 86#ifdef EXTRAKEY_ENABLE
83 host_system_send(0); 87 host_system_send(0);
84 host_consumer_send(0); 88 host_consumer_send(0);
diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c
index f0c396b18..56d4bb084 100644
--- a/tmk_core/common/host.c
+++ b/tmk_core/common/host.c
@@ -30,8 +30,9 @@ extern keymap_config_t keymap_config;
30#endif 30#endif
31 31
32static host_driver_t *driver; 32static host_driver_t *driver;
33static uint16_t last_system_report = 0; 33static uint16_t last_system_report = 0;
34static uint16_t last_consumer_report = 0; 34static uint16_t last_consumer_report = 0;
35static uint32_t last_programmable_button_report = 0;
35 36
36void host_set_driver(host_driver_t *d) { driver = d; } 37void host_set_driver(host_driver_t *d) { driver = d; }
37 38
@@ -122,6 +123,16 @@ void host_digitizer_send(digitizer_t *digitizer) {
122 123
123__attribute__((weak)) void send_digitizer(report_digitizer_t *report) {} 124__attribute__((weak)) void send_digitizer(report_digitizer_t *report) {}
124 125
126void host_programmable_button_send(uint32_t report) {
127 if (report == last_programmable_button_report) return;
128 last_programmable_button_report = report;
129
130 if (!driver) return;
131 (*driver->send_programmable_button)(report);
132}
133
125uint16_t host_last_system_report(void) { return last_system_report; } 134uint16_t host_last_system_report(void) { return last_system_report; }
126 135
127uint16_t host_last_consumer_report(void) { return last_consumer_report; } 136uint16_t host_last_consumer_report(void) { return last_consumer_report; }
137
138uint32_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 2cffef6e1..6b15f0d0c 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);
47void host_mouse_send(report_mouse_t *report); 47void host_mouse_send(report_mouse_t *report);
48void host_system_send(uint16_t data); 48void host_system_send(uint16_t data);
49void host_consumer_send(uint16_t data); 49void host_consumer_send(uint16_t data);
50void host_programmable_button_send(uint32_t data);
50 51
51uint16_t host_last_system_report(void); 52uint16_t host_last_system_report(void);
52uint16_t host_last_consumer_report(void); 53uint16_t host_last_consumer_report(void);
54uint32_t host_last_programmable_button_report(void);
53 55
54#ifdef __cplusplus 56#ifdef __cplusplus
55} 57}
diff --git a/tmk_core/common/host_driver.h b/tmk_core/common/host_driver.h
index 2aebca043..affd0dcb3 100644
--- a/tmk_core/common/host_driver.h
+++ b/tmk_core/common/host_driver.h
@@ -29,6 +29,7 @@ typedef struct {
29 void (*send_mouse)(report_mouse_t *); 29 void (*send_mouse)(report_mouse_t *);
30 void (*send_system)(uint16_t); 30 void (*send_system)(uint16_t);
31 void (*send_consumer)(uint16_t); 31 void (*send_consumer)(uint16_t);
32 void (*send_programmable_button)(uint32_t);
32} host_driver_t; 33} host_driver_t;
33 34
34void send_digitizer(report_digitizer_t *report); \ No newline at end of file 35void 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 f2223e806..1adc892f3 100644
--- a/tmk_core/common/report.h
+++ b/tmk_core/common/report.h
@@ -29,6 +29,7 @@ enum hid_report_ids {
29 REPORT_ID_MOUSE, 29 REPORT_ID_MOUSE,
30 REPORT_ID_SYSTEM, 30 REPORT_ID_SYSTEM,
31 REPORT_ID_CONSUMER, 31 REPORT_ID_CONSUMER,
32 REPORT_ID_PROGRAMMABLE_BUTTON,
32 REPORT_ID_NKRO, 33 REPORT_ID_NKRO,
33 REPORT_ID_JOYSTICK, 34 REPORT_ID_JOYSTICK,
34 REPORT_ID_DIGITIZER 35 REPORT_ID_DIGITIZER
@@ -196,6 +197,11 @@ typedef struct {
196} __attribute__((packed)) report_extra_t; 197} __attribute__((packed)) report_extra_t;
197 198
198typedef struct { 199typedef struct {
200 uint8_t report_id;
201 uint32_t usage;
202} __attribute__((packed)) report_programmable_button_t;
203
204typedef struct {
199#ifdef MOUSE_SHARED_EP 205#ifdef MOUSE_SHARED_EP
200 uint8_t report_id; 206 uint8_t report_id;
201#endif 207#endif
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 5b56e8a03..cb3aa693b 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);
142static void send_mouse(report_mouse_t *report); 142static void send_mouse(report_mouse_t *report);
143static void send_system(uint16_t data); 143static void send_system(uint16_t data);
144static void send_consumer(uint16_t data); 144static void send_consumer(uint16_t data);
145host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; 145static void send_programmable_button(uint32_t data);
146host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button};
146 147
147#ifdef VIRTSER_ENABLE 148#ifdef VIRTSER_ENABLE
148// clang-format off 149// clang-format off
@@ -760,27 +761,31 @@ static void send_mouse(report_mouse_t *report) {
760#endif 761#endif
761} 762}
762 763
763/** \brief Send Extra 764static void send_report(void *report, size_t size) {
764 *
765 * FIXME: Needs doc
766 */
767#ifdef EXTRAKEY_ENABLE
768static void send_extra(uint8_t report_id, uint16_t data) {
769 uint8_t timeout = 255; 765 uint8_t timeout = 255;
770 766
771 if (USB_DeviceState != DEVICE_STATE_Configured) return; 767 if (USB_DeviceState != DEVICE_STATE_Configured) return;
772 768
773 static report_extra_t r;
774 r = (report_extra_t){.report_id = report_id, .usage = data};
775 Endpoint_SelectEndpoint(SHARED_IN_EPNUM); 769 Endpoint_SelectEndpoint(SHARED_IN_EPNUM);
776 770
777 /* Check if write ready for a polling interval around 10ms */ 771 /* Check if write ready for a polling interval around 10ms */
778 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); 772 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
779 if (!Endpoint_IsReadWriteAllowed()) return; 773 if (!Endpoint_IsReadWriteAllowed()) return;
780 774
781 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); 775 Endpoint_Write_Stream_LE(report, size, NULL);
782 Endpoint_ClearIN(); 776 Endpoint_ClearIN();
783} 777}
778
779/** \brief Send Extra
780 *
781 * FIXME: Needs doc
782 */
783#ifdef EXTRAKEY_ENABLE
784static void send_extra(uint8_t report_id, uint16_t data) {
785 static report_extra_t r;
786 r = (report_extra_t){.report_id = report_id, .usage = data};
787 send_report(&r, sizeof(r));
788}
784#endif 789#endif
785 790
786/** \brief Send System 791/** \brief Send System
@@ -822,6 +827,14 @@ static void send_consumer(uint16_t data) {
822#endif 827#endif
823} 828}
824 829
830static void send_programmable_button(uint32_t data) {
831#ifdef PROGRAMMABLE_BUTTON_ENABLE
832 static report_programmable_button_t r;
833 r = (report_programmable_button_t){.report_id = REPORT_ID_PROGRAMMABLE_BUTTON, .usage = data};
834 send_report(&r, sizeof(r));
835#endif
836}
837
825/******************************************************************************* 838/*******************************************************************************
826 * sendchar 839 * sendchar
827 ******************************************************************************/ 840 ******************************************************************************/
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index 099964ae5..f720eea8d 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[] = {
237 HID_RI_END_COLLECTION(0), 237 HID_RI_END_COLLECTION(0),
238#endif 238#endif
239 239
240#ifdef PROGRAMMABLE_BUTTON_ENABLE
241 HID_RI_USAGE_PAGE(8, 0x0C), // Consumer
242 HID_RI_USAGE(8, 0x01), // Consumer Control
243 HID_RI_COLLECTION(8, 0x01), // Application
244 HID_RI_REPORT_ID(8, REPORT_ID_PROGRAMMABLE_BUTTON),
245 HID_RI_USAGE(8, 0x09), // Programmable Buttons
246 HID_RI_COLLECTION(8, 0x04), // Named Array
247 HID_RI_USAGE_PAGE(8, 0x09), // Button
248 HID_RI_USAGE_MINIMUM(8, 0x01), // Button 1
249 HID_RI_USAGE_MAXIMUM(8, 0x20), // Button 32
250 HID_RI_LOGICAL_MINIMUM(8, 0x01),
251 HID_RI_LOGICAL_MAXIMUM(8, 0x01),
252 HID_RI_REPORT_COUNT(8, 32),
253 HID_RI_REPORT_SIZE(8, 1),
254 HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
255 HID_RI_END_COLLECTION(0),
256 HID_RI_END_COLLECTION(0),
257#endif
258
240#ifdef NKRO_ENABLE 259#ifdef NKRO_ENABLE
241 HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop 260 HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
242 HID_RI_USAGE(8, 0x06), // Keyboard 261 HID_RI_USAGE(8, 0x06), // Keyboard
diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c
index 485b20c90..e4db5d065 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);
226static void send_mouse(report_mouse_t *report); 226static void send_mouse(report_mouse_t *report);
227static void send_system(uint16_t data); 227static void send_system(uint16_t data);
228static void send_consumer(uint16_t data); 228static void send_consumer(uint16_t data);
229static void send_programmable_button(uint32_t data);
229 230
230static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; 231static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button};
231 232
232host_driver_t *vusb_driver(void) { return &driver; } 233host_driver_t *vusb_driver(void) { return &driver; }
233 234
@@ -296,6 +297,19 @@ void send_digitizer(report_digitizer_t *report) {
296#ifdef DIGITIZER_ENABLE 297#ifdef DIGITIZER_ENABLE
297 if (usbInterruptIsReadyShared()) { 298 if (usbInterruptIsReadyShared()) {
298 usbSetInterruptShared((void *)report, sizeof(report_digitizer_t)); 299 usbSetInterruptShared((void *)report, sizeof(report_digitizer_t));
300#endif
301}
302
303static void send_programmable_button(uint32_t data) {
304#ifdef PROGRAMMABLE_BUTTON_ENABLE
305 static report_programmable_button_t report = {
306 .report_id = REPORT_ID_PROGRAMMABLE_BUTTON,
307 };
308
309 report.usage = data;
310
311 if (usbInterruptIsReadyShared()) {
312 usbSetInterruptShared((void *)&report, sizeof(report));
299 } 313 }
300#endif 314#endif
301} 315}
@@ -558,6 +572,26 @@ const PROGMEM uchar shared_hid_report[] = {
558 0xC0 // End Collection 572 0xC0 // End Collection
559#endif 573#endif
560 574
575#ifdef PROGRAMMABLE_BUTTON_ENABLE
576 // Programmable buttons report descriptor
577 0x05, 0x0C, // Usage Page (Consumer)
578 0x09, 0x01, // Usage (Consumer Control)
579 0xA1, 0x01, // Collection (Application)
580 0x85, REPORT_ID_PROGRAMMABLE_BUTTON, // Report ID
581 0x09, 0x03, // Usage (Programmable Buttons)
582 0xA1, 0x04, // Collection (Named Array)
583 0x05, 0x09, // Usage Page (Button)
584 0x19, 0x01, // Usage Minimum (Button 1)
585 0x29, 0x20, // Usage Maximum (Button 32)
586 0x15, 0x00, // Logical Minimum (0)
587 0x25, 0x01, // Logical Maximum (1)
588 0x95, 0x20, // Report Count (32)
589 0x75, 0x01, // Report Size (1)
590 0x81, 0x02, // Input (Data, Variable, Absolute)
591 0xC0, // End Collection
592 0xC0 // End Collection
593#endif
594
561#ifdef SHARED_EP_ENABLE 595#ifdef SHARED_EP_ENABLE
562}; 596};
563#endif 597#endif