diff options
| -rw-r--r-- | docs/custom_quantum_functions.md | 96 | ||||
| -rw-r--r-- | keyboards/maartenwut/wasdat/wasdat.c | 26 | ||||
| -rw-r--r-- | quantum/quantum.c | 21 | ||||
| -rw-r--r-- | quantum/quantum.h | 2 | ||||
| -rw-r--r-- | quantum/template/base/keyboard.c | 4 | ||||
| -rw-r--r-- | quantum/template/base/keymaps/default/keymap.c | 4 | ||||
| -rw-r--r-- | tmk_core/common/host.c | 6 | ||||
| -rw-r--r-- | tmk_core/common/host.h | 2 | ||||
| -rw-r--r-- | tmk_core/common/led.h | 13 |
9 files changed, 123 insertions, 51 deletions
diff --git a/docs/custom_quantum_functions.md b/docs/custom_quantum_functions.md index 839d49ca0..2d505b075 100644 --- a/docs/custom_quantum_functions.md +++ b/docs/custom_quantum_functions.md | |||
| @@ -90,68 +90,110 @@ keyrecord_t record { | |||
| 90 | 90 | ||
| 91 | # LED Control | 91 | # LED Control |
| 92 | 92 | ||
| 93 | QMK provides methods to read the 5 LEDs defined as part of the HID spec: | 93 | QMK provides methods to read 5 of the LEDs defined in the HID spec: |
| 94 | 94 | ||
| 95 | * `USB_LED_NUM_LOCK` | 95 | * Num Lock |
| 96 | * `USB_LED_CAPS_LOCK` | 96 | * Caps Lock |
| 97 | * `USB_LED_SCROLL_LOCK` | 97 | * Scroll Lock |
| 98 | * `USB_LED_COMPOSE` | 98 | * Compose |
| 99 | * `USB_LED_KANA` | 99 | * Kana |
| 100 | 100 | ||
| 101 | These five constants correspond to the positional bits of the host LED state. | 101 | There are two ways to get the lock LED state: |
| 102 | There are two ways to get the host LED state: | ||
| 103 | 102 | ||
| 104 | * by implementing `led_set_user()` | 103 | * by implementing `bool led_update_kb(led_t led_state)` or `_user(led_t led_state)`; or |
| 105 | * by calling `host_keyboard_leds()` | 104 | * by calling `led_t host_keyboard_led_state()` |
| 106 | 105 | ||
| 107 | ## `led_set_user()` | 106 | !> `host_keyboard_led_state()` may already reflect a new value before `led_update_user()` is called. |
| 108 | 107 | ||
| 109 | This function will be called when the state of one of those 5 LEDs changes. It receives the LED state as a parameter. | 108 | Two more deprecated functions exist that provide the LED state as a `uint8_t`: |
| 110 | Use the `IS_LED_ON(usb_led, led_name)` and `IS_LED_OFF(usb_led, led_name)` macros to check the LED status. | ||
| 111 | 109 | ||
| 112 | !> `host_keyboard_leds()` may already reflect a new value before `led_set_user()` is called. | 110 | * `uint8_t led_set_kb(uint8_t usb_led)` and `_user(uint8_t usb_led)` |
| 111 | * `uint8_t host_keyboard_leds()` | ||
| 113 | 112 | ||
| 114 | ### Example `led_set_user()` Implementation | 113 | ## `led_update_user()` |
| 114 | |||
| 115 | This function will be called when the state of one of those 5 LEDs changes. It receives the LED state as a struct parameter. | ||
| 116 | |||
| 117 | You must return either `true` or `false` from this function, depending on whether you want to override the keyboard-level implementation. | ||
| 118 | |||
| 119 | ?> Because the `led_set_*` functions return `void` instead of `bool`, they do not allow for overriding the keyboard LED control, and thus it's recommended to use `led_update_*` instead. | ||
| 120 | |||
| 121 | ### Example `led_update_kb()` Implementation | ||
| 122 | |||
| 123 | ```c | ||
| 124 | bool led_update_kb(led_t led_state) { | ||
| 125 | if(led_update_user(led_state)) { | ||
| 126 | if (led_state.num_lock) { | ||
| 127 | writePinLow(B0); | ||
| 128 | } else { | ||
| 129 | writePinHigh(B0); | ||
| 130 | } | ||
| 131 | if (led_state.caps_lock) { | ||
| 132 | writePinLow(B1); | ||
| 133 | } else { | ||
| 134 | writePinHigh(B1); | ||
| 135 | } | ||
| 136 | if (led_state.scroll_lock) { | ||
| 137 | writePinLow(B2); | ||
| 138 | } else { | ||
| 139 | writePinHigh(B2); | ||
| 140 | } | ||
| 141 | if (led_state.compose) { | ||
| 142 | writePinLow(B3); | ||
| 143 | } else { | ||
| 144 | writePinHigh(B3); | ||
| 145 | } | ||
| 146 | if (led_state.kana) { | ||
| 147 | writePinLow(B4); | ||
| 148 | } else { | ||
| 149 | writePinHigh(B4); | ||
| 150 | } | ||
| 151 | return true; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | ``` | ||
| 155 | |||
| 156 | ### Example `led_update_user()` Implementation | ||
| 115 | 157 | ||
| 116 | ```c | 158 | ```c |
| 117 | void led_set_user(uint8_t usb_led) { | 159 | bool led_update_user(led_t led_state) { |
| 118 | if (IS_LED_ON(usb_led, USB_LED_NUM_LOCK)) { | 160 | if (led_state.num_lock) { |
| 119 | writePinLow(B0); | 161 | writePinLow(B0); |
| 120 | } else { | 162 | } else { |
| 121 | writePinHigh(B0); | 163 | writePinHigh(B0); |
| 122 | } | 164 | } |
| 123 | if (IS_LED_ON(usb_led, USB_LED_CAPS_LOCK)) { | 165 | if (led_state.caps_lock) { |
| 124 | writePinLow(B1); | 166 | writePinLow(B1); |
| 125 | } else { | 167 | } else { |
| 126 | writePinHigh(B1); | 168 | writePinHigh(B1); |
| 127 | } | 169 | } |
| 128 | if (IS_LED_ON(usb_led, USB_LED_SCROLL_LOCK)) { | 170 | if (led_state.scroll_lock) { |
| 129 | writePinLow(B2); | 171 | writePinLow(B2); |
| 130 | } else { | 172 | } else { |
| 131 | writePinHigh(B2); | 173 | writePinHigh(B2); |
| 132 | } | 174 | } |
| 133 | if (IS_LED_ON(usb_led, USB_LED_COMPOSE)) { | 175 | if (led_state.compose) { |
| 134 | writePinLow(B3); | 176 | writePinLow(B3); |
| 135 | } else { | 177 | } else { |
| 136 | writePinHigh(B3); | 178 | writePinHigh(B3); |
| 137 | } | 179 | } |
| 138 | if (IS_LED_ON(usb_led, USB_LED_KANA)) { | 180 | if (led_state.kana) { |
| 139 | writePinLow(B4); | 181 | writePinLow(B4); |
| 140 | } else { | 182 | } else { |
| 141 | writePinHigh(B4); | 183 | writePinHigh(B4); |
| 142 | } | 184 | } |
| 185 | return true; | ||
| 143 | } | 186 | } |
| 144 | ``` | 187 | ``` |
| 145 | 188 | ||
| 146 | ### `led_set_*` Function Documentation | 189 | ### `led_update_*` Function Documentation |
| 147 | 190 | ||
| 148 | * Keyboard/Revision: `void led_set_kb(uint8_t usb_led)` | 191 | * Keyboard/Revision: `bool led_update_kb(led_t led_state)` |
| 149 | * Keymap: `void led_set_user(uint8_t usb_led)` | 192 | * Keymap: `bool led_update_user(led_t led_state)` |
| 150 | 193 | ||
| 151 | ## `host_keyboard_leds()` | 194 | ## `host_keyboard_led_state()` |
| 152 | 195 | ||
| 153 | Call this function to get the last received LED state. This is useful for reading the LED state outside `led_set_*`, e.g. in [`matrix_scan_user()`](#matrix-scanning-code). | 196 | Call this function to get the last received LED state as a `led_t`. This is useful for reading the LED state outside `led_update_*`, e.g. in [`matrix_scan_user()`](#matrix-scanning-code). |
| 154 | For convenience, you can use the `IS_HOST_LED_ON(led_name)` and `IS_HOST_LED_OFF(led_name)` macros instead of calling and checking `host_keyboard_leds()` directly. | ||
| 155 | 197 | ||
| 156 | ## Setting Physical LED State | 198 | ## Setting Physical LED State |
| 157 | 199 | ||
diff --git a/keyboards/maartenwut/wasdat/wasdat.c b/keyboards/maartenwut/wasdat/wasdat.c index 11338634d..99dd97dcf 100644 --- a/keyboards/maartenwut/wasdat/wasdat.c +++ b/keyboards/maartenwut/wasdat/wasdat.c | |||
| @@ -33,26 +33,12 @@ void led_init_ports(void) { | |||
| 33 | setPinOutput(B2); | 33 | setPinOutput(B2); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | void led_set_kb(uint8_t usb_led) { | 36 | bool led_update_kb(led_t led_state) { |
| 37 | // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here | 37 | if(led_update_user(led_state)) { |
| 38 | 38 | writePin(B0, !led_state.caps_lock); | |
| 39 | if (IS_LED_ON(usb_led, USB_LED_CAPS_LOCK)) { | 39 | writePin(B1, !led_state.scroll_lock); |
| 40 | writePinLow(B0); | 40 | writePin(B2, !led_state.num_lock); |
| 41 | } else { | ||
| 42 | writePinHigh(B0); | ||
| 43 | } | ||
| 44 | |||
| 45 | if (IS_LED_ON(usb_led, USB_LED_SCROLL_LOCK)) { | ||
| 46 | writePinLow(B1); | ||
| 47 | } else { | ||
| 48 | writePinHigh(B1); | ||
| 49 | } | ||
| 50 | |||
| 51 | if (IS_LED_ON(usb_led, USB_LED_NUM_LOCK)) { | ||
| 52 | writePinLow(B2); | ||
| 53 | } else { | ||
| 54 | writePinHigh(B2); | ||
| 55 | } | 41 | } |
| 56 | 42 | ||
| 57 | led_set_user(usb_led); | 43 | return true; |
| 58 | } | 44 | } |
diff --git a/quantum/quantum.c b/quantum/quantum.c index 1f17c6ff7..c27c3aba6 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c | |||
| @@ -1070,10 +1070,30 @@ void api_send_unicode(uint32_t unicode) { | |||
| 1070 | #endif | 1070 | #endif |
| 1071 | } | 1071 | } |
| 1072 | 1072 | ||
| 1073 | /** \brief Lock LED set callback - keymap/user level | ||
| 1074 | * | ||
| 1075 | * \deprecated Use led_update_user() instead. | ||
| 1076 | */ | ||
| 1073 | __attribute__((weak)) void led_set_user(uint8_t usb_led) {} | 1077 | __attribute__((weak)) void led_set_user(uint8_t usb_led) {} |
| 1074 | 1078 | ||
| 1079 | /** \brief Lock LED set callback - keyboard level | ||
| 1080 | * | ||
| 1081 | * \deprecated Use led_update_kb() instead. | ||
| 1082 | */ | ||
| 1075 | __attribute__((weak)) void led_set_kb(uint8_t usb_led) { led_set_user(usb_led); } | 1083 | __attribute__((weak)) void led_set_kb(uint8_t usb_led) { led_set_user(usb_led); } |
| 1076 | 1084 | ||
| 1085 | /** \brief Lock LED update callback - keymap/user level | ||
| 1086 | * | ||
| 1087 | * \return True if led_update_kb() should run its own code, false otherwise. | ||
| 1088 | */ | ||
| 1089 | __attribute__((weak)) bool led_update_user(led_t led_state) { return true; } | ||
| 1090 | |||
| 1091 | /** \brief Lock LED update callback - keyboard level | ||
| 1092 | * | ||
| 1093 | * \return Ignored for now. | ||
| 1094 | */ | ||
| 1095 | __attribute__((weak)) bool led_update_kb(led_t led_state) { return led_update_user(led_state); } | ||
| 1096 | |||
| 1077 | __attribute__((weak)) void led_init_ports(void) {} | 1097 | __attribute__((weak)) void led_init_ports(void) {} |
| 1078 | 1098 | ||
| 1079 | __attribute__((weak)) void led_set(uint8_t usb_led) { | 1099 | __attribute__((weak)) void led_set(uint8_t usb_led) { |
| @@ -1096,6 +1116,7 @@ __attribute__((weak)) void led_set(uint8_t usb_led) { | |||
| 1096 | #endif | 1116 | #endif |
| 1097 | 1117 | ||
| 1098 | led_set_kb(usb_led); | 1118 | led_set_kb(usb_led); |
| 1119 | led_update_kb((led_t) usb_led); | ||
| 1099 | } | 1120 | } |
| 1100 | 1121 | ||
| 1101 | //------------------------------------------------------------------------------ | 1122 | //------------------------------------------------------------------------------ |
diff --git a/quantum/quantum.h b/quantum/quantum.h index 87343a15d..7988c5878 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h | |||
| @@ -289,5 +289,7 @@ uint16_t hex_to_keycode(uint8_t hex); | |||
| 289 | 289 | ||
| 290 | void led_set_user(uint8_t usb_led); | 290 | void led_set_user(uint8_t usb_led); |
| 291 | void led_set_kb(uint8_t usb_led); | 291 | void led_set_kb(uint8_t usb_led); |
| 292 | bool led_update_user(led_t led_state); | ||
| 293 | bool led_update_kb(led_t led_state); | ||
| 292 | 294 | ||
| 293 | void api_send_unicode(uint32_t unicode); | 295 | void api_send_unicode(uint32_t unicode); |
diff --git a/quantum/template/base/keyboard.c b/quantum/template/base/keyboard.c index 55e4fffd3..fc31c294a 100644 --- a/quantum/template/base/keyboard.c +++ b/quantum/template/base/keyboard.c | |||
| @@ -42,9 +42,9 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | |||
| 42 | return process_record_user(keycode, record); | 42 | return process_record_user(keycode, record); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | void led_set_kb(uint8_t usb_led) { | 45 | bool led_update_kb(led_t led_state) { |
| 46 | // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here | 46 | // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here |
| 47 | 47 | ||
| 48 | led_set_user(usb_led); | 48 | return led_update_user(led_state); |
| 49 | } | 49 | } |
| 50 | */ | 50 | */ |
diff --git a/quantum/template/base/keymaps/default/keymap.c b/quantum/template/base/keymaps/default/keymap.c index 4d5bac7b2..3a68f5487 100644 --- a/quantum/template/base/keymaps/default/keymap.c +++ b/quantum/template/base/keymaps/default/keymap.c | |||
| @@ -70,7 +70,7 @@ void matrix_scan_user(void) { | |||
| 70 | 70 | ||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void led_set_user(uint8_t usb_led) { | 73 | bool led_update_user(led_t led_state) { |
| 74 | 74 | return true; | |
| 75 | } | 75 | } |
| 76 | */ | 76 | */ |
diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c index ce39760a5..713b0d945 100644 --- a/tmk_core/common/host.c +++ b/tmk_core/common/host.c | |||
| @@ -39,6 +39,12 @@ uint8_t host_keyboard_leds(void) { | |||
| 39 | if (!driver) return 0; | 39 | if (!driver) return 0; |
| 40 | return (*driver->keyboard_leds)(); | 40 | return (*driver->keyboard_leds)(); |
| 41 | } | 41 | } |
| 42 | |||
| 43 | led_t host_keyboard_led_state(void) { | ||
| 44 | if (!driver) return (led_t) {0}; | ||
| 45 | return (led_t)((*driver->keyboard_leds)()); | ||
| 46 | } | ||
| 47 | |||
| 42 | /* send report */ | 48 | /* send report */ |
| 43 | void host_keyboard_send(report_keyboard_t *report) { | 49 | void host_keyboard_send(report_keyboard_t *report) { |
| 44 | if (!driver) return; | 50 | if (!driver) return; |
diff --git a/tmk_core/common/host.h b/tmk_core/common/host.h index b2a7f9842..2cffef6e1 100644 --- a/tmk_core/common/host.h +++ b/tmk_core/common/host.h | |||
| @@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 21 | #include <stdbool.h> | 21 | #include <stdbool.h> |
| 22 | #include "report.h" | 22 | #include "report.h" |
| 23 | #include "host_driver.h" | 23 | #include "host_driver.h" |
| 24 | #include "led.h" | ||
| 24 | 25 | ||
| 25 | #define IS_LED_ON(leds, led_name) ((leds) & (1 << (led_name))) | 26 | #define IS_LED_ON(leds, led_name) ((leds) & (1 << (led_name))) |
| 26 | #define IS_LED_OFF(leds, led_name) (~(leds) & (1 << (led_name))) | 27 | #define IS_LED_OFF(leds, led_name) (~(leds) & (1 << (led_name))) |
| @@ -41,6 +42,7 @@ host_driver_t *host_get_driver(void); | |||
| 41 | 42 | ||
| 42 | /* host driver interface */ | 43 | /* host driver interface */ |
| 43 | uint8_t host_keyboard_leds(void); | 44 | uint8_t host_keyboard_leds(void); |
| 45 | led_t host_keyboard_led_state(void); | ||
| 44 | void host_keyboard_send(report_keyboard_t *report); | 46 | void host_keyboard_send(report_keyboard_t *report); |
| 45 | void host_mouse_send(report_mouse_t *report); | 47 | void host_mouse_send(report_mouse_t *report); |
| 46 | void host_system_send(uint16_t data); | 48 | void host_system_send(uint16_t data); |
diff --git a/tmk_core/common/led.h b/tmk_core/common/led.h index 2c28fe540..daf974bed 100644 --- a/tmk_core/common/led.h +++ b/tmk_core/common/led.h | |||
| @@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 18 | #ifndef LED_H | 18 | #ifndef LED_H |
| 19 | #define LED_H | 19 | #define LED_H |
| 20 | #include "stdint.h" | 20 | #include "stdint.h" |
| 21 | #include "stdbool.h" | ||
| 21 | 22 | ||
| 22 | /* FIXME: Add doxygen comments here. */ | 23 | /* FIXME: Add doxygen comments here. */ |
| 23 | 24 | ||
| @@ -32,6 +33,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 32 | extern "C" { | 33 | extern "C" { |
| 33 | #endif | 34 | #endif |
| 34 | 35 | ||
| 36 | typedef union { | ||
| 37 | uint8_t raw; | ||
| 38 | struct { | ||
| 39 | bool num_lock : 1; | ||
| 40 | bool caps_lock : 1; | ||
| 41 | bool scroll_lock : 1; | ||
| 42 | bool compose : 1; | ||
| 43 | bool kana : 1; | ||
| 44 | uint8_t reserved : 3; | ||
| 45 | }; | ||
| 46 | } led_t; | ||
| 47 | |||
| 35 | void led_set(uint8_t usb_led); | 48 | void led_set(uint8_t usb_led); |
| 36 | 49 | ||
| 37 | void led_init_ports(void); | 50 | void led_init_ports(void); |
