From 4039a50ec344bff10d9798a350e244351ec02f8b Mon Sep 17 00:00:00 2001 From: iangus Date: Sun, 30 Jan 2022 14:48:35 -0500 Subject: [PATCH 01/48] Add Contra shield (#633) * Add Contra Shield (#1) * Add bluetooth control layer to contra keymap (#2) * fix contra keymap issues * add bluetooth control layer * clean up contra files * add contra.conf file * add missing bracket for default_layer * update copyright year to 2021 * add contra metadata file * refactor pro micro overlay for new syntax --- app/boards/shields/contra/Kconfig.defconfig | 9 ++++ app/boards/shields/contra/Kconfig.shield | 5 +++ app/boards/shields/contra/contra.conf | 0 app/boards/shields/contra/contra.keymap | 46 +++++++++++++++++++++ app/boards/shields/contra/contra.overlay | 39 +++++++++++++++++ app/boards/shields/contra/contra.zmk.yml | 8 ++++ 6 files changed, 107 insertions(+) create mode 100644 app/boards/shields/contra/Kconfig.defconfig create mode 100644 app/boards/shields/contra/Kconfig.shield create mode 100644 app/boards/shields/contra/contra.conf create mode 100644 app/boards/shields/contra/contra.keymap create mode 100644 app/boards/shields/contra/contra.overlay create mode 100644 app/boards/shields/contra/contra.zmk.yml diff --git a/app/boards/shields/contra/Kconfig.defconfig b/app/boards/shields/contra/Kconfig.defconfig new file mode 100644 index 00000000..8fde0970 --- /dev/null +++ b/app/boards/shields/contra/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_CONTRA + +config ZMK_KEYBOARD_NAME + default "Contra Keyboard" + +endif \ No newline at end of file diff --git a/app/boards/shields/contra/Kconfig.shield b/app/boards/shields/contra/Kconfig.shield new file mode 100644 index 00000000..59412ff5 --- /dev/null +++ b/app/boards/shields/contra/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_CONTRA + def_bool $(shields_list_contains,contra) \ No newline at end of file diff --git a/app/boards/shields/contra/contra.conf b/app/boards/shields/contra/contra.conf new file mode 100644 index 00000000..e69de29b diff --git a/app/boards/shields/contra/contra.keymap b/app/boards/shields/contra/contra.keymap new file mode 100644 index 00000000..e24b5028 --- /dev/null +++ b/app/boards/shields/contra/contra.keymap @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#define DEFAULT 0 +#define NUM_MODS 1 +#define BT_CTRL 2 + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp ENTER + &kp LCTRL &kp LGUI &kp LALT &kp BSLH &to DEFAULT &kp SPACE &trans &to NUM_MODS &kp LEFT &kp RIGHT &kp UP &kp DOWN + >; + }; + + num_mods { + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &kp TAB &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp PG_UP &kp LBKT &kp RBKT &kp BSLH + &kp LSHFT &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp EQUAL &kp PG_DN &kp HOME &kp END &kp ENTER + &kp LCTRL &kp LGUI &kp LALT &reset &to DEFAULT &kp SPACE &trans &mo BT_CTRL &kp LEFT &kp RIGHT &kp UP &kp DOWN + >; + }; + + bt_control { + bindings = < + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &bt BT_PRV &bt BT_NXT &trans &trans + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/contra/contra.overlay b/app/boards/shields/contra/contra.overlay new file mode 100644 index 00000000..21e19425 --- /dev/null +++ b/app/boards/shields/contra/contra.overlay @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 3 GPIO_ACTIVE_HIGH> + , <&pro_micro 2 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 1 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/contra/contra.zmk.yml b/app/boards/shields/contra/contra.zmk.yml new file mode 100644 index 00000000..da3a9447 --- /dev/null +++ b/app/boards/shields/contra/contra.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: contra +name: Contra +type: shield +url: https://github.com/ai03-2725/Contra +requires: [pro_micro] +features: + - keys From 4c317e0febdb9b507ca202b03aebba05384c7646 Mon Sep 17 00:00:00 2001 From: Sam Mohr Date: Sun, 30 Jan 2022 15:55:22 -0500 Subject: [PATCH 02/48] Add support for the Clog (#1092) * Add support for the Clog * format DTSI definition * add a default keymap * update copyright year, reduce conf to minimum --- app/boards/shields/clog/Kconfig.defconfig | 19 ++++ app/boards/shields/clog/Kconfig.shield | 8 ++ app/boards/shields/clog/README.md | 8 ++ app/boards/shields/clog/clog.conf | 0 app/boards/shields/clog/clog.dtsi | 51 ++++++++++ app/boards/shields/clog/clog.keymap | 113 +++++++++++++++++++++ app/boards/shields/clog/clog.zmk.yml | 11 ++ app/boards/shields/clog/clog_left.overlay | 7 ++ app/boards/shields/clog/clog_right.overlay | 11 ++ 9 files changed, 228 insertions(+) create mode 100644 app/boards/shields/clog/Kconfig.defconfig create mode 100644 app/boards/shields/clog/Kconfig.shield create mode 100644 app/boards/shields/clog/README.md create mode 100644 app/boards/shields/clog/clog.conf create mode 100644 app/boards/shields/clog/clog.dtsi create mode 100644 app/boards/shields/clog/clog.keymap create mode 100644 app/boards/shields/clog/clog.zmk.yml create mode 100644 app/boards/shields/clog/clog_left.overlay create mode 100644 app/boards/shields/clog/clog_right.overlay diff --git a/app/boards/shields/clog/Kconfig.defconfig b/app/boards/shields/clog/Kconfig.defconfig new file mode 100644 index 00000000..60ef47e4 --- /dev/null +++ b/app/boards/shields/clog/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_CLOG_LEFT + +config ZMK_KEYBOARD_NAME + default "Clog" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif + +if SHIELD_CLOG_LEFT || SHIELD_CLOG_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/app/boards/shields/clog/Kconfig.shield b/app/boards/shields/clog/Kconfig.shield new file mode 100644 index 00000000..2301af94 --- /dev/null +++ b/app/boards/shields/clog/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_CLOG_LEFT + def_bool $(shields_list_contains,clog_left) + +config SHIELD_CLOG_RIGHT + def_bool $(shields_list_contains,clog_right) diff --git a/app/boards/shields/clog/README.md b/app/boards/shields/clog/README.md new file mode 100644 index 00000000..6b63889a --- /dev/null +++ b/app/boards/shields/clog/README.md @@ -0,0 +1,8 @@ +# The Clog + +The Clog is a 34-key choc v1 split board by S'mores. This firmware works for both the [Clog][clog], +as well as the [Sephirette][sephirette], the MX version. You can purchase kits for both boards +at smoresboards.com. + +[clog]: https://github.com/smores56/clog +[sephirette]: https://github.com/smores56/sephirette diff --git a/app/boards/shields/clog/clog.conf b/app/boards/shields/clog/clog.conf new file mode 100644 index 00000000..e69de29b diff --git a/app/boards/shields/clog/clog.dtsi b/app/boards/shields/clog/clog.dtsi new file mode 100644 index 00000000..27943100 --- /dev/null +++ b/app/boards/shields/clog/clog.dtsi @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <34>; + rows = <1>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,20) RC(0,19) RC(0,18) RC(0,17) + RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) RC(0,21) + RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) + RC(0,15) RC(0,16) RC(0,33) RC(0,32) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + label = "KSCAN"; + + input-gpios + = <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; +}; diff --git a/app/boards/shields/clog/clog.keymap b/app/boards/shields/clog/clog.keymap new file mode 100644 index 00000000..885404f7 --- /dev/null +++ b/app/boards/shields/clog/clog.keymap @@ -0,0 +1,113 @@ +/* +* Copyright (c) 2022 The ZMK Contributors +* +* SPDX-License-Identifier: MIT +*/ + +#include +#include +#include + +#define MAIN 0 +#define SYM 1 +#define NAV 2 +#define BT 3 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <140>; +}; + +/ { + combos { + compatible = "zmk,combos"; + + combo_esc { + timeout-ms = <100>; + key-positions = <21 22>; + bindings = <&kp ESC>; + }; + + combo_tab { + timeout-ms = <100>; + key-positions = <22 23>; + bindings = <&kp TAB>; + }; + + combo_minus { + timeout-ms = <100>; + key-positions = <26 27>; + bindings = <&kp MINUS>; + }; + + combo_underscore { + timeout-ms = <100>; + key-positions = <26 28>; + bindings = <&kp UNDERSCORE>; + }; + + combo_colon { + timeout-ms = <100>; + key-positions = <7 8>; + bindings = <&kp COLON>; + }; + + combo_semicolon { + timeout-ms = <100>; + key-positions = <6 8>; + bindings = <&kp SEMICOLON>; + }; + + combo_backslash { + timeout-ms = <100>; + key-positions = <27 28>; + bindings = <&kp BSLH>; + }; + + combo_grave { + timeout-ms = <100>; + key-positions = <8 9>; + bindings = <&kp GRAVE>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + MAIN_layer { + bindings = < + &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O + &kp Q &kp A &kp S &kp D < SYM F &kp G &kp H < SYM J &kp K &kp L &kp SQT &kp P + &mt LSHFT Z &mt LALT X &mt LCTRL C &mt LGUI V &kp B &kp N &mt RGUI M &mt RCTRL COMMA &mt RALT DOT &mt RSHFT FSLH + < BT ENTER < NAV SPACE &sk RSHFT &kp BSPC + >; + }; + + SYM_layer { + bindings = < + &kp N7 &kp N8 &kp N9 &kp STAR &kp DLLR &kp LBRC &kp RBRC &kp HASH + &kp AMPS &kp EXCL &kp N1 &kp N2 &kp N3 &kp EQUAL &kp LT &kp LPAR &kp RPAR &kp GT &kp PIPE &none + &kp CARET &kp N4 &kp N5 &kp N6 &kp PLUS &kp TILDE &kp LBKT &kp RBKT &kp AT &kp PRCNT + &kp DOT &kp N0 &trans &none + >; + }; + + NAV_layer { + bindings = < + &kp C_VOL_DN &kp C_VOL_UP &kp C_NEXT &kp C_PP &none &kp F7 &kp F8 &kp F9 + &kp C_PREV &kp LEFT &kp DOWN &kp UP &kp RIGHT &kp LC(TAB) &kp PSCRN &kp F1 &kp F2 &kp F3 &kp F10 &kp F12 + &kp HOME &kp PG_DN &kp PG_UP &kp END &kp LS(LC(TAB)) &kp CAPS &kp F4 &kp F5 &kp F6 &kp F11 + &none &none &trans &kp DEL + >; + }; + + BT_layer { + bindings = < + &none &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &none + &none &none &none &none &none &none &bt BT_CLR &none &none &none + &none &none &none &none + >; + }; + }; +}; diff --git a/app/boards/shields/clog/clog.zmk.yml b/app/boards/shields/clog/clog.zmk.yml new file mode 100644 index 00000000..f71df0df --- /dev/null +++ b/app/boards/shields/clog/clog.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: clog +name: Clog +type: shield +url: https://github.com/smores56/clog +requires: [pro_micro] +features: + - keys +siblings: + - clog_left + - clog_right diff --git a/app/boards/shields/clog/clog_left.overlay b/app/boards/shields/clog/clog_left.overlay new file mode 100644 index 00000000..58246025 --- /dev/null +++ b/app/boards/shields/clog/clog_left.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "clog.dtsi" diff --git a/app/boards/shields/clog/clog_right.overlay b/app/boards/shields/clog/clog_right.overlay new file mode 100644 index 00000000..0dc5d64f --- /dev/null +++ b/app/boards/shields/clog/clog_right.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "clog.dtsi" + +&default_transform { + col-offset = <17>; +}; From ed48d1ae899bd774f70eedf137c80c38c9f45cea Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 24 Jan 2022 13:43:45 -0500 Subject: [PATCH 03/48] fix(ble): Restore BLE SC passkey entry for pairing. * Handle capturing numeric inputs while pairing and sending final passkey once six digits entered. --- app/include/zmk/ble.h | 3 +- app/src/ble.c | 95 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 78 insertions(+), 20 deletions(-) diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index f6f6e191..0bdbab38 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -21,8 +21,7 @@ bool zmk_ble_active_profile_is_connected(); char *zmk_ble_active_profile_name(); int zmk_ble_unpair_all(); -bool zmk_ble_handle_key_user(struct zmk_key_event *key_event); #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr); -#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ \ No newline at end of file +#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ diff --git a/app/src/ble.c b/app/src/ble.c index a9f2afe9..68061129 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -36,10 +36,24 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +#define IS_HOST_PERIPHERAL \ + (!IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)) +#define IS_SPLIT_PERIPHERAL \ + (IS_ENABLED(CONFIG_ZMK_SPLIT) && !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)) + +#define DO_PASSKEY_ENTRY (IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) && !IS_SPLIT_PERIPHERAL) + +#if DO_PASSKEY_ENTRY +#include + +#define PASSKEY_DIGITS 6 + static struct bt_conn *auth_passkey_entry_conn; -static uint8_t passkey_entries[6] = {0, 0, 0, 0, 0, 0}; +static uint8_t passkey_entries[PASSKEY_DIGITS] = {}; static uint8_t passkey_digit = 0; +#endif + #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) #define PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1) #else @@ -66,11 +80,6 @@ static uint8_t active_profile; BUILD_ASSERT(DEVICE_NAME_LEN <= 16, "ERROR: BLE device name is too long. Max length: 16"); -#define IS_HOST_PERIPHERAL \ - (!IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)) -#define IS_SPLIT_PERIPHERAL \ - (IS_ENABLED(CONFIG_ZMK_SPLIT) && !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)) - static const struct bt_data zmk_ble_ad[] = { #if IS_HOST_PERIPHERAL BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), @@ -456,7 +465,7 @@ static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) { } */ -#ifdef CONFIG_ZMK_BLE_PASSKEY_ENTRY +#if DO_PASSKEY_ENTRY static void auth_passkey_entry(struct bt_conn *conn) { char addr[BT_ADDR_LE_STR_LEN]; @@ -464,6 +473,7 @@ static void auth_passkey_entry(struct bt_conn *conn) { bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); LOG_DBG("Passkey entry requested for %s", log_strdup(addr)); + passkey_digit = 0; auth_passkey_entry_conn = bt_conn_ref(conn); } @@ -474,12 +484,14 @@ static void auth_cancel(struct bt_conn *conn) { bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); +#if DO_PASSKEY_ENTRY if (auth_passkey_entry_conn) { bt_conn_unref(auth_passkey_entry_conn); auth_passkey_entry_conn = NULL; } passkey_digit = 0; +#endif LOG_DBG("Pairing cancelled: %s", log_strdup(addr)); } @@ -532,7 +544,7 @@ static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { .pairing_complete = auth_pairing_complete, // .passkey_display = auth_passkey_display, -#ifdef CONFIG_ZMK_BLE_PASSKEY_ENTRY +#if DO_PASSKEY_ENTRY .passkey_entry = auth_passkey_entry, #endif .cancel = auth_cancel, @@ -612,32 +624,79 @@ int zmk_ble_unpair_all() { return resp; }; -bool zmk_ble_handle_key_user(struct zmk_key_event *key_event) { - zmk_key_t key = key_event->key; +#if DO_PASSKEY_ENTRY + +static bool zmk_ble_numeric_usage_to_value(const zmk_key_t key, const zmk_key_t one, + const zmk_key_t zero, uint32_t *value) { + if (key < one || key > zero) { + return false; + } + + *value = (key == zero) ? 0 : (key - one + 1); + return true; +} + +static int zmk_ble_handle_key_user(struct zmk_keycode_state_changed *event) { + zmk_key_t key = event->keycode; + + LOG_DBG("key %d", key); if (!auth_passkey_entry_conn) { - return true; + LOG_DBG("No connection for passkey entry"); + return ZMK_EV_EVENT_BUBBLE; } - if (key < NUMBER_1 || key > NUMBER_0) { - return true; + if (!event->state) { + LOG_DBG("Key released, ignoring"); + return ZMK_EV_EVENT_BUBBLE; } - uint32_t val = (key == NUMBER_0) ? 0 : (key - NUMBER_1 + 1); + if (key == HID_USAGE_KEY_KEYBOARD_ESCAPE) { + bt_conn_auth_cancel(auth_passkey_entry_conn); + return ZMK_EV_EVENT_HANDLED; + } + + uint32_t val; + if (!(zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYBOARD_1_AND_EXCLAMATION, + HID_USAGE_KEY_KEYBOARD_0_AND_RIGHT_PARENTHESIS, &val) || + zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYPAD_1_AND_END, + HID_USAGE_KEY_KEYPAD_0_AND_INSERT, &val))) { + LOG_DBG("Key not a number, ignoring"); + return ZMK_EV_EVENT_BUBBLE; + } passkey_entries[passkey_digit++] = val; + LOG_DBG("value entered: %d, digits collected so far: %d", val, passkey_digit); - if (passkey_digit == 6) { + if (passkey_digit == PASSKEY_DIGITS) { uint32_t passkey = 0; - for (int i = 5; i >= 0; i--) { - passkey = (passkey * 10) + val; + for (int i = 0; i < PASSKEY_DIGITS; i++) { + passkey = (passkey * 10) + passkey_entries[i]; } + + LOG_DBG("Final passkey: %d", passkey); bt_conn_auth_passkey_entry(auth_passkey_entry_conn, passkey); bt_conn_unref(auth_passkey_entry_conn); auth_passkey_entry_conn = NULL; } - return false; + return ZMK_EV_EVENT_HANDLED; } +static int zmk_ble_listener(const zmk_event_t *eh) { + struct zmk_keycode_state_changed *kc_state; + + kc_state = as_zmk_keycode_state_changed(eh); + + if (kc_state != NULL) { + return zmk_ble_handle_key_user(kc_state); + } + + return 0; +} + +ZMK_LISTENER(zmk_ble, zmk_ble_listener); +ZMK_SUBSCRIPTION(zmk_ble, zmk_keycode_state_changed); +#endif /* DO_PASSKEY_ENTRY */ + SYS_INIT(zmk_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); From ac3c3170bd70f5186544495cb5ced7bfbf3f6764 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Dec 2021 05:06:40 +0000 Subject: [PATCH 04/48] chore(deps-dev): bump eslint-plugin-react from 7.24.0 to 7.28.0 in /docs Bumps [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) from 7.24.0 to 7.28.0. - [Release notes](https://github.com/yannickcr/eslint-plugin-react/releases) - [Changelog](https://github.com/yannickcr/eslint-plugin-react/blob/master/CHANGELOG.md) - [Commits](https://github.com/yannickcr/eslint-plugin-react/compare/v7.24.0...v7.28.0) --- updated-dependencies: - dependency-name: eslint-plugin-react dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- docs/package-lock.json | 877 +++++++++++++---------------------------- docs/package.json | 2 +- 2 files changed, 272 insertions(+), 607 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index af50fa60..6fe700d9 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -32,7 +32,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-mdx": "^1.13.0", - "eslint-plugin-react": "^7.23.2", + "eslint-plugin-react": "^7.28.0", "json-schema-to-typescript": "^10.1.3", "mustache": "^4.2.0", "null-loader": "^4.0.0", @@ -8360,16 +8360,16 @@ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "node_modules/array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" + "is-string": "^1.0.7" }, "engines": { "node": ">= 0.4" @@ -8378,48 +8378,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-includes/node_modules/es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes/node_modules/es-abstract/node_modules/is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -8445,15 +8403,14 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", - "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", "dev": true, "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "function-bind": "^1.1.1" + "es-abstract": "^1.19.0" }, "engines": { "node": ">= 0.4" @@ -10807,23 +10764,30 @@ } }, "node_modules/es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "dependencies": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -11448,29 +11412,31 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", - "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", + "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", "dev": true, "dependencies": { - "array-includes": "^3.1.3", - "array.prototype.flatmap": "^1.2.4", + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", "doctrine": "^2.1.0", - "has": "^1.0.3", + "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.0.4", - "object.entries": "^1.1.4", - "object.fromentries": "^2.0.4", - "object.values": "^1.1.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", "prop-types": "^15.7.2", "resolve": "^2.0.0-next.3", - "string.prototype.matchall": "^4.0.5" + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, "node_modules/eslint-plugin-react/node_modules/doctrine": { @@ -11485,6 +11451,15 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.3", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", @@ -11498,6 +11473,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -12653,6 +12637,21 @@ "node": ">=6" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -12931,6 +12930,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -13731,7 +13744,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -13911,9 +13923,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "engines": { "node": ">= 0.4" }, @@ -14223,12 +14235,12 @@ "dev": true }, "node_modules/is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dependencies": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -14258,6 +14270,14 @@ "node": ">=6" } }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -14267,9 +14287,12 @@ } }, "node_modules/is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -14296,6 +14319,17 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-whitespace-character": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", @@ -15619,9 +15653,9 @@ } }, "node_modules/object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -15678,71 +15712,28 @@ } }, "node_modules/object.entries": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", - "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "es-abstract": "^1.19.1" }, "engines": { "node": ">= 0.4" } }, - "node_modules/object.entries/node_modules/es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries/node_modules/is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.fromentries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", - "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" + "es-abstract": "^1.19.1" }, "engines": { "node": ">= 0.4" @@ -15751,48 +15742,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.fromentries/node_modules/es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.fromentries/node_modules/is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.getownpropertydescriptors": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", @@ -15809,41 +15758,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.getownpropertydescriptors/node_modules/es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "node_modules/object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.getownpropertydescriptors/node_modules/is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "engines": { - "node": ">= 0.4" + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -15861,13 +15783,13 @@ } }, "node_modules/object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "es-abstract": "^1.19.1" }, "engines": { "node": ">= 0.4" @@ -15876,46 +15798,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.values/node_modules/es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values/node_modules/is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -19385,7 +19267,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -19872,14 +19753,14 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string.prototype.matchall": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", - "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", @@ -19890,48 +19771,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.matchall/node_modules/es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.matchall/node_modules/is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/string.prototype.trimend": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", @@ -21050,30 +20889,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/util.promisify/node_modules/es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "dependencies": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/utila": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", @@ -28620,50 +28435,16 @@ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "dependencies": { - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true - } - } - } + "is-string": "^1.0.7" } }, "array-union": { @@ -28682,15 +28463,14 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, "array.prototype.flatmap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", - "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "function-bind": "^1.1.1" + "es-abstract": "^1.19.0" } }, "asap": { @@ -30469,23 +30249,30 @@ } }, "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "requires": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" } }, "es-module-lexer": { @@ -31021,23 +30808,25 @@ } }, "eslint-plugin-react": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", - "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", + "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", "dev": true, "requires": { - "array-includes": "^3.1.3", - "array.prototype.flatmap": "^1.2.4", + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", "doctrine": "^2.1.0", - "has": "^1.0.3", + "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.0.4", - "object.entries": "^1.1.4", - "object.fromentries": "^2.0.4", - "object.values": "^1.1.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", "prop-types": "^15.7.2", "resolve": "^2.0.0-next.3", - "string.prototype.matchall": "^4.0.5" + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" }, "dependencies": { "doctrine": { @@ -31049,6 +30838,12 @@ "esutils": "^2.0.2" } }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, "resolve": { "version": "2.0.0-next.3", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", @@ -31058,6 +30853,12 @@ "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, @@ -31928,6 +31729,15 @@ "pump": "^3.0.0" } }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -32141,6 +31951,14 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -32794,7 +32612,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, "requires": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -32909,9 +32726,9 @@ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" }, "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-ci": { "version": "2.0.0", @@ -33121,12 +32938,12 @@ "dev": true }, "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "requires": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" + "has-tostringtag": "^1.0.0" } }, "is-regexp": { @@ -33144,15 +32961,23 @@ "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-symbol": { "version": "1.0.4", @@ -33167,6 +32992,14 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "requires": { + "call-bind": "^1.0.2" + } + }, "is-whitespace-character": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", @@ -34199,9 +34032,9 @@ } }, "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" }, "object-is": { "version": "1.1.5", @@ -34237,90 +34070,25 @@ } }, "object.entries": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", - "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true - } + "es-abstract": "^1.19.1" } }, "object.fromentries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", - "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true - } + "es-abstract": "^1.19.1" } }, "object.getownpropertydescriptors": { @@ -34331,36 +34099,16 @@ "call-bind": "^1.0.2", "define-properties": "^1.1.3", "es-abstract": "^1.18.0-next.2" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" - } + } + }, + "object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" } }, "object.pick": { @@ -34372,43 +34120,13 @@ } }, "object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" - } + "es-abstract": "^1.19.1" } }, "obuf": { @@ -37045,7 +36763,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -37436,51 +37153,19 @@ } }, "string.prototype.matchall": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", - "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", "regexp.prototype.flags": "^1.3.1", "side-channel": "^1.0.4" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true - } } }, "string.prototype.trimend": { @@ -38287,26 +37972,6 @@ "es-abstract": "^1.17.2", "has-symbols": "^1.0.1", "object.getownpropertydescriptors": "^2.1.0" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } } }, "utila": { diff --git a/docs/package.json b/docs/package.json index f8b65cee..13add5d1 100644 --- a/docs/package.json +++ b/docs/package.json @@ -51,7 +51,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-mdx": "^1.13.0", - "eslint-plugin-react": "^7.23.2", + "eslint-plugin-react": "^7.28.0", "json-schema-to-typescript": "^10.1.3", "mustache": "^4.2.0", "null-loader": "^4.0.0", From 70bb7c93349344e0990f12282abfcd8d00ba7208 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 29 Nov 2021 04:26:22 +0000 Subject: [PATCH 05/48] feat(behaviors): `&key_repeat` behavior + tests. * Add new `&key_repeat` behavior that captures and re-sends the most recently triggered keycode. Closes: #853 --- app/CMakeLists.txt | 1 + app/dts/behaviors.dtsi | 1 + app/dts/behaviors/key_repeat.dtsi | 19 +++ .../behaviors/zmk,behavior-key-repeat.yaml | 13 ++ app/src/behaviors/behavior_key_repeat.c | 124 ++++++++++++++++++ app/tests/key-repeat/behavior_keymap.dtsi | 17 +++ .../events.patterns | 2 + .../keycode_events.snapshot | 12 ++ .../native_posix.keymap | 15 +++ .../events.patterns | 2 + .../keycode_events.snapshot | 8 ++ .../native_posix.keymap | 13 ++ .../events.patterns | 2 + .../keycode_events.snapshot | 0 .../native_posix.keymap | 11 ++ docs/docs/behaviors/key-repeat.md | 38 ++++++ 16 files changed, 278 insertions(+) create mode 100644 app/dts/behaviors/key_repeat.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml create mode 100644 app/src/behaviors/behavior_key_repeat.c create mode 100644 app/tests/key-repeat/behavior_keymap.dtsi create mode 100644 app/tests/key-repeat/ignore-other-usage-page-events/events.patterns create mode 100644 app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot create mode 100644 app/tests/key-repeat/ignore-other-usage-page-events/native_posix.keymap create mode 100644 app/tests/key-repeat/press-and-release-after-key-usage/events.patterns create mode 100644 app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot create mode 100644 app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap create mode 100644 app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns create mode 100644 app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/keycode_events.snapshot create mode 100644 app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix.keymap create mode 100644 docs/docs/behaviors/key-repeat.md diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 970c6c20..c5b74aa5 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -48,6 +48,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c) target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c) target_sources(app PRIVATE src/behaviors/behavior_caps_word.c) + target_sources(app PRIVATE src/behaviors/behavior_key_repeat.c) target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c) target_sources(app PRIVATE src/behaviors/behavior_mod_morph.c) target_sources(app PRIVATE src/behaviors/behavior_outputs.c) diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 5b5f72b4..06489616 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -15,3 +15,4 @@ #include #include #include +#include diff --git a/app/dts/behaviors/key_repeat.dtsi b/app/dts/behaviors/key_repeat.dtsi new file mode 100644 index 00000000..aa8ffa04 --- /dev/null +++ b/app/dts/behaviors/key_repeat.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + behaviors { + /omit-if-no-ref/ key_repeat: behavior_key_repeat { + compatible = "zmk,behavior-key-repeat"; + label = "KEY_REPEAT"; + #binding-cells = <0>; + usage-pages = ; + }; + }; +}; + diff --git a/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml b/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml new file mode 100644 index 00000000..10b3aa04 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Key repeat behavior + +compatible: "zmk,behavior-key-repeat" + +include: zero_param.yaml + +properties: + usage-pages: + type: array + required: true diff --git a/app/src/behaviors/behavior_key_repeat.c b/app/src/behaviors/behavior_key_repeat.c new file mode 100644 index 00000000..b2e28a6e --- /dev/null +++ b/app/src/behaviors/behavior_key_repeat.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_key_repeat + +#include +#include +#include +#include + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +struct behavior_key_repeat_config { + uint8_t index; + uint8_t usage_pages_count; + uint16_t usage_pages[]; +}; + +struct behavior_key_repeat_data { + struct zmk_keycode_state_changed last_keycode_pressed; + struct zmk_keycode_state_changed current_keycode_pressed; +}; + +static int on_key_repeat_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = device_get_binding(binding->behavior_dev); + struct behavior_key_repeat_data *data = dev->data; + + if (data->last_keycode_pressed.usage_page == 0) { + return ZMK_BEHAVIOR_OPAQUE; + } + + memcpy(&data->current_keycode_pressed, &data->last_keycode_pressed, + sizeof(struct zmk_keycode_state_changed)); + data->current_keycode_pressed.timestamp = k_uptime_get(); + + ZMK_EVENT_RAISE(new_zmk_keycode_state_changed(data->current_keycode_pressed)); + + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_key_repeat_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = device_get_binding(binding->behavior_dev); + struct behavior_key_repeat_data *data = dev->data; + + if (data->current_keycode_pressed.usage_page == 0) { + return ZMK_BEHAVIOR_OPAQUE; + } + + data->current_keycode_pressed.timestamp = k_uptime_get(); + data->current_keycode_pressed.state = false; + + ZMK_EVENT_RAISE(new_zmk_keycode_state_changed(data->current_keycode_pressed)); + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_key_repeat_driver_api = { + .binding_pressed = on_key_repeat_binding_pressed, + .binding_released = on_key_repeat_binding_released, +}; + +static int key_repeat_keycode_state_changed_listener(const zmk_event_t *eh); + +ZMK_LISTENER(behavior_key_repeat, key_repeat_keycode_state_changed_listener); +ZMK_SUBSCRIPTION(behavior_key_repeat, zmk_keycode_state_changed); + +static const struct device *devs[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)]; + +static int key_repeat_keycode_state_changed_listener(const zmk_event_t *eh) { + struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + if (ev == NULL || !ev->state) { + return ZMK_EV_EVENT_BUBBLE; + } + + for (int i = 0; i < DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT); i++) { + const struct device *dev = devs[i]; + if (dev == NULL) { + continue; + } + + struct behavior_key_repeat_data *data = dev->data; + const struct behavior_key_repeat_config *config = dev->config; + + for (int u = 0; u < config->usage_pages_count; u++) { + if (config->usage_pages[u] == ev->usage_page) { + memcpy(&data->last_keycode_pressed, ev, sizeof(struct zmk_keycode_state_changed)); + break; + } + } + } + + return ZMK_EV_EVENT_BUBBLE; +} + +static int behavior_key_repeat_init(const struct device *dev) { + const struct behavior_key_repeat_config *config = dev->config; + devs[config->index] = dev; + return 0; +} + +#define KR_INST(n) \ + static struct behavior_key_repeat_data behavior_key_repeat_data_##n = {}; \ + static struct behavior_key_repeat_config behavior_key_repeat_config_##n = { \ + .index = n, \ + .usage_pages = DT_INST_PROP(n, usage_pages), \ + .usage_pages_count = DT_INST_PROP_LEN(n, usage_pages), \ + }; \ + DEVICE_DT_INST_DEFINE(n, behavior_key_repeat_init, device_pm_control_nop, \ + &behavior_key_repeat_data_##n, &behavior_key_repeat_config_##n, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_key_repeat_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KR_INST) + +#endif diff --git a/app/tests/key-repeat/behavior_keymap.dtsi b/app/tests/key-repeat/behavior_keymap.dtsi new file mode 100644 index 00000000..93b6d069 --- /dev/null +++ b/app/tests/key-repeat/behavior_keymap.dtsi @@ -0,0 +1,17 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label = "Default keymap"; + + default_layer { + bindings = < + &key_repeat &kp A + &kp B &kp C_VOL_UP + >; + }; + }; +}; diff --git a/app/tests/key-repeat/ignore-other-usage-page-events/events.patterns b/app/tests/key-repeat/ignore-other-usage-page-events/events.patterns new file mode 100644 index 00000000..79471923 --- /dev/null +++ b/app/tests/key-repeat/ignore-other-usage-page-events/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot b/app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot new file mode 100644 index 00000000..c06d94a5 --- /dev/null +++ b/app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x0c keycode 0xe9 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x0c keycode 0xe9 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/key-repeat/ignore-other-usage-page-events/native_posix.keymap b/app/tests/key-repeat/ignore-other-usage-page-events/native_posix.keymap new file mode 100644 index 00000000..b042e8e0 --- /dev/null +++ b/app/tests/key-repeat/ignore-other-usage-page-events/native_posix.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/events.patterns b/app/tests/key-repeat/press-and-release-after-key-usage/events.patterns new file mode 100644 index 00000000..79471923 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-after-key-usage/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot b/app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot new file mode 100644 index 00000000..d568d378 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap b/app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap new file mode 100644 index 00000000..98c8f6f8 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns new file mode 100644 index 00000000..79471923 --- /dev/null +++ b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/keycode_events.snapshot b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/keycode_events.snapshot new file mode 100644 index 00000000..e69de29b diff --git a/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix.keymap b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix.keymap new file mode 100644 index 00000000..9ff64468 --- /dev/null +++ b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/docs/docs/behaviors/key-repeat.md b/docs/docs/behaviors/key-repeat.md new file mode 100644 index 00000000..5217bce8 --- /dev/null +++ b/docs/docs/behaviors/key-repeat.md @@ -0,0 +1,38 @@ +--- +title: Key Repeat Behavior +sidebar_label: Key Repeat +--- + +## Summary + +The key repeat behavior when triggered will send whatever keycode was last sent/triggered. + +### Behavior Binding + +- Reference: `&key_repeat` + +Example: + +``` +&key_repeat +``` + +### Configuration + +#### Usage Pages + +By default, the key repeat will only track the last pressed key from the HID "Key" usage page, and ignore events from other usages, e.g. Consumer page. + +If you'd rather have the repeat also capture and send Consumer page usages, you can update the existing behavior: + +``` +&key_repeat { + usage-pages = ; +}; + +/ { + keymap { + ... + }; +}; +``` From 52b1fd5dd3f1cb260cd0fba28c4b5aa23dd3d0f0 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 29 Nov 2021 15:41:22 +0000 Subject: [PATCH 06/48] fix(behaviors): Capture mods for `&key_repeat` * When tracking the last keycode, also capture the currently held explicit modifiers to use when replaying the key later. --- app/src/behaviors/behavior_key_repeat.c | 2 ++ app/tests/key-repeat/behavior_keymap.dtsi | 2 +- .../events.patterns | 2 ++ .../keycode_events.snapshot | 12 ++++++++++++ .../native_posix.keymap | 15 +++++++++++++++ 5 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 app/tests/key-repeat/press-and-release-with-explicit-modifiers/events.patterns create mode 100644 app/tests/key-repeat/press-and-release-with-explicit-modifiers/keycode_events.snapshot create mode 100644 app/tests/key-repeat/press-and-release-with-explicit-modifiers/native_posix.keymap diff --git a/app/src/behaviors/behavior_key_repeat.c b/app/src/behaviors/behavior_key_repeat.c index b2e28a6e..22de37d9 100644 --- a/app/src/behaviors/behavior_key_repeat.c +++ b/app/src/behaviors/behavior_key_repeat.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -93,6 +94,7 @@ static int key_repeat_keycode_state_changed_listener(const zmk_event_t *eh) { for (int u = 0; u < config->usage_pages_count; u++) { if (config->usage_pages[u] == ev->usage_page) { memcpy(&data->last_keycode_pressed, ev, sizeof(struct zmk_keycode_state_changed)); + data->last_keycode_pressed.implicit_modifiers |= zmk_hid_get_explicit_mods(); break; } } diff --git a/app/tests/key-repeat/behavior_keymap.dtsi b/app/tests/key-repeat/behavior_keymap.dtsi index 93b6d069..24902fc6 100644 --- a/app/tests/key-repeat/behavior_keymap.dtsi +++ b/app/tests/key-repeat/behavior_keymap.dtsi @@ -10,7 +10,7 @@ default_layer { bindings = < &key_repeat &kp A - &kp B &kp C_VOL_UP + &kp LCTRL &kp C_VOL_UP >; }; }; diff --git a/app/tests/key-repeat/press-and-release-with-explicit-modifiers/events.patterns b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/events.patterns new file mode 100644 index 00000000..79471923 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/press-and-release-with-explicit-modifiers/keycode_events.snapshot b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/keycode_events.snapshot new file mode 100644 index 00000000..628214a4 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x01 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x01 explicit_mods 0x00 +press: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x01 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/key-repeat/press-and-release-with-explicit-modifiers/native_posix.keymap b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/native_posix.keymap new file mode 100644 index 00000000..ab9622e4 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/native_posix.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file From c74ae45e1721bc9e63332c07fd0654c0e4126be1 Mon Sep 17 00:00:00 2001 From: Temur Beissov Date: Mon, 31 Jan 2022 22:02:19 +0300 Subject: [PATCH 07/48] Lotus58 (#1090) * lotus58 shield added * lotus58 default keymap * lotus58 keymap legend update * Lotus58 keymap fix * lotus58 keymap update * lotus58 kb name fixed * lotus58 keymap update PR fix --- app/boards/shields/lotus58/Kconfig.defconfig | 55 +++++++++ app/boards/shields/lotus58/Kconfig.shield | 8 ++ app/boards/shields/lotus58/lotus58.conf | 9 ++ app/boards/shields/lotus58/lotus58.dtsi | 89 +++++++++++++++ app/boards/shields/lotus58/lotus58.keymap | 104 ++++++++++++++++++ app/boards/shields/lotus58/lotus58.zmk.yml | 14 +++ .../shields/lotus58/lotus58_left.overlay | 22 ++++ .../shields/lotus58/lotus58_right.overlay | 26 +++++ 8 files changed, 327 insertions(+) create mode 100644 app/boards/shields/lotus58/Kconfig.defconfig create mode 100644 app/boards/shields/lotus58/Kconfig.shield create mode 100644 app/boards/shields/lotus58/lotus58.conf create mode 100644 app/boards/shields/lotus58/lotus58.dtsi create mode 100644 app/boards/shields/lotus58/lotus58.keymap create mode 100644 app/boards/shields/lotus58/lotus58.zmk.yml create mode 100644 app/boards/shields/lotus58/lotus58_left.overlay create mode 100644 app/boards/shields/lotus58/lotus58_right.overlay diff --git a/app/boards/shields/lotus58/Kconfig.defconfig b/app/boards/shields/lotus58/Kconfig.defconfig new file mode 100644 index 00000000..f0d35f4d --- /dev/null +++ b/app/boards/shields/lotus58/Kconfig.defconfig @@ -0,0 +1,55 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_LOTUS58_LEFT + +config ZMK_KEYBOARD_NAME + default "Lotus58" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif + +if SHIELD_LOTUS58_LEFT || SHIELD_LOTUS58_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LVGL_HOR_RES_MAX + default 128 + +config LVGL_VER_RES_MAX + default 32 + +config LVGL_VDB_SIZE + default 64 + +config LVGL_DPI + default 148 + +config LVGL_BITS_PER_PIXEL + default 1 + +choice LVGL_COLOR_DEPTH + default LVGL_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/lotus58/Kconfig.shield b/app/boards/shields/lotus58/Kconfig.shield new file mode 100644 index 00000000..dbf7ba01 --- /dev/null +++ b/app/boards/shields/lotus58/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_LOTUS58_LEFT + def_bool $(shields_list_contains,lotus58_left) + +config SHIELD_LOTUS58_RIGHT + def_bool $(shields_list_contains,lotus58_right) diff --git a/app/boards/shields/lotus58/lotus58.conf b/app/boards/shields/lotus58/lotus58.conf new file mode 100644 index 00000000..193f1ab4 --- /dev/null +++ b/app/boards/shields/lotus58/lotus58.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the Lotus58 OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/lotus58/lotus58.dtsi b/app/boards/shields/lotus58/lotus58.dtsi new file mode 100644 index 00000000..fb0d174f --- /dev/null +++ b/app/boards/shields/lotus58/lotus58.dtsi @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | SW30 | | SW30 | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(4,0) RC(4,11) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,7) RC(4,8) RC(4,9) RC(4,10) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + label = "LEFT_ENCODER"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + resolution = <4>; + status = "disabled"; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + label = "RIGHT_ENCODER"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + resolution = <4>; + status = "disabled"; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/lotus58/lotus58.keymap b/app/boards/shields/lotus58/lotus58.keymap new file mode 100644 index 00000000..cfe4342c --- /dev/null +++ b/app/boards/shields/lotus58/lotus58.keymap @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_dsklg { + timeout-ms = <100>; + key-positions = <24 52>; + layers = <0>; + bindings = <&kp LGUI>; + }; + }; + + behaviors { + fofunc: four_ffour { + compatible = "zmk,behavior-mod-morph"; + label = "FOUR_FUNCFOUR"; + #binding-cells = <0>; + bindings = <&kp N4>, <&kp F4>; + mods = <(MOD_LALT|MOD_RALT)>; + }; + sleft: s_left { + compatible = "zmk,behavior-mod-morph"; + label = "S_LEFT"; + #binding-cells = <0>; + bindings = <&kp S>, <&kp LEFT>; + mods = <(MOD_LGUI|MOD_RGUI)>; + }; + fright: f_right { + compatible = "zmk,behavior-mod-morph"; + label = "R_RIGHT"; + #binding-cells = <0>; + bindings = <&kp F>, <&kp RIGHT>; + mods = <(MOD_LGUI|MOD_RGUI)>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------------------------ +// 0| ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | = | 11 +// 12| TAB | Q | W | E | R | T | | Y | U | I | O | P | [ | 23 +// 24| SFT | A | S | D | F | G | RESET | | RESET | H | J | K | L | ; | ' SFT | 37 +// 38| CTRL | Z | X | C | V | B | MUTE | | PLAY | N | M | , | . | / | \ CTRL| 51 +// 52 |ENT RS| ALT | SPACE|DELETE LW| |ENTER RS| BSPC | ] LW | RGUI | 59 + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &fofunc &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp EQUAL +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT +&kp LSHFT &kp A &sleft &kp D &fright &kp G &reset &reset &kp H &kp J &kp K &kp L &kp SEMI &mt RSHFT SQT +&kp LCTRL &kp Z &kp X &kp C &kp V &kp B &kp C_MUTE &kp C_PP &kp N &kp M &kp COMMA &kp DOT &kp FSLH &mt RCTRL BSLH + < 2 RET &kp LALT &kp SPACE < 1 DEL < 2 RET &kp BSPC < 1 RBKT &kp LGUI + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP &inc_dec_kp PG_UP PG_DN>; + }; + + lower_layer { +// ------------------------------------------------------------------------------------------------------------ +// | ` | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | F11 | +// | | ! | HOME| ^ | END | % | | VOL^ | PGUP | INS | ^ | PSCR | - | +// | | # | <- | v | -> | $ | | | | VOLv | <- | ^ | -> | ~ | _ | +// | | @ | - | ( | ) | & | | | | MUTE | PGDN | v | : | * | | | +// | F11 | | | | | | | | F12 | + bindings = < +&kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp PLUS +&trans &kp EXCL &kp HOME &kp UP &kp END &kp PRCNT &kp C_VOL_UP &kp PG_UP &kp INS &kp CARET &kp PSCRN &kp MINUS +&trans &kp HASH &kp LEFT &kp DOWN &kp RIGHT &kp DLLR &trans &trans &kp C_VOL_DN &kp LEFT &kp UP &kp RIGHT &kp TILDE &kp UNDER +&trans &kp AT &kp MINUS &kp LBRC &kp RBRC &kp AMPS &trans &trans &kp C_MUTE &kp PG_DN &kp DOWN &kp COLON &kp STAR &kp PIPE + &kp F11 &trans &trans &trans &trans &trans &trans &kp F12 + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP &inc_dec_kp C_NEXT C_PREV>; + }; + + raise_layer { +// ------------------------------------------------------------------------------------------------------------ +// |BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | |OUTTOG|OUTUSB| OUTBT | | RESET | FLASH | +// | | INS | PSCR | GUI | RESET | | | PGUP | | ^ | | | | +// | | ALT | CTRL | SHIFT | FLASH | CAPS | | | | PGDN | <- | v | -> | DEL | BSPC | +// | | UNDO | CUT | COPY | PASTE | | | | | | |> | <|<| | |>|> | | | +// | | | | | | | | | | + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &out OUT_TOG &out OUT_USB &out OUT_BLE &trans &reset &bootloader +&trans &kp INS &kp PSCRN &kp K_CMENU &reset &trans &kp PG_UP &trans &kp UP &trans &trans &trans +&trans &kp LALT &kp LCTRL &kp LSHFT &bootloader &kp CLCK &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp DEL &kp BSPC +&trans &kp K_UNDO &kp K_CUT &kp K_COPY &kp K_PASTE &trans &trans &trans &trans &kp C_PP &kp C_PREV &kp C_NEXT &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; diff --git a/app/boards/shields/lotus58/lotus58.zmk.yml b/app/boards/shields/lotus58/lotus58.zmk.yml new file mode 100644 index 00000000..5cabbd0e --- /dev/null +++ b/app/boards/shields/lotus58/lotus58.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: lotus58 +name: Lotus58 +type: shield +url: https://github.com/TweetyDaBird/Lotus58 +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder +siblings: + - lotus58_left + - lotus58_right diff --git a/app/boards/shields/lotus58/lotus58_left.overlay b/app/boards/shields/lotus58/lotus58_left.overlay new file mode 100644 index 00000000..9755ae0b --- /dev/null +++ b/app/boards/shields/lotus58/lotus58_left.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "lotus58.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/lotus58/lotus58_right.overlay b/app/boards/shields/lotus58/lotus58_right.overlay new file mode 100644 index 00000000..dffcaeb1 --- /dev/null +++ b/app/boards/shields/lotus58/lotus58_right.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "lotus58.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; From 47f873b038c6468d29d97f855dfc05818f660418 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sun, 20 Dec 2020 09:49:42 -0500 Subject: [PATCH 08/48] feature(split): behavior locality support. * GATT characteristic allowing passng data + behavior label to invoke the behavior on the peripheral side. * Behaviors have a locality setting to specify where they run. * Build reset/power/RGB on peripheral. --- app/CMakeLists.txt | 4 +- app/dts/behaviors/ext_power.dtsi | 2 +- app/dts/behaviors/reset.dtsi | 2 +- app/dts/behaviors/rgb_underglow.dtsi | 2 +- app/include/drivers/behavior.h | 46 ++++++++++++++ .../zmk/events/position_state_changed.h | 11 +++- app/include/zmk/keymap.h | 5 +- app/include/zmk/split/bluetooth/central.h | 8 +++ app/include/zmk/split/bluetooth/service.h | 14 +++++ app/include/zmk/split/bluetooth/uuid.h | 1 + app/src/behaviors/behavior_ext_power.c | 1 + app/src/behaviors/behavior_reset.c | 1 + app/src/behaviors/behavior_rgb_underglow.c | 1 + app/src/keymap.c | 61 ++++++++++++++++--- app/src/kscan.c | 9 ++- app/src/split/bluetooth/central.c | 49 ++++++++++++++- app/src/split/bluetooth/service.c | 50 +++++++++++++++ 17 files changed, 247 insertions(+), 20 deletions(-) create mode 100644 app/include/zmk/split/bluetooth/central.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index c5b74aa5..1e153fb6 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -42,9 +42,10 @@ target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/battery_state_changed.c) target_sources_ifdef(CONFIG_USB app PRIVATE src/events/usb_conn_state_changed.c) +target_sources(app PRIVATE src/behaviors/behavior_reset.c) +target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c) if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_key_press.c) - target_sources(app PRIVATE src/behaviors/behavior_reset.c) target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c) target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c) target_sources(app PRIVATE src/behaviors/behavior_caps_word.c) @@ -57,7 +58,6 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_transparent.c) target_sources(app PRIVATE src/behaviors/behavior_none.c) target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) - target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c) target_sources(app PRIVATE src/combo.c) target_sources(app PRIVATE src/conditional_layer.c) target_sources(app PRIVATE src/keymap.c) diff --git a/app/dts/behaviors/ext_power.dtsi b/app/dts/behaviors/ext_power.dtsi index 742e33ae..abb7f2ff 100644 --- a/app/dts/behaviors/ext_power.dtsi +++ b/app/dts/behaviors/ext_power.dtsi @@ -8,7 +8,7 @@ behaviors { /omit-if-no-ref/ ext_power: behavior_ext_power { compatible = "zmk,behavior-ext-power"; - label = "EXT_POWER_BEHAVIOR"; + label = "EXTPOWER"; #binding-cells = <1>; }; }; diff --git a/app/dts/behaviors/reset.dtsi b/app/dts/behaviors/reset.dtsi index c720bc88..e4ba5658 100644 --- a/app/dts/behaviors/reset.dtsi +++ b/app/dts/behaviors/reset.dtsi @@ -16,7 +16,7 @@ /omit-if-no-ref/ bootloader: behavior_reset_dfu { compatible = "zmk,behavior-reset"; - label = "BOOTLOADER_RESET"; + label = "BOOTLOAD"; type = ; #binding-cells = <0>; }; diff --git a/app/dts/behaviors/rgb_underglow.dtsi b/app/dts/behaviors/rgb_underglow.dtsi index 60bdb3aa..265a1a52 100644 --- a/app/dts/behaviors/rgb_underglow.dtsi +++ b/app/dts/behaviors/rgb_underglow.dtsi @@ -8,7 +8,7 @@ behaviors { /omit-if-no-ref/ rgb_ug: behavior_rgb_underglow { compatible = "zmk,behavior-rgb-underglow"; - label = "RGB_UNDERGLOW"; + label = "RGB_UG"; #binding-cells = <2>; }; }; diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h index 2bdffea5..fcb24f6f 100644 --- a/app/include/drivers/behavior.h +++ b/app/include/drivers/behavior.h @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -26,7 +28,14 @@ typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_bin const struct device *sensor, int64_t timestamp); +enum behavior_locality { + BEHAVIOR_LOCALITY_CENTRAL, + BEHAVIOR_LOCALITY_EVENT_SOURCE, + BEHAVIOR_LOCALITY_GLOBAL +}; + __subsystem struct behavior_driver_api { + enum behavior_locality locality; behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params; behavior_keymap_binding_callback_t binding_pressed; behavior_keymap_binding_callback_t binding_released; @@ -60,6 +69,28 @@ static inline int z_impl_behavior_keymap_binding_convert_central_state_dependent return api->binding_convert_central_state_dependent_params(binding, event); } +/** + * @brief Determine where the behavior should be run + * @param behavior Pointer to the device structure for the driver instance. + * + * @retval Zero if successful. + * @retval Negative errno code if failure. + */ +__syscall int behavior_get_locality(const struct device *behavior, + enum behavior_locality *locality); + +static inline int z_impl_behavior_get_locality(const struct device *behavior, + enum behavior_locality *locality) { + if (behavior == NULL) { + return -EINVAL; + } + + const struct behavior_driver_api *api = (const struct behavior_driver_api *)behavior->api; + *locality = api->locality; + + return 0; +} + /** * @brief Handle the keymap binding being pressed * @param dev Pointer to the device structure for the driver instance. @@ -75,6 +106,11 @@ __syscall int behavior_keymap_binding_pressed(struct zmk_behavior_binding *bindi static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *dev = device_get_binding(binding->behavior_dev); + + if (dev == NULL) { + return -EINVAL; + } + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->binding_pressed == NULL) { @@ -98,6 +134,11 @@ __syscall int behavior_keymap_binding_released(struct zmk_behavior_binding *bind static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *dev = device_get_binding(binding->behavior_dev); + + if (dev == NULL) { + return -EINVAL; + } + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->binding_released == NULL) { @@ -125,6 +166,11 @@ static inline int z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding, const struct device *sensor, int64_t timestamp) { const struct device *dev = device_get_binding(binding->behavior_dev); + + if (dev == NULL) { + return -EINVAL; + } + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->sensor_binding_triggered == NULL) { diff --git a/app/include/zmk/events/position_state_changed.h b/app/include/zmk/events/position_state_changed.h index e2f68720..59619db6 100644 --- a/app/include/zmk/events/position_state_changed.h +++ b/app/include/zmk/events/position_state_changed.h @@ -8,10 +8,19 @@ #include #include +#include + +#if IS_ENABLED(CONFIG_ZMK_BLE) +typedef const bt_addr_le_t *zmk_position_state_changed_source_t; +#else +typedef void *zmk_position_state_changed_source_t; +#endif + struct zmk_position_state_changed { + zmk_position_state_changed_source_t source; uint32_t position; bool state; int64_t timestamp; }; -ZMK_EVENT_DECLARE(zmk_position_state_changed); \ No newline at end of file +ZMK_EVENT_DECLARE(zmk_position_state_changed); diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index 7151930a..0771542c 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -6,6 +6,8 @@ #pragma once +#include + typedef uint32_t zmk_keymap_layers_state_t; uint8_t zmk_keymap_layer_default(); @@ -18,7 +20,8 @@ int zmk_keymap_layer_toggle(uint8_t layer); int zmk_keymap_layer_to(uint8_t layer); const char *zmk_keymap_layer_label(uint8_t layer); -int zmk_keymap_position_state_changed(uint32_t position, bool pressed, int64_t timestamp); +int zmk_keymap_position_state_changed(zmk_position_state_changed_source_t source, uint32_t position, + bool pressed, int64_t timestamp); #define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \ { \ diff --git a/app/include/zmk/split/bluetooth/central.h b/app/include/zmk/split/bluetooth/central.h new file mode 100644 index 00000000..ab46a8f5 --- /dev/null +++ b/app/include/zmk/split/bluetooth/central.h @@ -0,0 +1,8 @@ + +#pragma once + +#include +#include + +int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event, bool state); \ No newline at end of file diff --git a/app/include/zmk/split/bluetooth/service.h b/app/include/zmk/split/bluetooth/service.h index b9f9fc3e..f0c1d79f 100644 --- a/app/include/zmk/split/bluetooth/service.h +++ b/app/include/zmk/split/bluetooth/service.h @@ -6,5 +6,19 @@ #pragma once +#define ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN 9 + +struct zmk_split_run_behavior_data { + uint8_t position; + uint8_t state; + uint32_t param1; + uint32_t param2; +} __packed; + +struct zmk_split_run_behavior_payload { + struct zmk_split_run_behavior_data data; + char behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN]; +} __packed; + int zmk_split_bt_position_pressed(uint8_t position); int zmk_split_bt_position_released(uint8_t position); \ No newline at end of file diff --git a/app/include/zmk/split/bluetooth/uuid.h b/app/include/zmk/split/bluetooth/uuid.h index a31884d9..735f5751 100644 --- a/app/include/zmk/split/bluetooth/uuid.h +++ b/app/include/zmk/split/bluetooth/uuid.h @@ -15,3 +15,4 @@ #define ZMK_BT_SPLIT_UUID(num) BT_UUID_128_ENCODE(num, 0x0096, 0x7107, 0xc967, 0xc5cfb1c2482a) #define ZMK_SPLIT_BT_SERVICE_UUID ZMK_BT_SPLIT_UUID(0x00000000) #define ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000001) +#define ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID ZMK_BT_SPLIT_UUID(0x00000002) diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c index fdd890c9..27793318 100644 --- a/app/src/behaviors/behavior_ext_power.c +++ b/app/src/behaviors/behavior_ext_power.c @@ -71,6 +71,7 @@ static const struct behavior_driver_api behavior_ext_power_driver_api = { on_keymap_binding_convert_central_state_dependent_params, .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released, + .locality = BEHAVIOR_LOCALITY_GLOBAL, }; DEVICE_DT_INST_DEFINE(0, behavior_ext_power_init, device_pm_control_nop, NULL, NULL, APPLICATION, diff --git a/app/src/behaviors/behavior_reset.c b/app/src/behaviors/behavior_reset.c index e19cf329..eb0477db 100644 --- a/app/src/behaviors/behavior_reset.c +++ b/app/src/behaviors/behavior_reset.c @@ -36,6 +36,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static const struct behavior_driver_api behavior_reset_driver_api = { .binding_pressed = on_keymap_binding_pressed, + .locality = BEHAVIOR_LOCALITY_EVENT_SOURCE, }; #define RST_INST(n) \ diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c index 0243b54b..33af6556 100644 --- a/app/src/behaviors/behavior_rgb_underglow.c +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -134,6 +134,7 @@ static const struct behavior_driver_api behavior_rgb_underglow_driver_api = { on_keymap_binding_convert_central_state_dependent_params, .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released, + .locality = BEHAVIOR_LOCALITY_GLOBAL, }; DEVICE_DT_INST_DEFINE(0, behavior_rgb_underglow_init, device_pm_control_nop, NULL, NULL, diff --git a/app/src/keymap.c b/app/src/keymap.c index 1643f647..16ec3169 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -4,7 +4,12 @@ * SPDX-License-Identifier: MIT */ +#define IS_BLE_CENTRAL \ + (IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_BLE) && \ + IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)) + #include +#include #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -14,6 +19,10 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +#if IS_BLE_CENTRAL +#include +#endif + #include #include #include @@ -152,7 +161,17 @@ const char *zmk_keymap_layer_label(uint8_t layer) { return zmk_keymap_layer_names[layer]; } -int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, int64_t timestamp) { +int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + bool pressed) { + if (pressed) { + return behavior_keymap_binding_pressed(binding, event); + } else { + return behavior_keymap_binding_released(binding, event); + } +} + +int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source, int layer, + uint32_t position, bool pressed, int64_t timestamp) { // We want to make a copy of this, since it may be converted from // relative to absolute before being invoked struct zmk_behavior_binding binding = zmk_keymap[layer][position]; @@ -169,7 +188,7 @@ int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, behavior = device_get_binding(binding.behavior_dev); if (!behavior) { - LOG_DBG("No behavior assigned to %d on layer %d", position, layer); + LOG_WRN("No behavior assigned to %d on layer %d", position, layer); return 1; } @@ -179,20 +198,44 @@ int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, return err; } - if (pressed) { - return behavior_keymap_binding_pressed(&binding, event); - } else { - return behavior_keymap_binding_released(&binding, event); + enum behavior_locality locality = BEHAVIOR_LOCALITY_CENTRAL; + err = behavior_get_locality(behavior, &locality); + if (err) { + LOG_ERR("Failed to get behavior locality %d", err); + return err; } + + switch (locality) { + case BEHAVIOR_LOCALITY_CENTRAL: + return invoke_locally(&binding, event, pressed); + case BEHAVIOR_LOCALITY_EVENT_SOURCE: +#if IS_BLE_CENTRAL + if (!bt_addr_le_cmp(source, BT_ADDR_LE_NONE)) { + return invoke_locally(&binding, event, pressed); + } else { + return zmk_split_bt_invoke_behavior(source, &binding, event, pressed); + } +#else + return invoke_locally(&binding, event, pressed); +#endif + case BEHAVIOR_LOCALITY_GLOBAL: +#if IS_BLE_CENTRAL + zmk_split_bt_invoke_behavior(BT_ADDR_LE_ANY, &binding, event, pressed); +#endif + return invoke_locally(&binding, event, pressed); + } + + return -ENOTSUP; } -int zmk_keymap_position_state_changed(uint32_t position, bool pressed, int64_t timestamp) { +int zmk_keymap_position_state_changed(zmk_position_state_changed_source_t source, uint32_t position, + bool pressed, int64_t timestamp) { if (pressed) { zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state; } for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { if (zmk_keymap_layer_active_with_state(layer, zmk_keymap_active_behavior_layer[position])) { - int ret = zmk_keymap_apply_position_state(layer, position, pressed, timestamp); + int ret = zmk_keymap_apply_position_state(source, layer, position, pressed, timestamp); if (ret > 0) { LOG_DBG("behavior processing to continue to next layer"); continue; @@ -249,7 +292,7 @@ int zmk_keymap_sensor_triggered(uint8_t sensor_number, const struct device *sens int keymap_listener(const zmk_event_t *eh) { const struct zmk_position_state_changed *pos_ev; if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) { - return zmk_keymap_position_state_changed(pos_ev->position, pos_ev->state, + return zmk_keymap_position_state_changed(pos_ev->source, pos_ev->position, pos_ev->state, pos_ev->timestamp); } diff --git a/app/src/kscan.c b/app/src/kscan.c index 3c9c201e..13ad2ccb 100644 --- a/app/src/kscan.c +++ b/app/src/kscan.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -49,8 +50,12 @@ void zmk_kscan_process_msgq(struct k_work *item) { uint32_t position = zmk_matrix_transform_row_column_to_position(ev.row, ev.column); LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s", ev.row, ev.column, position, (pressed ? "true" : "false")); - ZMK_EVENT_RAISE(new_zmk_position_state_changed((struct zmk_position_state_changed){ - .state = pressed, .position = position, .timestamp = k_uptime_get()})); + ZMK_EVENT_RAISE(new_zmk_position_state_changed((struct zmk_position_state_changed) { +#if IS_ENABLED(CONFIG_ZMK_BLE) + .source = BT_ADDR_LE_NONE, +#endif + .state = pressed, .position = position, .timestamp = k_uptime_get() + })); } } diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 9a7f01b2..5ac4f83c 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -18,7 +18,9 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include +#include #include +#include #include #include #include @@ -33,6 +35,7 @@ static const struct bt_uuid_128 split_service_uuid = BT_UUID_INIT_128(ZMK_SPLIT_ static struct bt_gatt_discover_params discover_params; static struct bt_gatt_subscribe_params subscribe_params; static struct bt_gatt_discover_params sub_discover_params; +static uint16_t run_behavior_handle; K_MSGQ_DEFINE(peripheral_event_msgq, sizeof(struct zmk_position_state_changed), CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4); @@ -72,8 +75,10 @@ static uint8_t split_central_notify_func(struct bt_conn *conn, if (changed_positions[i] & BIT(j)) { uint32_t position = (i * 8) + j; bool pressed = position_state[i] & BIT(j); - struct zmk_position_state_changed ev = { - .position = position, .state = pressed, .timestamp = k_uptime_get()}; + struct zmk_position_state_changed ev = {.source = bt_conn_get_dst(conn), + .position = position, + .state = pressed, + .timestamp = k_uptime_get()}; k_msgq_put(&peripheral_event_msgq, &ev, K_NO_WAIT); k_work_submit(&peripheral_event_work); @@ -124,9 +129,28 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, subscribe_params.disc_params = &sub_discover_params; subscribe_params.end_handle = discover_params.end_handle; subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + LOG_ERR("Discover failed (err %d)", err); + } + } else if (!bt_uuid_cmp(discover_params.uuid, + BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID))) { + run_behavior_handle = bt_gatt_attr_value_handle(attr); + } else { subscribe_params.notify = split_central_notify_func; subscribe_params.value = BT_GATT_CCC_NOTIFY; split_central_subscribe(conn); + + memcpy(&uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID), sizeof(uuid)); + discover_params.uuid = &uuid.uuid; + discover_params.start_handle = attr->handle + 1; + discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + LOG_ERR("Discover failed (err %d)", err); + } } return subscribe_params.value_handle ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE; @@ -340,6 +364,27 @@ static struct bt_conn_cb conn_callbacks = { .disconnected = split_central_disconnected, }; +int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event, bool state) { + struct zmk_split_run_behavior_payload payload = {.data = { + .param1 = binding->param1, + .param2 = binding->param2, + .position = event.position, + .state = state, + }}; + strncpy(payload.behavior_dev, binding->behavior_dev, ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1); + payload.behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1] = '\0'; + + int err = bt_gatt_write_without_response(default_conn, run_behavior_handle, &payload, + sizeof(struct zmk_split_run_behavior_payload), true); + + if (err) { + LOG_ERR("Failed to write the behavior characteristic (err %d)", err); + } + + return err; +}; + int zmk_split_bt_central_init(const struct device *_arg) { bt_conn_cb_register(&conn_callbacks); diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index fbac6446..bb0202c3 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -15,6 +15,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +#include +#include #include #include #include @@ -24,12 +26,57 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static uint8_t num_of_positions = ZMK_KEYMAP_LEN; static uint8_t position_state[POS_STATE_LEN]; +static struct zmk_split_run_behavior_payload behavior_run_payload; + static ssize_t split_svc_pos_state(struct bt_conn *conn, const struct bt_gatt_attr *attrs, void *buf, uint16_t len, uint16_t offset) { return bt_gatt_attr_read(conn, attrs, buf, len, offset, &position_state, sizeof(position_state)); } +static ssize_t split_svc_run_behavior(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) { + struct zmk_split_run_behavior_payload *payload = attrs->user_data; + uint16_t end_addr = offset + len; + + LOG_DBG("offset %d len %d", offset, len); + + if (end_addr > sizeof(struct zmk_split_run_behavior_payload)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(payload + offset, buf, len); + + // We run if: + // 1: We've gotten all the position/state/param data. + // 2: We have a null terminated string for the behavior device label. + if ((end_addr > sizeof(struct zmk_split_run_behavior_data)) && + payload->behavior_dev[end_addr - sizeof(struct zmk_split_run_behavior_data)] == '\0') { + struct zmk_behavior_binding binding = { + .param1 = payload->data.param1, + .param2 = payload->data.param2, + .behavior_dev = payload->behavior_dev, + }; + LOG_DBG("INVOKE THE BEHAVIOR: %s with params %d %d", log_strdup(binding.behavior_dev), + binding.param1, binding.param2); + struct zmk_behavior_binding_event event = {.position = payload->data.position, + .timestamp = k_uptime_get()}; + int err; + if (payload->data.state > 0) { + err = behavior_keymap_binding_pressed(&binding, event); + } else { + err = behavior_keymap_binding_released(&binding, event); + } + + if (err) { + LOG_ERR("Failed to invoke behavior %s: %d", log_strdup(binding.behavior_dev), err); + } + } + + return len; +} + static ssize_t split_svc_num_of_positions(struct bt_conn *conn, const struct bt_gatt_attr *attrs, void *buf, uint16_t len, uint16_t offset) { return bt_gatt_attr_read(conn, attrs, buf, len, offset, attrs->user_data, sizeof(uint8_t)); @@ -45,6 +92,9 @@ BT_GATT_SERVICE_DEFINE( BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, split_svc_pos_state, NULL, &position_state), BT_GATT_CCC(split_svc_pos_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID), + BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE_ENCRYPT, NULL, + split_svc_run_behavior, &behavior_run_payload), BT_GATT_DESCRIPTOR(BT_UUID_NUM_OF_DIGITALS, BT_GATT_PERM_READ, split_svc_num_of_positions, NULL, &num_of_positions), ); From 0febaa142a2baca1be293aca339bdc6920500c01 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 12 Jan 2021 10:49:00 -0500 Subject: [PATCH 09/48] refactor(split): Clean up split GATT discovery. * Use Zephyr auto CCC discovery instead of doing it ourselves. * Split service versus characteristic discovery into dedicated steps in the flow. * Fix for not searching properly when connecting to a peripheral a second time. --- app/src/split/bluetooth/central.c | 28 ++++++++-------------------- app/src/split_listener.c | 2 -- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 5ac4f83c..d123f4ec 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -129,31 +129,18 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, subscribe_params.disc_params = &sub_discover_params; subscribe_params.end_handle = discover_params.end_handle; subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); - - err = bt_gatt_discover(conn, &discover_params); - if (err) { - LOG_ERR("Discover failed (err %d)", err); - } - } else if (!bt_uuid_cmp(discover_params.uuid, - BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID))) { - run_behavior_handle = bt_gatt_attr_value_handle(attr); - } else { subscribe_params.notify = split_central_notify_func; subscribe_params.value = BT_GATT_CCC_NOTIFY; split_central_subscribe(conn); - - memcpy(&uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID), sizeof(uuid)); - discover_params.uuid = &uuid.uuid; - discover_params.start_handle = attr->handle + 1; - discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; - - err = bt_gatt_discover(conn, &discover_params); - if (err) { - LOG_ERR("Discover failed (err %d)", err); - } + } else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid, + BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID))) { + LOG_DBG("Found run behavior handle"); + run_behavior_handle = bt_gatt_attr_value_handle(attr); } - return subscribe_params.value_handle ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE; + bool subscribed = (run_behavior_handle && subscribe_params.value_handle); + + return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE; } static uint8_t split_central_service_discovery_func(struct bt_conn *conn, @@ -355,6 +342,7 @@ static void split_central_disconnected(struct bt_conn *conn, uint8_t reason) { // Clean up previously discovered handles; subscribe_params.value_handle = 0; + run_behavior_handle = 0; start_scan(); } diff --git a/app/src/split_listener.c b/app/src/split_listener.c index 8ac56c9f..01cd89d9 100644 --- a/app/src/split_listener.c +++ b/app/src/split_listener.c @@ -4,8 +4,6 @@ * SPDX-License-Identifier: MIT */ -#define DT_DRV_COMPAT zmk_split_listener - #include #include #include From d486304f7987e6cfd5ab9a77f3e077087759a258 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Tue, 9 Nov 2021 05:04:54 +0000 Subject: [PATCH 10/48] fix(underglow): Handle cycling effects on splits. * Convert relative effect cycling to absolute effect selection. --- app/include/dt-bindings/zmk/rgb.h | 3 ++- app/include/zmk/rgb_underglow.h | 2 ++ app/src/behaviors/behavior_rgb_underglow.c | 12 ++++++++++++ app/src/rgb_underglow.c | 16 +++++++++++++--- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/app/include/dt-bindings/zmk/rgb.h b/app/include/dt-bindings/zmk/rgb.h index 95aa5029..c1a80082 100644 --- a/app/include/dt-bindings/zmk/rgb.h +++ b/app/include/dt-bindings/zmk/rgb.h @@ -17,7 +17,8 @@ #define RGB_SPD_CMD 10 #define RGB_EFF_CMD 11 #define RGB_EFR_CMD 12 -#define RGB_COLOR_HSB_CMD 13 +#define RGB_EFS_CMD 13 +#define RGB_COLOR_HSB_CMD 14 #define RGB_TOG RGB_TOG_CMD 0 #define RGB_ON RGB_ON_CMD 0 diff --git a/app/include/zmk/rgb_underglow.h b/app/include/zmk/rgb_underglow.h index 4d452a6f..797f0b19 100644 --- a/app/include/zmk/rgb_underglow.h +++ b/app/include/zmk/rgb_underglow.h @@ -17,6 +17,8 @@ int zmk_rgb_underglow_get_state(bool *state); int zmk_rgb_underglow_on(); int zmk_rgb_underglow_off(); int zmk_rgb_underglow_cycle_effect(int direction); +int zmk_rgb_underglow_calc_effect(int direction); +int zmk_rgb_underglow_select_effect(int effect); struct zmk_led_hsb zmk_rgb_underglow_calc_hue(int direction); struct zmk_led_hsb zmk_rgb_underglow_calc_sat(int direction); struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction); diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c index 33af6556..96f69048 100644 --- a/app/src/behaviors/behavior_rgb_underglow.c +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -77,6 +77,16 @@ on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_bin binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); break; } + case RGB_EFR_CMD: { + binding->param1 = RGB_EFS_CMD; + binding->param2 = zmk_rgb_underglow_calc_effect(-1); + break; + } + case RGB_EFF_CMD: { + binding->param1 = RGB_EFS_CMD; + binding->param2 = zmk_rgb_underglow_calc_effect(1); + break; + } default: return 0; } @@ -111,6 +121,8 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, return zmk_rgb_underglow_change_spd(1); case RGB_SPD_CMD: return zmk_rgb_underglow_change_spd(-1); + case RGB_EFS_CMD: + return zmk_rgb_underglow_select_effect(binding->param2); case RGB_EFF_CMD: return zmk_rgb_underglow_cycle_effect(1); case RGB_EFR_CMD: diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 40d99c7d..427552fa 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -332,18 +332,28 @@ int zmk_rgb_underglow_off() { return zmk_rgb_underglow_save_state(); } -int zmk_rgb_underglow_cycle_effect(int direction) { +int zmk_rgb_underglow_calc_effect(int direction) { + return (state.current_effect + UNDERGLOW_EFFECT_NUMBER + direction) % UNDERGLOW_EFFECT_NUMBER; +} + +int zmk_rgb_underglow_select_effect(int effect) { if (!led_strip) return -ENODEV; - state.current_effect += UNDERGLOW_EFFECT_NUMBER + direction; - state.current_effect %= UNDERGLOW_EFFECT_NUMBER; + if (effect < 0 || effect >= UNDERGLOW_EFFECT_NUMBER) { + return -EINVAL; + } + state.current_effect = effect; state.animation_step = 0; return zmk_rgb_underglow_save_state(); } +int zmk_rgb_underglow_cycle_effect(int direction) { + return zmk_rgb_underglow_select_effect(zmk_rgb_underglow_calc_effect(direction)); +} + int zmk_rgb_underglow_toggle() { return state.on ? zmk_rgb_underglow_off() : zmk_rgb_underglow_on(); } From ce3471d4feef7c51e28d52587ccc51b500853b4e Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sat, 20 Nov 2021 22:12:24 +0000 Subject: [PATCH 11/48] fix(split): Add queue for running remote behaviors --- app/Kconfig | 8 +++++ app/src/split/bluetooth/central.c | 59 ++++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index 3502c652..76035147 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -175,6 +175,14 @@ config ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE int "Max number of key position state events to queue when received from peripherals" default 5 +config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_STACK_SIZE + int "BLE split central write thread stack size" + default 512 + +config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE + int "Max number of behavior run events to queue to send to the peripheral(s)" + default 5 + endif if !ZMK_SPLIT_BLE_ROLE_CENTRAL diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index d123f4ec..c28941f1 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -352,6 +352,51 @@ static struct bt_conn_cb conn_callbacks = { .disconnected = split_central_disconnected, }; +K_THREAD_STACK_DEFINE(split_central_split_run_q_stack, + CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_STACK_SIZE); + +struct k_work_q split_central_split_run_q; + +K_MSGQ_DEFINE(zmk_split_central_split_run_msgq, sizeof(struct zmk_split_run_behavior_payload), + CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE, 4); + +void split_central_split_run_callback(struct k_work *work) { + struct zmk_split_run_behavior_payload payload; + + while (k_msgq_get(&zmk_split_central_split_run_msgq, &payload, K_NO_WAIT) == 0) { + int err = + bt_gatt_write_without_response(default_conn, run_behavior_handle, &payload, + sizeof(struct zmk_split_run_behavior_payload), true); + + if (err) { + LOG_ERR("Failed to write the behavior characteristic (err %d)", err); + } + } +} + +K_WORK_DEFINE(split_central_split_run_work, split_central_split_run_callback); + +static int split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payload payload) { + int err = k_msgq_put(&zmk_split_central_split_run_msgq, &payload, K_MSEC(100)); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("Consumer message queue full, popping first message and queueing again"); + struct zmk_split_run_behavior_payload discarded_report; + k_msgq_get(&zmk_split_central_split_run_msgq, &discarded_report, K_NO_WAIT); + return split_bt_invoke_behavior_payload(payload); + } + default: + LOG_WRN("Failed to queue behavior to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&split_central_split_run_q, &split_central_split_run_work); + + return 0; +}; + int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, bool state) { struct zmk_split_run_behavior_payload payload = {.data = { @@ -363,17 +408,13 @@ int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior strncpy(payload.behavior_dev, binding->behavior_dev, ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1); payload.behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1] = '\0'; - int err = bt_gatt_write_without_response(default_conn, run_behavior_handle, &payload, - sizeof(struct zmk_split_run_behavior_payload), true); - - if (err) { - LOG_ERR("Failed to write the behavior characteristic (err %d)", err); - } - - return err; -}; + return split_bt_invoke_behavior_payload(payload); +} int zmk_split_bt_central_init(const struct device *_arg) { + k_work_q_start(&split_central_split_run_q, split_central_split_run_q_stack, + K_THREAD_STACK_SIZEOF(split_central_split_run_q_stack), + CONFIG_ZMK_BLE_THREAD_PRIORITY); bt_conn_cb_register(&conn_callbacks); return start_scan(); From e8540f17fcf2e99604c2d497dab5cf87092b45d5 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 22 Nov 2021 06:02:05 +0000 Subject: [PATCH 12/48] fix: Ensure power and underglow behaviors built. * Remove `/omit-if-no-ref/` from the behavior nodes. --- app/dts/behaviors/ext_power.dtsi | 2 +- app/dts/behaviors/rgb_underglow.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/dts/behaviors/ext_power.dtsi b/app/dts/behaviors/ext_power.dtsi index abb7f2ff..18e824e2 100644 --- a/app/dts/behaviors/ext_power.dtsi +++ b/app/dts/behaviors/ext_power.dtsi @@ -6,7 +6,7 @@ / { behaviors { - /omit-if-no-ref/ ext_power: behavior_ext_power { + ext_power: behavior_ext_power { compatible = "zmk,behavior-ext-power"; label = "EXTPOWER"; #binding-cells = <1>; diff --git a/app/dts/behaviors/rgb_underglow.dtsi b/app/dts/behaviors/rgb_underglow.dtsi index 265a1a52..54fe422e 100644 --- a/app/dts/behaviors/rgb_underglow.dtsi +++ b/app/dts/behaviors/rgb_underglow.dtsi @@ -6,7 +6,7 @@ / { behaviors { - /omit-if-no-ref/ rgb_ug: behavior_rgb_underglow { + rgb_ug: behavior_rgb_underglow { compatible = "zmk,behavior-rgb-underglow"; label = "RGB_UG"; #binding-cells = <2>; From 9297c5f2b43bae138bea712928f9e8c66efb74a7 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sun, 2 Jan 2022 04:55:30 +0000 Subject: [PATCH 13/48] refactor(splits): Use index for event source. * Track peripherals by indexes slot, with all appropiate peripheral state stored in the slot. * Event sources tracked by peripheral slot index. --- app/include/zmk/ble.h | 11 + .../zmk/events/position_state_changed.h | 9 +- app/include/zmk/keymap.h | 4 +- app/include/zmk/split/bluetooth/central.h | 2 +- app/src/ble.c | 16 +- app/src/keymap.c | 25 +- app/src/kscan.c | 11 +- app/src/split/bluetooth/central.c | 277 +++++++++++++----- 8 files changed, 252 insertions(+), 103 deletions(-) diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index 0bdbab38..f813ddc8 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -9,6 +9,17 @@ #include #include +#define ZMK_BLE_IS_CENTRAL \ + (IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_BLE) && \ + IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)) + +#if ZMK_BLE_IS_CENTRAL +#define ZMK_BLE_PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1) +#define ZMK_BLE_SPLIT_PERIPHERAL_COUNT 1 +#else +#define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED +#endif + int zmk_ble_clear_bonds(); int zmk_ble_prof_next(); int zmk_ble_prof_prev(); diff --git a/app/include/zmk/events/position_state_changed.h b/app/include/zmk/events/position_state_changed.h index 59619db6..7685fe0f 100644 --- a/app/include/zmk/events/position_state_changed.h +++ b/app/include/zmk/events/position_state_changed.h @@ -8,16 +8,9 @@ #include #include -#include - -#if IS_ENABLED(CONFIG_ZMK_BLE) -typedef const bt_addr_le_t *zmk_position_state_changed_source_t; -#else -typedef void *zmk_position_state_changed_source_t; -#endif struct zmk_position_state_changed { - zmk_position_state_changed_source_t source; + uint8_t source; uint32_t position; bool state; int64_t timestamp; diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index 0771542c..1195b943 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -20,8 +20,8 @@ int zmk_keymap_layer_toggle(uint8_t layer); int zmk_keymap_layer_to(uint8_t layer); const char *zmk_keymap_layer_label(uint8_t layer); -int zmk_keymap_position_state_changed(zmk_position_state_changed_source_t source, uint32_t position, - bool pressed, int64_t timestamp); +int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed, + int64_t timestamp); #define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \ { \ diff --git a/app/include/zmk/split/bluetooth/central.h b/app/include/zmk/split/bluetooth/central.h index ab46a8f5..07240860 100644 --- a/app/include/zmk/split/bluetooth/central.h +++ b/app/include/zmk/split/bluetooth/central.h @@ -4,5 +4,5 @@ #include #include -int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding, +int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, bool state); \ No newline at end of file diff --git a/app/src/ble.c b/app/src/ble.c index 68061129..afc2e47f 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -72,7 +72,7 @@ enum advertising_type { BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, BT_GAP_ADV_FAST_INT_MIN_2, \ BT_GAP_ADV_FAST_INT_MAX_2, NULL) -static struct zmk_ble_profile profiles[PROFILE_COUNT]; +static struct zmk_ble_profile profiles[ZMK_BLE_PROFILE_COUNT]; static uint8_t active_profile; #define DEVICE_NAME CONFIG_BT_DEVICE_NAME @@ -260,7 +260,7 @@ static int ble_save_profile() { } int zmk_ble_prof_select(uint8_t index) { - if (index >= PROFILE_COUNT) { + if (index >= ZMK_BLE_PROFILE_COUNT) { return -ERANGE; } @@ -281,12 +281,13 @@ int zmk_ble_prof_select(uint8_t index) { int zmk_ble_prof_next() { LOG_DBG(""); - return zmk_ble_prof_select((active_profile + 1) % PROFILE_COUNT); + return zmk_ble_prof_select((active_profile + 1) % ZMK_BLE_PROFILE_COUNT); }; int zmk_ble_prof_prev() { LOG_DBG(""); - return zmk_ble_prof_select((active_profile + PROFILE_COUNT - 1) % PROFILE_COUNT); + return zmk_ble_prof_select((active_profile + ZMK_BLE_PROFILE_COUNT - 1) % + ZMK_BLE_PROFILE_COUNT); }; bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].peer; } @@ -324,8 +325,9 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c return -EINVAL; } - if (idx >= PROFILE_COUNT) { - LOG_WRN("Profile address for index %d is larger than max of %d", idx, PROFILE_COUNT); + if (idx >= ZMK_BLE_PROFILE_COUNT) { + LOG_WRN("Profile address for index %d is larger than max of %d", idx, + ZMK_BLE_PROFILE_COUNT); return -EINVAL; } @@ -591,7 +593,7 @@ static int zmk_ble_init(const struct device *_arg) { bt_unpair(i, NULL); } - for (int i = 0; i < PROFILE_COUNT; i++) { + for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { char setting_name[15]; sprintf(setting_name, "ble/profiles/%d", i); diff --git a/app/src/keymap.c b/app/src/keymap.c index 16ec3169..8acc5ec1 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -4,10 +4,6 @@ * SPDX-License-Identifier: MIT */ -#define IS_BLE_CENTRAL \ - (IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_BLE) && \ - IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)) - #include #include #include @@ -19,7 +15,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include -#if IS_BLE_CENTRAL +#include +#if ZMK_BLE_IS_CENTRAL #include #endif @@ -170,8 +167,8 @@ int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_bin } } -int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source, int layer, - uint32_t position, bool pressed, int64_t timestamp) { +int zmk_keymap_apply_position_state(uint8_t source, int layer, uint32_t position, bool pressed, + int64_t timestamp) { // We want to make a copy of this, since it may be converted from // relative to absolute before being invoked struct zmk_behavior_binding binding = zmk_keymap[layer][position]; @@ -209,8 +206,8 @@ int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source, case BEHAVIOR_LOCALITY_CENTRAL: return invoke_locally(&binding, event, pressed); case BEHAVIOR_LOCALITY_EVENT_SOURCE: -#if IS_BLE_CENTRAL - if (!bt_addr_le_cmp(source, BT_ADDR_LE_NONE)) { +#if ZMK_BLE_IS_CENTRAL + if (source == UINT_MAX) { return invoke_locally(&binding, event, pressed); } else { return zmk_split_bt_invoke_behavior(source, &binding, event, pressed); @@ -219,8 +216,10 @@ int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source, return invoke_locally(&binding, event, pressed); #endif case BEHAVIOR_LOCALITY_GLOBAL: -#if IS_BLE_CENTRAL - zmk_split_bt_invoke_behavior(BT_ADDR_LE_ANY, &binding, event, pressed); +#if ZMK_BLE_IS_CENTRAL + for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) { + zmk_split_bt_invoke_behavior(i, &binding, event, pressed); + } #endif return invoke_locally(&binding, event, pressed); } @@ -228,8 +227,8 @@ int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source, return -ENOTSUP; } -int zmk_keymap_position_state_changed(zmk_position_state_changed_source_t source, uint32_t position, - bool pressed, int64_t timestamp) { +int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed, + int64_t timestamp) { if (pressed) { zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state; } diff --git a/app/src/kscan.c b/app/src/kscan.c index 13ad2ccb..3425fabe 100644 --- a/app/src/kscan.c +++ b/app/src/kscan.c @@ -50,12 +50,11 @@ void zmk_kscan_process_msgq(struct k_work *item) { uint32_t position = zmk_matrix_transform_row_column_to_position(ev.row, ev.column); LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s", ev.row, ev.column, position, (pressed ? "true" : "false")); - ZMK_EVENT_RAISE(new_zmk_position_state_changed((struct zmk_position_state_changed) { -#if IS_ENABLED(CONFIG_ZMK_BLE) - .source = BT_ADDR_LE_NONE, -#endif - .state = pressed, .position = position, .timestamp = k_uptime_get() - })); + ZMK_EVENT_RAISE(new_zmk_position_state_changed( + (struct zmk_position_state_changed){.source = UINT8_MAX, + .state = pressed, + .position = position, + .timestamp = k_uptime_get()})); } } diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index c28941f1..0d52d051 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -29,17 +29,112 @@ static int start_scan(void); #define POSITION_STATE_DATA_LEN 16 -static struct bt_conn *default_conn; +enum peripheral_slot_state { + PERIPHERAL_SLOT_STATE_OPEN, + PERIPHERAL_SLOT_STATE_CONNECTING, + PERIPHERAL_SLOT_STATE_CONNECTED, +}; + +struct peripheral_slot { + enum peripheral_slot_state state; + struct bt_conn *conn; + struct bt_gatt_discover_params discover_params; + struct bt_gatt_subscribe_params subscribe_params; + struct bt_gatt_discover_params sub_discover_params; + uint16_t run_behavior_handle; + uint8_t position_state[POSITION_STATE_DATA_LEN]; + uint8_t changed_positions[POSITION_STATE_DATA_LEN]; +}; + +static struct peripheral_slot peripherals[ZMK_BLE_SPLIT_PERIPHERAL_COUNT]; static const struct bt_uuid_128 split_service_uuid = BT_UUID_INIT_128(ZMK_SPLIT_BT_SERVICE_UUID); -static struct bt_gatt_discover_params discover_params; -static struct bt_gatt_subscribe_params subscribe_params; -static struct bt_gatt_discover_params sub_discover_params; -static uint16_t run_behavior_handle; K_MSGQ_DEFINE(peripheral_event_msgq, sizeof(struct zmk_position_state_changed), CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4); +int peripheral_slot_index_for_conn(struct bt_conn *conn) { + for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) { + if (peripherals[i].conn == conn) { + return i; + } + } + + return -EINVAL; +} + +struct peripheral_slot *peripheral_slot_for_conn(struct bt_conn *conn) { + int idx = peripheral_slot_index_for_conn(conn); + if (idx < 0) { + return NULL; + } + + return &peripherals[idx]; +} + +int release_peripheral_slot(int index) { + if (index < 0 || index >= ZMK_BLE_SPLIT_PERIPHERAL_COUNT) { + return -EINVAL; + } + + struct peripheral_slot *slot = &peripherals[index]; + + if (slot->state == PERIPHERAL_SLOT_STATE_OPEN) { + return -EINVAL; + } + + LOG_DBG("Releasing peripheral slot at %d", index); + + if (slot->conn != NULL) { + bt_conn_unref(slot->conn); + slot->conn = NULL; + } + slot->state = PERIPHERAL_SLOT_STATE_OPEN; + + for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { + slot->position_state[i] = 0U; + slot->changed_positions[i] = 0U; + } + + // Clean up previously discovered handles; + slot->subscribe_params.value_handle = 0; + slot->run_behavior_handle = 0; + + return 0; +} + +int reserve_peripheral_slot() { + for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) { + if (peripherals[i].state == PERIPHERAL_SLOT_STATE_OPEN) { + // Be sure the slot is fully reinitialized. + release_peripheral_slot(i); + peripherals[i].state = PERIPHERAL_SLOT_STATE_CONNECTING; + return i; + } + } + + return -ENOMEM; +} + +int release_peripheral_slot_for_conn(struct bt_conn *conn) { + int idx = peripheral_slot_index_for_conn(conn); + if (idx < 0) { + return idx; + } + + return release_peripheral_slot(idx); +} + +int confirm_peripheral_slot_conn(struct bt_conn *conn) { + int idx = peripheral_slot_index_for_conn(conn); + if (idx < 0) { + return idx; + } + + peripherals[idx].state = PERIPHERAL_SLOT_STATE_CONNECTED; + return 0; +} + void peripheral_event_work_callback(struct k_work *work) { struct zmk_position_state_changed ev; while (k_msgq_get(&peripheral_event_msgq, &ev, K_NO_WAIT) == 0) { @@ -53,9 +148,12 @@ K_WORK_DEFINE(peripheral_event_work, peripheral_event_work_callback); static uint8_t split_central_notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) { - static uint8_t position_state[POSITION_STATE_DATA_LEN]; + struct peripheral_slot *slot = peripheral_slot_for_conn(conn); - uint8_t changed_positions[POSITION_STATE_DATA_LEN]; + if (slot == NULL) { + LOG_ERR("No peripheral state found for connection"); + return BT_GATT_ITER_CONTINUE; + } if (!data) { LOG_DBG("[UNSUBSCRIBED]"); @@ -66,16 +164,18 @@ static uint8_t split_central_notify_func(struct bt_conn *conn, LOG_DBG("[NOTIFICATION] data %p length %u", data, length); for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { - changed_positions[i] = ((uint8_t *)data)[i] ^ position_state[i]; - position_state[i] = ((uint8_t *)data)[i]; + slot->changed_positions[i] = ((uint8_t *)data)[i] ^ slot->position_state[i]; + slot->position_state[i] = ((uint8_t *)data)[i]; + LOG_DBG("data: %d", slot->position_state[i]); } for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { for (int j = 0; j < 8; j++) { - if (changed_positions[i] & BIT(j)) { + if (slot->changed_positions[i] & BIT(j)) { uint32_t position = (i * 8) + j; - bool pressed = position_state[i] & BIT(j); - struct zmk_position_state_changed ev = {.source = bt_conn_get_dst(conn), + bool pressed = slot->position_state[i] & BIT(j); + struct zmk_position_state_changed ev = {.source = + peripheral_slot_index_for_conn(conn), .position = position, .state = pressed, .timestamp = k_uptime_get()}; @@ -90,7 +190,13 @@ static uint8_t split_central_notify_func(struct bt_conn *conn, } static void split_central_subscribe(struct bt_conn *conn) { - int err = bt_gatt_subscribe(conn, &subscribe_params); + struct peripheral_slot *slot = peripheral_slot_for_conn(conn); + if (slot == NULL) { + LOG_ERR("No peripheral state found for connection"); + return; + } + + int err = bt_gatt_subscribe(conn, &slot->subscribe_params); switch (err) { case -EALREADY: LOG_DBG("[ALREADY SUBSCRIBED]"); @@ -117,28 +223,34 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, return BT_GATT_ITER_STOP; } + struct peripheral_slot *slot = peripheral_slot_for_conn(conn); + if (slot == NULL) { + LOG_ERR("No peripheral state found for connection"); + return BT_GATT_ITER_STOP; + } + LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID))) { LOG_DBG("Found position state characteristic"); - discover_params.uuid = NULL; - discover_params.start_handle = attr->handle + 2; - discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + slot->discover_params.uuid = NULL; + slot->discover_params.start_handle = attr->handle + 2; + slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; - subscribe_params.disc_params = &sub_discover_params; - subscribe_params.end_handle = discover_params.end_handle; - subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); - subscribe_params.notify = split_central_notify_func; - subscribe_params.value = BT_GATT_CCC_NOTIFY; + slot->subscribe_params.disc_params = &slot->sub_discover_params; + slot->subscribe_params.end_handle = slot->discover_params.end_handle; + slot->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + slot->subscribe_params.notify = split_central_notify_func; + slot->subscribe_params.value = BT_GATT_CCC_NOTIFY; split_central_subscribe(conn); } else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID))) { LOG_DBG("Found run behavior handle"); - run_behavior_handle = bt_gatt_attr_value_handle(attr); + slot->run_behavior_handle = bt_gatt_attr_value_handle(attr); } - bool subscribed = (run_behavior_handle && subscribe_params.value_handle); + bool subscribed = (slot->run_behavior_handle && slot->subscribe_params.value_handle); return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE; } @@ -154,18 +266,24 @@ static uint8_t split_central_service_discovery_func(struct bt_conn *conn, LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); - if (bt_uuid_cmp(discover_params.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) { + struct peripheral_slot *slot = peripheral_slot_for_conn(conn); + if (slot == NULL) { + LOG_ERR("No peripheral state found for connection"); + return BT_GATT_ITER_STOP; + } + + if (bt_uuid_cmp(slot->discover_params.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) { LOG_DBG("Found other service"); return BT_GATT_ITER_CONTINUE; } LOG_DBG("Found split service"); - discover_params.uuid = NULL; - discover_params.func = split_central_chrc_discovery_func; - discover_params.start_handle = attr->handle + 1; - discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + slot->discover_params.uuid = NULL; + slot->discover_params.func = split_central_chrc_discovery_func; + slot->discover_params.start_handle = attr->handle + 1; + slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; - int err = bt_gatt_discover(conn, &discover_params); + int err = bt_gatt_discover(conn, &slot->discover_params); if (err) { LOG_ERR("Failed to start discovering split service characteristics (err %d)", err); } @@ -183,14 +301,20 @@ static void split_central_process_connection(struct bt_conn *conn) { return; } - if (conn == default_conn && !subscribe_params.value_handle) { - discover_params.uuid = &split_service_uuid.uuid; - discover_params.func = split_central_service_discovery_func; - discover_params.start_handle = 0x0001; - discover_params.end_handle = 0xffff; - discover_params.type = BT_GATT_DISCOVER_PRIMARY; + struct peripheral_slot *slot = peripheral_slot_for_conn(conn); + if (slot == NULL) { + LOG_ERR("No peripheral state found for connection"); + return; + } - err = bt_gatt_discover(default_conn, &discover_params); + if (!slot->subscribe_params.value_handle) { + slot->discover_params.uuid = &split_service_uuid.uuid; + slot->discover_params.func = split_central_service_discovery_func; + slot->discover_params.start_handle = 0x0001; + slot->discover_params.end_handle = 0xffff; + slot->discover_params.type = BT_GATT_DISCOVER_PRIMARY; + + err = bt_gatt_discover(slot->conn, &slot->discover_params); if (err) { LOG_ERR("Discover failed(err %d)", err); return; @@ -251,21 +375,33 @@ static bool split_central_eir_found(struct bt_data *data, void *user_data) { continue; } - default_conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); - if (default_conn) { + uint8_t slot_idx = reserve_peripheral_slot(); + if (slot_idx < 0) { + LOG_ERR("Faild to reserve peripheral slot (err %d)", slot_idx); + continue; + } + + struct peripheral_slot *slot = &peripherals[slot_idx]; + + slot->conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); + if (slot->conn) { LOG_DBG("Found existing connection"); - split_central_process_connection(default_conn); + split_central_process_connection(slot->conn); + err = bt_conn_le_phy_update(slot->conn, BT_CONN_LE_PHY_PARAM_2M); + if (err) { + LOG_ERR("Update phy conn failed (err %d)", err); + } } else { param = BT_LE_CONN_PARAM(0x0006, 0x0006, 30, 400); - err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn); + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &slot->conn); if (err) { LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err, BT_HCI_OP_LE_CREATE_CONN); start_scan(); } - err = bt_conn_le_phy_update(default_conn, BT_CONN_LE_PHY_PARAM_2M); + err = bt_conn_le_phy_update(slot->conn, BT_CONN_LE_PHY_PARAM_2M); if (err) { LOG_ERR("Update phy conn failed (err %d)", err); start_scan(); @@ -314,8 +450,7 @@ static void split_central_connected(struct bt_conn *conn, uint8_t conn_err) { if (conn_err) { LOG_ERR("Failed to connect to %s (%u)", log_strdup(addr), conn_err); - bt_conn_unref(default_conn); - default_conn = NULL; + release_peripheral_slot_for_conn(conn); start_scan(); return; @@ -323,6 +458,7 @@ static void split_central_connected(struct bt_conn *conn, uint8_t conn_err) { LOG_DBG("Connected: %s", log_strdup(addr)); + confirm_peripheral_slot_conn(conn); split_central_process_connection(conn); } @@ -333,16 +469,7 @@ static void split_central_disconnected(struct bt_conn *conn, uint8_t reason) { LOG_DBG("Disconnected: %s (reason %d)", log_strdup(addr), reason); - if (default_conn != conn) { - return; - } - - bt_conn_unref(default_conn); - default_conn = NULL; - - // Clean up previously discovered handles; - subscribe_params.value_handle = 0; - run_behavior_handle = 0; + release_peripheral_slot_for_conn(conn); start_scan(); } @@ -357,16 +484,30 @@ K_THREAD_STACK_DEFINE(split_central_split_run_q_stack, struct k_work_q split_central_split_run_q; -K_MSGQ_DEFINE(zmk_split_central_split_run_msgq, sizeof(struct zmk_split_run_behavior_payload), +struct zmk_split_run_behavior_payload_wrapper { + uint8_t source; + struct zmk_split_run_behavior_payload payload; +}; + +K_MSGQ_DEFINE(zmk_split_central_split_run_msgq, + sizeof(struct zmk_split_run_behavior_payload_wrapper), CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE, 4); void split_central_split_run_callback(struct k_work *work) { - struct zmk_split_run_behavior_payload payload; + struct zmk_split_run_behavior_payload_wrapper payload_wrapper; - while (k_msgq_get(&zmk_split_central_split_run_msgq, &payload, K_NO_WAIT) == 0) { - int err = - bt_gatt_write_without_response(default_conn, run_behavior_handle, &payload, - sizeof(struct zmk_split_run_behavior_payload), true); + LOG_DBG(""); + + while (k_msgq_get(&zmk_split_central_split_run_msgq, &payload_wrapper, K_NO_WAIT) == 0) { + if (peripherals[payload_wrapper.source].state != PERIPHERAL_SLOT_STATE_CONNECTED) { + LOG_ERR("Source not connected"); + continue; + } + + int err = bt_gatt_write_without_response( + peripherals[payload_wrapper.source].conn, + peripherals[payload_wrapper.source].run_behavior_handle, &payload_wrapper.payload, + sizeof(struct zmk_split_run_behavior_payload), true); if (err) { LOG_ERR("Failed to write the behavior characteristic (err %d)", err); @@ -376,15 +517,18 @@ void split_central_split_run_callback(struct k_work *work) { K_WORK_DEFINE(split_central_split_run_work, split_central_split_run_callback); -static int split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payload payload) { - int err = k_msgq_put(&zmk_split_central_split_run_msgq, &payload, K_MSEC(100)); +static int +split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payload_wrapper payload_wrapper) { + LOG_DBG(""); + + int err = k_msgq_put(&zmk_split_central_split_run_msgq, &payload_wrapper, K_MSEC(100)); if (err) { switch (err) { case -EAGAIN: { LOG_WRN("Consumer message queue full, popping first message and queueing again"); - struct zmk_split_run_behavior_payload discarded_report; + struct zmk_split_run_behavior_payload_wrapper discarded_report; k_msgq_get(&zmk_split_central_split_run_msgq, &discarded_report, K_NO_WAIT); - return split_bt_invoke_behavior_payload(payload); + return split_bt_invoke_behavior_payload(payload_wrapper); } default: LOG_WRN("Failed to queue behavior to send (%d)", err); @@ -397,18 +541,19 @@ static int split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payloa return 0; }; -int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding, +int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, bool state) { struct zmk_split_run_behavior_payload payload = {.data = { .param1 = binding->param1, .param2 = binding->param2, .position = event.position, - .state = state, + .state = state ? 1 : 0, }}; strncpy(payload.behavior_dev, binding->behavior_dev, ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1); payload.behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1] = '\0'; - return split_bt_invoke_behavior_payload(payload); + struct zmk_split_run_behavior_payload_wrapper wrapper = {.source = source, .payload = payload}; + return split_bt_invoke_behavior_payload(wrapper); } int zmk_split_bt_central_init(const struct device *_arg) { From 4d55e60adb963b99c3be6e97c56f5c258d3c8bc5 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sun, 2 Jan 2022 04:57:37 +0000 Subject: [PATCH 14/48] refactor(behaviors): Always add reset behaviors. * Don'd omit unreferenced reset behaviors, so they are always available in split peripherals. --- app/dts/behaviors/reset.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/dts/behaviors/reset.dtsi b/app/dts/behaviors/reset.dtsi index e4ba5658..cb246814 100644 --- a/app/dts/behaviors/reset.dtsi +++ b/app/dts/behaviors/reset.dtsi @@ -8,13 +8,13 @@ / { behaviors { - /omit-if-no-ref/ reset: behavior_reset { + reset: behavior_reset { compatible = "zmk,behavior-reset"; label = "RESET"; #binding-cells = <0>; }; - /omit-if-no-ref/ bootloader: behavior_reset_dfu { + bootloader: behavior_reset_dfu { compatible = "zmk,behavior-reset"; label = "BOOTLOAD"; type = ; From fa110488b0c9e5c79066d51e0b6214447e223257 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sun, 30 Jan 2022 03:38:10 +0000 Subject: [PATCH 15/48] fix(split): Add define for local source. * Add `ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL` and use it consinstently to fix bug w/ local `&reset`, `&bootloader`, etc. --- app/include/zmk/events/position_state_changed.h | 2 ++ app/src/keymap.c | 2 +- app/src/kscan.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/include/zmk/events/position_state_changed.h b/app/include/zmk/events/position_state_changed.h index 7685fe0f..5323e943 100644 --- a/app/include/zmk/events/position_state_changed.h +++ b/app/include/zmk/events/position_state_changed.h @@ -9,6 +9,8 @@ #include #include +#define ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL UINT8_MAX + struct zmk_position_state_changed { uint8_t source; uint32_t position; diff --git a/app/src/keymap.c b/app/src/keymap.c index 8acc5ec1..e586316f 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -207,7 +207,7 @@ int zmk_keymap_apply_position_state(uint8_t source, int layer, uint32_t position return invoke_locally(&binding, event, pressed); case BEHAVIOR_LOCALITY_EVENT_SOURCE: #if ZMK_BLE_IS_CENTRAL - if (source == UINT_MAX) { + if (source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) { return invoke_locally(&binding, event, pressed); } else { return zmk_split_bt_invoke_behavior(source, &binding, event, pressed); diff --git a/app/src/kscan.c b/app/src/kscan.c index 3425fabe..c7cf2881 100644 --- a/app/src/kscan.c +++ b/app/src/kscan.c @@ -51,7 +51,7 @@ void zmk_kscan_process_msgq(struct k_work *item) { LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s", ev.row, ev.column, position, (pressed ? "true" : "false")); ZMK_EVENT_RAISE(new_zmk_position_state_changed( - (struct zmk_position_state_changed){.source = UINT8_MAX, + (struct zmk_position_state_changed){.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL, .state = pressed, .position = position, .timestamp = k_uptime_get()})); From dbefe92ea099a043619727a9ec33cc65de8e6a0c Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sun, 30 Jan 2022 04:50:10 +0000 Subject: [PATCH 16/48] fix(split): Slightly improved logging on peripherals. --- app/src/split/bluetooth/service.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index bb0202c3..3b860197 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -58,8 +58,8 @@ static ssize_t split_svc_run_behavior(struct bt_conn *conn, const struct bt_gatt .param2 = payload->data.param2, .behavior_dev = payload->behavior_dev, }; - LOG_DBG("INVOKE THE BEHAVIOR: %s with params %d %d", log_strdup(binding.behavior_dev), - binding.param1, binding.param2); + LOG_DBG("%s with params %d %d: pressed? %d", log_strdup(binding.behavior_dev), + binding.param1, binding.param2, payload->data.state); struct zmk_behavior_binding_event event = {.position = payload->data.position, .timestamp = k_uptime_get()}; int err; From b8700eaaa1e24837d6b9ff60430d706c555f9a2f Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sun, 30 Jan 2022 05:32:12 +0000 Subject: [PATCH 17/48] fix(split): Fix an off-by-one error in split svc. * Properly check end of behavior device string for null terminator. --- app/src/split/bluetooth/service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index 3b860197..ca192d7d 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -52,7 +52,7 @@ static ssize_t split_svc_run_behavior(struct bt_conn *conn, const struct bt_gatt // 1: We've gotten all the position/state/param data. // 2: We have a null terminated string for the behavior device label. if ((end_addr > sizeof(struct zmk_split_run_behavior_data)) && - payload->behavior_dev[end_addr - sizeof(struct zmk_split_run_behavior_data)] == '\0') { + payload->behavior_dev[end_addr - sizeof(struct zmk_split_run_behavior_data) - 1] == '\0') { struct zmk_behavior_binding binding = { .param1 = payload->data.param1, .param2 = payload->data.param2, From 74307504280573aae5819afad29aceaf97b8344e Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Tue, 1 Feb 2022 03:29:50 +0000 Subject: [PATCH 18/48] refactor(splits): Minor cleanups to periph invocation * Add strlcpy from public domain version. * Leverage strlcpy to detect truncation of behavior dev strs, and log. * Use `offsetof` for cleaner detection on peripheral side. --- app/CMakeLists.txt | 1 + app/include/zmk/stdlib.h | 19 +++++++++++++++++++ app/src/split/bluetooth/central.c | 9 +++++++-- app/src/split/bluetooth/service.c | 4 +++- app/src/stdlib.c | 25 +++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 app/include/zmk/stdlib.h create mode 100644 app/src/stdlib.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 1e153fb6..7681efab 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -23,6 +23,7 @@ zephyr_linker_sources(RODATA include/linker/zmk-events.ld) # find_package(Zephyr) which defines the target. target_include_directories(app PRIVATE include) target_sources_ifdef(CONFIG_ZMK_SLEEP app PRIVATE src/power.c) +target_sources(app PRIVATE src/stdlib.c) target_sources(app PRIVATE src/activity.c) target_sources(app PRIVATE src/kscan.c) target_sources(app PRIVATE src/matrix_transform.c) diff --git a/app/include/zmk/stdlib.h b/app/include/zmk/stdlib.h new file mode 100644 index 00000000..fa8fe673 --- /dev/null +++ b/app/include/zmk/stdlib.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include /* for size_t */ + +/* + * ANSI C version of strlcpy + * Based on the NetBSD strlcpy man page. + * + * Nathan Myers , 2003/06/03 + * Placed in the public domain. + */ + +size_t strlcpy(char *dst, const char *src, size_t size); \ No newline at end of file diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 0d52d051..8a0e79ea 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -17,6 +17,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#include #include #include #include @@ -549,8 +550,12 @@ int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *bi .position = event.position, .state = state ? 1 : 0, }}; - strncpy(payload.behavior_dev, binding->behavior_dev, ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1); - payload.behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1] = '\0'; + const size_t payload_dev_size = sizeof(payload.behavior_dev); + if (strlcpy(payload.behavior_dev, binding->behavior_dev, payload_dev_size) >= + payload_dev_size) { + LOG_ERR("Truncated behavior label %s to %s before invoking peripheral behavior", + log_strdup(binding->behavior_dev), log_strdup(payload.behavior_dev)); + } struct zmk_split_run_behavior_payload_wrapper wrapper = {.source = source, .payload = payload}; return split_bt_invoke_behavior_payload(wrapper); diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index ca192d7d..7de78506 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -51,8 +51,10 @@ static ssize_t split_svc_run_behavior(struct bt_conn *conn, const struct bt_gatt // We run if: // 1: We've gotten all the position/state/param data. // 2: We have a null terminated string for the behavior device label. + const size_t behavior_dev_offset = + offsetof(struct zmk_split_run_behavior_payload, behavior_dev); if ((end_addr > sizeof(struct zmk_split_run_behavior_data)) && - payload->behavior_dev[end_addr - sizeof(struct zmk_split_run_behavior_data) - 1] == '\0') { + payload->behavior_dev[end_addr - behavior_dev_offset - 1] == '\0') { struct zmk_behavior_binding binding = { .param1 = payload->data.param1, .param2 = payload->data.param2, diff --git a/app/src/stdlib.c b/app/src/stdlib.c new file mode 100644 index 00000000..5bca1696 --- /dev/null +++ b/app/src/stdlib.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/* + * ANSI C version of strlcpy + * Based on the NetBSD strlcpy man page. + * + * Nathan Myers , 2003/06/03 + * Placed in the public domain. + */ + +size_t strlcpy(char *dst, const char *src, size_t size) { + const size_t len = strlen(src); + if (size != 0) { + memcpy(dst, src, (len > size - 1) ? size - 1 : len); + dst[size - 1] = 0; + } + return len; +} From edbbbc75409c06f7828b8fd70323a2a3350980e6 Mon Sep 17 00:00:00 2001 From: Nick Winans Date: Wed, 2 Feb 2022 23:15:50 -0600 Subject: [PATCH 19/48] feat(ci): Use metadata for builds * Build per board * Nightly builds of all boards * Detect board changes and build those changed * Core set of boards/shields built otherwise. --- .github/workflows/build.yml | 447 +++++++++++++++++++++++++++++------- app/core-coverage.yml | 30 +++ 2 files changed, 391 insertions(+), 86 deletions(-) create mode 100644 app/core-coverage.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b790b665..bfb195fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,75 +9,19 @@ on: paths: - ".github/workflows/build.yml" - "app/**" + schedule: + - cron: '22 4 * * *' jobs: build: + if: ${{ always() }} runs-on: ubuntu-latest container: image: docker.io/zmkfirmware/zmk-build-arm:2.5 + needs: compile-matrix strategy: matrix: - board: - - bluemicro840_v1 - - nice_nano - - nice_nano_v2 - - nrfmicro_13 - - proton_c - shield: - - bfo9000_left - - bfo9000_right - - boardsource3x4 - - corne_left - - corne_right - - cradio_left - - cradio_right - - crbn - - eek - - helix_left - - helix_right - - iris_left - - iris_right - - jian_left - - jian_right - - jorne_left - - jorne_right - - kyria_left - - kyria_right - - lily58_left - - lily58_right - - microdox_left - - microdox_right - - nibble - - qaz - - quefrency_left - - quefrency_right - - reviung41 - - romac - - romac_plus - - settings_reset - - sofle_left - - sofle_right - - splitreus62_left - - splitreus62_right - - tg4x - - tidbit - cmake-args: [""] - include: - - board: bdn9_rev2 - - board: dz60rgb_rev1 - - board: nrf52840_m2 - shield: m60 - - board: planck_rev6 - - board: proton_c - shield: clueboard_california - - board: nice_nano_v2 - shield: kyria_left - cmake-args: -DCONFIG_ZMK_DISPLAY=y - skip-archive: true - - board: nice_nano_v2 - shield: kyria_right - cmake-args: -DCONFIG_ZMK_DISPLAY=y - skip-archive: true + include: ${{ fromJSON(needs.compile-matrix.outputs.include-list) }} steps: - name: Checkout uses: actions/checkout@v2 @@ -104,29 +48,360 @@ jobs: run: west update - name: Export Zephyr CMake package (west zephyr-export) run: west zephyr-export - - name: Prepare variables - id: variables - run: | - SHIELD_ARG= - ARTIFACT_NAME="${{ matrix.board }}" - - if [ -n "${{ matrix.shield }}" ]; then - SHIELD_ARG="-DSHIELD=${{ matrix.shield }}" - ARTIFACT_NAME="${ARTIFACT_NAME}-${{ matrix.shield }}" - fi - - ARTIFACT_NAME="${ARTIFACT_NAME}-zmk" - - echo ::set-output name=shield-arg::${SHIELD_ARG} - echo ::set-output name=artifact-name::${ARTIFACT_NAME} - - name: Build (west build) - run: west build -s app -b ${{ matrix.board }} -- ${{ steps.variables.outputs.shield-arg }} ${{ matrix.cmake-args }} - - name: Archive artifacts - if: ${{ !matrix.skip-archive }} - uses: actions/upload-artifact@v2 + - name: Use Node.js + uses: actions/setup-node@v2 with: - name: "${{ steps.variables.outputs.artifact-name }}" - path: | - build/zephyr/zmk.hex - build/zephyr/zmk.uf2 - continue-on-error: true + node-version: '14.x' + - name: Install @actions/artifact + run: npm install @actions/artifact + - name: Build and upload artifacts + uses: actions/github-script@v4 + id: boards-list + with: + script: | + const fs = require('fs'); + const artifact = require('@actions/artifact'); + const artifactClient = artifact.create(); + + const execSync = require('child_process').execSync; + + const buildShieldArgs = JSON.parse(`${{ matrix.shieldArgs }}`); + + let error = false; + + for (const shieldArgs of buildShieldArgs) { + try { + const output = execSync(`west build -s app -p -b ${{ matrix.board }} -- ${shieldArgs.shield ? '-DSHIELD=' + shieldArgs.shield : ''} ${shieldArgs['cmake-args'] || ''}`); + + console.log(`::group::${{ matrix.board}} ${shieldArgs.shield} Build`) + console.log(output.toString()); + + const fileExtensions = ["hex", "uf2"]; + + const files = fileExtensions + .map(extension => "build/zephyr/zmk." + extension) + .filter(path => fs.existsSync(path)); + + const rootDirectory = 'build/zephyr'; + const options = { + continueOnError: true + } + + const cmakeName = shieldArgs['cmake-args'] ? '-' + (shieldArgs.nickname || shieldArgs['cmake-args'].split(' ').join('')) : ''; + const artifactName = `${{ matrix.board }}${shieldArgs.shield ? '-' + shieldArgs.shield : ''}${cmakeName}-zmk`; + + await artifactClient.uploadArtifact(artifactName, files, rootDirectory, options); + } catch (e) { + console.error(`::error::Failed to build or upload ${{ matrix.board }} ${shieldArgs.shield} ${shieldArgs['cmake-args']}`); + console.error(e); + error = true; + } finally { + console.log('::endgroup::'); + } + } + + if (error) { + throw new Error('Failed to build one or more configurations'); + } + compile-matrix: + if: ${{ always() }} + runs-on: ubuntu-latest + needs: [core-coverage, board-changes, nightly] + outputs: + include-list: ${{ steps.compile-list.outputs.result }} + steps: + - name: Join build lists + uses: actions/github-script@v4 + id: compile-list + with: + script: | + const coreCoverage = `${{ needs.core-coverage.outputs.core-include }}` || "[]"; + const boardChanges = `${{ needs.board-changes.outputs.boards-include }}` || "[]"; + const nightly = `${{ needs.nightly.outputs.nightly-include }}` || "[]"; + + const combined = [ + ...JSON.parse(coreCoverage), + ...JSON.parse(boardChanges), + ...JSON.parse(nightly) + ]; + const combinedUnique = [...new Map(combined.map(el => [JSON.stringify(el), el])).values()]; + + const perBoard = {}; + + for (const configuration of combinedUnique) { + if (!perBoard[configuration.board]) + perBoard[configuration.board] = []; + + perBoard[configuration.board].push({ + shield: configuration.shield, + 'cmake-args': configuration['cmake-args'], + nickname: configuration.nickname + }) + } + + return Object.entries(perBoard).map(([board, shieldArgs]) => ({ + board, + shieldArgs: JSON.stringify(shieldArgs), + })); + core-coverage: + if: ${{ needs.get-changed-files.outputs.core-changes == 'true' }} + runs-on: ubuntu-latest + needs: get-changed-files + outputs: + core-include: ${{ steps.core-list.outputs.result }} + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: '14.x' + - name: Install js-yaml + run: npm install js-yaml + - uses: actions/github-script@v4 + id: core-list + with: + script: | + const fs = require('fs'); + const yaml = require('js-yaml'); + + const coreCoverage = yaml.load(fs.readFileSync('app/core-coverage.yml', 'utf8')); + + let include = coreCoverage.board.flatMap(board => + coreCoverage.shield.map(shield => ({ board, shield })) + ); + + return [...include, ...coreCoverage.include]; + board-changes: + if: ${{ needs.get-changed-files.outputs.board-changes == 'true' }} + runs-on: ubuntu-latest + needs: [get-grouped-hardware, get-changed-files] + outputs: + boards-include: ${{ steps.boards-list.outputs.result }} + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: '14.x' + - name: Install js-yaml + run: npm install js-yaml + - uses: actions/github-script@v4 + id: boards-list + with: + script: | + const fs = require('fs'); + const yaml = require('js-yaml'); + + const changedFiles = JSON.parse(`${{ needs.get-changed-files.outputs.changed-files }}`); + const metadata = JSON.parse(`${{ needs.get-grouped-hardware.outputs.organized-metadata }}`); + const boardChanges = new Set(changedFiles.filter(f => f.startsWith('app/boards')).map(f => f.split('/').slice(0, 4).join('/'))); + + return (await Promise.all([...boardChanges].flatMap(async bc => { + const globber = await glob.create(bc + "/*.zmk.yml"); + const files = await globber.glob(); + + const aggregated = files.flatMap((f) => + yaml.loadAll(fs.readFileSync(f, "utf8")) + ); + + const boardAndShield = (b, s) => { + if (s.siblings) { + return s.siblings.map(shield => ({ + board: b.id, + shield, + })); + } else { + return { + board: b.id, + shield: s.id + }; + } + } + + return aggregated.flatMap(hm => { + switch (hm.type) { + case "board": + if (hm.features && hm.features.includes("keys")) { + if (hm.siblings) { + return hm.siblings.map(board => ({ + board, + })); + } else { + return { + board: hm.id + }; + } + } else if (hm.exposes) { + return hm.exposes.flatMap(i => + metadata.interconnects[i].shields.flatMap(s => boardAndShield(hm, s)) + ); + } else { + console.error("Board without keys or interconnect"); + } + break; + case "shield": + if (hm.features && hm.features.includes("keys")) { + return hm.requires.flatMap(i => + metadata.interconnects[i].boards.flatMap(b => boardAndShield(b, hm)) + ); + } + break; + case "interconnect": + break; + } + }); + }))).flat(); + nightly: + if: ${{ github.event_name == 'schedule' }} + runs-on: ubuntu-latest + needs: get-grouped-hardware + outputs: + nightly-include: ${{ steps.nightly-list.outputs.result }} + steps: + - name: Create nightly list + uses: actions/github-script@v4 + id: nightly-list + with: + script: | + const metadata = JSON.parse(`${{ needs.get-grouped-hardware.outputs.organized-metadata }}`); + + let includeOnboard = metadata.onboard.flatMap(b => { + if (b.siblings) { + return b.siblings.map(board => ({ + board, + })); + } else { + return { + board: b.id, + }; + } + }); + + let includeInterconnect = Object.values(metadata.interconnects).flatMap(i => + i.boards.flatMap(b => + i.shields.flatMap(s => { + if (s.siblings) { + return s.siblings.map(shield => ({ + board: b.id, + shield, + })); + } else { + return { + board: b.id, + shield: s.id, + }; + } + }) + ) + ); + + return [...includeOnboard, ...includeInterconnect]; + get-grouped-hardware: + runs-on: ubuntu-latest + outputs: + organized-metadata: ${{ steps.organize-metadata.outputs.result }} + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: '14.x' + - name: Install js-yaml + run: npm install js-yaml + - name: Aggregate Metadata + uses: actions/github-script@v4 + id: aggregate-metadata + with: + script: | + const fs = require('fs'); + const yaml = require('js-yaml'); + + const globber = await glob.create("app/boards/**/*.zmk.yml"); + const files = await globber.glob(); + + const aggregated = files.flatMap((f) => + yaml.loadAll(fs.readFileSync(f, "utf8")) + ); + + return JSON.stringify(aggregated).replace(/\\/g,"\\\\"); + result-encoding: string + + - name: Organize Metadata + uses: actions/github-script@v4 + id: organize-metadata + with: + script: | + const hardware = JSON.parse(`${{ steps.aggregate-metadata.outputs.result }}`); + + const grouped = hardware.reduce((agg, hm) => { + switch (hm.type) { + case "board": + if (hm.features && hm.features.includes("keys")) { + agg.onboard.push(hm); + } else if (hm.exposes) { + hm.exposes.forEach((element) => { + let ic = agg.interconnects[element] || { + boards: [], + shields: [], + }; + ic.boards.push(hm); + agg.interconnects[element] = ic; + }); + } else { + console.error("Board without keys or interconnect"); + } + break; + case "shield": + if (hm.features && hm.features.includes("keys")) { + hm.requires.forEach((id) => { + let ic = agg.interconnects[id] || { boards: [], shields: [] }; + ic.shields.push(hm); + agg.interconnects[id] = ic; + }); + } + break; + case "interconnect": + let ic = agg.interconnects[hm.id] || { boards: [], shields: [] }; + ic.interconnect = hm; + agg.interconnects[hm.id] = ic; + break; + } + return agg; + }, + { onboard: [], interconnects: {} }); + + return JSON.stringify(grouped).replace(/\\/g,"\\\\"); + result-encoding: string + get-changed-files: + if: ${{ github.event_name != 'schedule' }} + runs-on: ubuntu-latest + outputs: + changed-files: ${{ steps.changed-files.outputs.all }} + board-changes: ${{ steps.board-changes.outputs.result }} + core-changes: ${{ steps.core-changes.outputs.result }} + steps: + - uses: Ana06/get-changed-files@v2.0.0 + id: changed-files + with: + format: 'json' + - uses: actions/github-script@v4 + id: board-changes + with: + script: | + const changedFiles = JSON.parse(`${{ steps.changed-files.outputs.all }}`); + const boardChanges = changedFiles.filter(f => f.startsWith('app/boards')); + return boardChanges.length ? 'true' : 'false'; + result-encoding: string + - uses: actions/github-script@v4 + id: core-changes + with: + script: | + const changedFiles = JSON.parse(`${{ steps.changed-files.outputs.all }}`); + const boardChanges = changedFiles.filter(f => f.startsWith('app/boards')); + const appChanges = changedFiles.filter(f => f.startsWith('app')); + const ymlChanges = changedFiles.includes('.github/workflows/build.yml'); + return boardChanges.length < appChanges.length || ymlChanges ? 'true' : 'false'; + result-encoding: string diff --git a/app/core-coverage.yml b/app/core-coverage.yml new file mode 100644 index 00000000..6784287b --- /dev/null +++ b/app/core-coverage.yml @@ -0,0 +1,30 @@ +board: +- nice_nano_v2 +- nrfmicro_13 +- proton_c +shield: +- corne_left +- corne_right +- romac +- settings_reset +- tidbit +include: +- board: bdn9_rev2 +- board: nice60 +- board: nrf52840_m2 + shield: m60 +- board: planck_rev6 +- board: proton_c + shield: clueboard_california +- board: nice_nano_v2 + shield: kyria_left + cmake-args: "-DCONFIG_ZMK_DISPLAY=y" + nickname: "display" +- board: nice_nano_v2 + shield: kyria_right + cmake-args: "-DCONFIG_ZMK_DISPLAY=y" + nickname: "display" +- board: nice_nano + shield: romac_plus + cmake-args: "-DCONFIG_ZMK_RGB_UNDERGLOW=y -DCONFIG_WS2812_STRIP=y" + nickname: "underglow" From 4a1254bc27f23bc5025fb44970796eb425cd8469 Mon Sep 17 00:00:00 2001 From: Lucas Uyezu Date: Tue, 19 Oct 2021 23:39:04 -0400 Subject: [PATCH 20/48] Add support for Knob Goblin shield --- .../shields/knob_goblin/Kconfig.defconfig | 45 +++++++++++ app/boards/shields/knob_goblin/Kconfig.shield | 5 ++ .../shields/knob_goblin/knob_goblin.conf | 9 +++ .../shields/knob_goblin/knob_goblin.keymap | 40 ++++++++++ .../shields/knob_goblin/knob_goblin.overlay | 79 +++++++++++++++++++ .../shields/knob_goblin/knob_goblin.zmk.yml | 11 +++ 6 files changed, 189 insertions(+) create mode 100644 app/boards/shields/knob_goblin/Kconfig.defconfig create mode 100644 app/boards/shields/knob_goblin/Kconfig.shield create mode 100644 app/boards/shields/knob_goblin/knob_goblin.conf create mode 100644 app/boards/shields/knob_goblin/knob_goblin.keymap create mode 100644 app/boards/shields/knob_goblin/knob_goblin.overlay create mode 100644 app/boards/shields/knob_goblin/knob_goblin.zmk.yml diff --git a/app/boards/shields/knob_goblin/Kconfig.defconfig b/app/boards/shields/knob_goblin/Kconfig.defconfig new file mode 100644 index 00000000..07df5996 --- /dev/null +++ b/app/boards/shields/knob_goblin/Kconfig.defconfig @@ -0,0 +1,45 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_KNOB_GOBLIN + +config ZMK_KEYBOARD_NAME + default "Knob Goblin" + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LVGL_HOR_RES_MAX + default 128 + +config LVGL_VER_RES_MAX + default 32 + +config LVGL_VDB_SIZE + default 64 + +config LVGL_DPI + default 148 + +config LVGL_BITS_PER_PIXEL + default 1 + +choice LVGL_COLOR_DEPTH + default LVGL_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif # SHIELD_KNOB_GOBLIN diff --git a/app/boards/shields/knob_goblin/Kconfig.shield b/app/boards/shields/knob_goblin/Kconfig.shield new file mode 100644 index 00000000..5a140cb9 --- /dev/null +++ b/app/boards/shields/knob_goblin/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_KNOB_GOBLIN + def_bool $(shields_list_contains,knob_goblin) diff --git a/app/boards/shields/knob_goblin/knob_goblin.conf b/app/boards/shields/knob_goblin/knob_goblin.conf new file mode 100644 index 00000000..2eefae4d --- /dev/null +++ b/app/boards/shields/knob_goblin/knob_goblin.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment to enable Encoders +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Knob Goblin OLED Display +CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/knob_goblin/knob_goblin.keymap b/app/boards/shields/knob_goblin/knob_goblin.keymap new file mode 100644 index 00000000..8e4a7e66 --- /dev/null +++ b/app/boards/shields/knob_goblin/knob_goblin.keymap @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + + bindings = < + &trans &kp EQUAL &kp KP_SLASH &kp KP_MULTIPLY &kp KP_MINUS + &trans &kp KP_NUMBER_7 &kp KP_NUMBER_8 &kp KP_NUMBER_9 &kp KP_PLUS + &trans &kp KP_NUMBER_4 &kp KP_NUMBER_5 &kp KP_NUMBER_6 &kp KP_PLUS + &kp C_PLAY_PAUSE &kp KP_NUMBER_1 &kp KP_NUMBER_2 &kp KP_NUMBER_3 &kp KP_ENTER + &kp C_MUTE &mo 1 &kp KP_NUMBER_0 &kp KP_DOT &kp KP_ENTER + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + + num_layer { + bindings = < + &trans &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 + &trans &kp HOME &trans &kp PAGE_UP &trans + &trans &kp END &kp UP_ARROW &kp PAGE_DOWN &trans + &trans &kp LEFT_ARROW &kp DOWN_ARROW &kp RIGHT_ARROW &kp SPACE + &trans &trans &kp BACKSPACE &kp DELETE &trans + >; + + }; + }; +}; + diff --git a/app/boards/shields/knob_goblin/knob_goblin.overlay b/app/boards/shields/knob_goblin/knob_goblin.overlay new file mode 100644 index 00000000..82cc3dc3 --- /dev/null +++ b/app/boards/shields/knob_goblin/knob_goblin.overlay @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + ; + }; + + top_encoder: encoder_top { + compatible = "alps,ec11"; + label = "TOP_ENCODER"; + a-gpios = <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + resolution = <4>; + status = "okay"; + }; + + bottom_encoder: encoder_bottom { + compatible = "alps,ec11"; + label = "BOTTOM_ENCODER"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + resolution = <4>; + status = "okay"; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&top_encoder &bottom_encoder>; + }; + +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/knob_goblin/knob_goblin.zmk.yml b/app/boards/shields/knob_goblin/knob_goblin.zmk.yml new file mode 100644 index 00000000..5383d1c2 --- /dev/null +++ b/app/boards/shields/knob_goblin/knob_goblin.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: knob_goblin +name: Knob Goblin +type: shield +url: https://knob-goblin.com/ +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder From 614e0f1b2b552af4d4e9cffc91655fd3bc643817 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Jan 2022 03:46:12 +0000 Subject: [PATCH 21/48] chore(deps): bump follow-redirects from 1.14.1 to 1.14.7 in /docs Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.1 to 1.14.7. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.1...v1.14.7) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] --- docs/package-lock.json | 1842 +--------------------------------------- 1 file changed, 6 insertions(+), 1836 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 6fe700d9..756a5a16 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -618,25 +618,6 @@ "node": ">=0.8.0" } }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { "version": "7.12.3", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.3.tgz", @@ -1025,25 +1006,6 @@ "node": ">=0.8.0" } }, - "node_modules/@babel/plugin-proposal-class-static-block/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/plugin-proposal-dynamic-import": { "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", @@ -1448,25 +1410,6 @@ "node": ">=0.8.0" } }, - "node_modules/@babel/plugin-proposal-private-property-in-object/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", @@ -1563,7 +1506,6 @@ "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -5718,14 +5660,6 @@ "node": ">=10.13.0" } }, - "node_modules/@docusaurus/core/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, "node_modules/@docusaurus/core/node_modules/html-webpack-plugin": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.3.2.tgz", @@ -5861,17 +5795,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/@docusaurus/core/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@docusaurus/core/node_modules/update-notifier": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", @@ -6068,19 +5991,6 @@ "react-dom": "^16.8.4 || ^17.0.0" } }, - "node_modules/@docusaurus/plugin-content-docs/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@docusaurus/plugin-content-docs/node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -6960,17 +6870,6 @@ "node": ">=6.0.0" } }, - "node_modules/@mdx-js/mdx/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@mdx-js/mdx/node_modules/@mdx-js/util": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", @@ -7025,14 +6924,6 @@ "node": ">=0.8.0" } }, - "node_modules/@mdx-js/mdx/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, "node_modules/@mdx-js/mdx/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -7041,17 +6932,6 @@ "semver": "bin/semver" } }, - "node_modules/@mdx-js/mdx/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@mdx-js/react": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", @@ -7492,14 +7372,6 @@ "node": ">=0.8.0" } }, - "node_modules/@svgr/plugin-svgo/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, "node_modules/@svgr/plugin-svgo/node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -7533,17 +7405,6 @@ "node": ">=0.10.0" } }, - "node_modules/@svgr/plugin-svgo/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@svgr/plugin-svgo/node_modules/svgo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", @@ -8494,11 +8355,6 @@ "@babel/core": "^7.11.6" } }, - "node_modules/babel-plugin-apply-mdx-type-prop/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, "node_modules/babel-plugin-apply-mdx-type-prop/node_modules/@mdx-js/util": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", @@ -8528,11 +8384,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/babel-plugin-extract-import-names/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", @@ -8981,44 +8832,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/chalk/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9441,25 +9254,6 @@ "node": ">=0.8.0" } }, - "node_modules/coa/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/coa/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/collapse-white-space": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", @@ -9612,28 +9406,6 @@ "node": ">=8" } }, - "node_modules/configstore/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/configstore/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/connect-history-api-fallback": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", @@ -9788,7 +9560,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -10280,26 +10051,6 @@ "node": ">=8.0.0" } }, - "node_modules/csso/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/csstype": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz", @@ -11045,223 +10796,6 @@ "eslint": ">=5.0.0" } }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/generator": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.3.tgz", - "integrity": "sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.14.2", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/helper-function-name": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz", - "integrity": "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.14.2" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", - "dev": true - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/helpers": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.0.tgz", - "integrity": "sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.14.0" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/parser": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz", - "integrity": "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/template/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.12.13" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz", - "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.2", - "@babel/helper-function-name": "^7.14.2", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.14.2", - "@babel/types": "^7.14.2", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/traverse/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.12.13" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@babel/types": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz", - "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.0", - "to-fast-properties": "^2.0.0" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/@mdx-js/util": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, "node_modules/eslint-plugin-mdx/node_modules/cosmiconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", @@ -11278,121 +10812,6 @@ "node": ">=10" } }, - "node_modules/eslint-plugin-mdx/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/remark-mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", - "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", - "dev": true, - "dependencies": { - "@babel/core": "7.12.9", - "@babel/helper-plugin-utils": "7.10.4", - "@babel/plugin-proposal-object-rest-spread": "7.12.1", - "@babel/plugin-syntax-jsx": "7.12.1", - "@mdx-js/util": "1.6.22", - "is-alphabetical": "1.0.4", - "remark-parse": "8.0.3", - "unified": "9.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/remark-mdx/node_modules/unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", - "dev": true, - "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-mdx/node_modules/tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", - "dev": true - }, "node_modules/eslint-plugin-mdx/node_modules/unified": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz", @@ -12259,9 +11678,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", + "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", "funding": [ { "type": "individual", @@ -12427,14 +11846,6 @@ "node": ">=0.10.0" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -12493,17 +11904,6 @@ "semver": "bin/semver" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -14524,18 +13924,6 @@ "node": ">=10" } }, - "node_modules/json-schema-to-typescript/node_modules/prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -15247,19 +14635,6 @@ "webpack": "^4.4.0 || ^5.0.0" } }, - "node_modules/mini-css-extract-plugin/node_modules/loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/mini-css-extract-plugin/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -15590,20 +14965,6 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/null-loader/node_modules/loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -16543,11 +15904,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-minify-font-values/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-minify-gradients": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.1.tgz", @@ -16564,11 +15920,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-minify-gradients/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-minify-selectors": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz", @@ -16584,18 +15935,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/postcss-modules-local-by-default": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", @@ -16662,11 +16001,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-normalize-positions/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-normalize-repeat-style": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz", @@ -16682,11 +16016,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-normalize-repeat-style/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-normalize-string": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz", @@ -16701,11 +16030,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-normalize-string/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-normalize-timing-functions": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz", @@ -16721,11 +16045,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-normalize-timing-functions/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-normalize-unicode": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz", @@ -16768,11 +16087,6 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.788.tgz", "integrity": "sha512-dbMIpX4E4/Gk4gzOh1GYS7ls1vGsByWKpIqLviJi1mSmSt5BvrWLLtSqpFE5BaC7Ef4NnI0GMaiddNX2Brw6zA==" }, - "node_modules/postcss-normalize-unicode/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-normalize-url": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.2.tgz", @@ -16789,11 +16103,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-normalize-url/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-normalize-whitespace": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz", @@ -16808,11 +16117,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-normalize-whitespace/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-reduce-idents": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.0.1.tgz", @@ -16910,11 +16214,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-svgo/node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, "node_modules/postcss-unique-selectors": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz", @@ -17335,14 +16634,6 @@ "node": ">=10" } }, - "node_modules/react-dev-utils/node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, "node_modules/react-dev-utils/node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -17409,19 +16700,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, - "node_modules/react-dev-utils/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/react-dev-utils/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -17473,59 +16751,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-dev-utils/node_modules/globby/node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/react-dev-utils/node_modules/globby/node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/globby/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/globby/node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/globby/node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/react-dev-utils/node_modules/globby/node_modules/ignore": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", @@ -17534,42 +16759,6 @@ "node": ">= 4" } }, - "node_modules/react-dev-utils/node_modules/globby/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/react-dev-utils/node_modules/globby/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/globby/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, "node_modules/react-dev-utils/node_modules/immer": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", @@ -17579,35 +16768,11 @@ "url": "https://opencollective.com/immer" } }, - "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/react-dev-utils/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "node_modules/react-dev-utils/node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/react-dev-utils/node_modules/prompts": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", @@ -17620,36 +16785,6 @@ "node": ">= 6" } }, - "node_modules/react-dev-utils/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -18312,11 +17447,6 @@ "node": ">=6.9.0" } }, - "node_modules/remark-mdx/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, "node_modules/remark-mdx/node_modules/@babel/helper-split-export-declaration": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", @@ -18440,30 +17570,6 @@ "node": ">=6.0.0" } }, - "node_modules/remark-mdx/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/remark-mdx/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/remark-mdx/node_modules/@mdx-js/util": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", @@ -18518,14 +17624,6 @@ "node": ">=0.8.0" } }, - "node_modules/remark-mdx/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, "node_modules/remark-mdx/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -18534,17 +17632,6 @@ "semver": "bin/semver" } }, - "node_modules/remark-mdx/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/remark-parse": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", @@ -19215,14 +18302,6 @@ "node": ">=8" } }, - "node_modules/shallow-clone/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -19927,18 +19006,6 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.788.tgz", "integrity": "sha512-dbMIpX4E4/Gk4gzOh1GYS7ls1vGsByWKpIqLviJi1mSmSt5BvrWLLtSqpFE5BaC7Ef4NnI0GMaiddNX2Brw6zA==" }, - "node_modules/stylehacks/node_modules/postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -19983,21 +19050,6 @@ "node": ">=10.13.0" } }, - "node_modules/svgo/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/svgo/node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -20006,17 +19058,6 @@ "node": ">= 10" } }, - "node_modules/svgo/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/synckit": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.1.5.tgz", @@ -20518,22 +19559,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unified/node_modules/is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unified/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -21115,21 +20140,6 @@ "node": ">=0.4.0" } }, - "node_modules/webpack-bundle-analyzer/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/webpack-bundle-analyzer/node_modules/commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", @@ -21152,17 +20162,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-bundle-analyzer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", @@ -21876,24 +20875,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -22621,19 +21602,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -22915,19 +21883,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -23229,19 +22184,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -23313,7 +22255,6 @@ "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -26377,11 +25318,6 @@ "is-glob": "^4.0.1" } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, "html-webpack-plugin": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.3.2.tgz", @@ -26463,14 +25399,6 @@ "ajv-keywords": "^3.5.2" } }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, "update-notifier": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", @@ -26628,16 +25556,6 @@ "webpack": "^5.40.0" }, "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, "execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -27308,14 +26226,6 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==" }, - "@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, "@mdx-js/util": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", @@ -27357,23 +26267,10 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -27681,11 +26578,6 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, "js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -27713,14 +26605,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, "svgo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", @@ -28529,11 +27413,6 @@ "@mdx-js/util": "1.6.22" }, "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, "@mdx-js/util": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", @@ -28555,13 +27434,6 @@ "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", "requires": { "@babel/helper-plugin-utils": "7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - } } }, "babel-plugin-polyfill-corejs2": { @@ -28916,32 +27788,6 @@ "supports-color": "^7.1.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -29287,19 +28133,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -29423,21 +28256,6 @@ "unique-string": "^2.0.0", "write-file-atomic": "^3.0.0", "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } } }, "connect-history-api-fallback": { @@ -29554,7 +28372,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -29868,22 +28685,6 @@ "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", "requires": { "css-tree": "^1.1.2" - }, - "dependencies": { - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "csstype": { @@ -30503,204 +29304,6 @@ "vfile": "^4.2.1" }, "dependencies": { - "@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/generator": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.3.tgz", - "integrity": "sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.2", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz", - "integrity": "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.14.2" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", - "dev": true - }, - "@babel/helpers": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.0.tgz", - "integrity": "sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg==", - "dev": true, - "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.14.0" - } - }, - "@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz", - "integrity": "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - } - } - }, - "@babel/traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz", - "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.2", - "@babel/helper-function-name": "^7.14.2", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.14.2", - "@babel/types": "^7.14.2", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - } - } - }, - "@babel/types": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz", - "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.0", - "to-fast-properties": "^2.0.0" - } - }, - "@mdx-js/util": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, "cosmiconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", @@ -30714,83 +29317,6 @@ "yaml": "^1.10.0" } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "remark-mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", - "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", - "dev": true, - "requires": { - "@babel/core": "7.12.9", - "@babel/helper-plugin-utils": "7.10.4", - "@babel/plugin-proposal-object-rest-spread": "7.12.1", - "@babel/plugin-syntax-jsx": "7.12.1", - "@mdx-js/util": "1.6.22", - "is-alphabetical": "1.0.4", - "remark-parse": "8.0.3", - "unified": "9.2.0" - }, - "dependencies": { - "unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", - "dev": true, - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - } - } - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", - "dev": true - }, "unified": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz", @@ -31448,9 +29974,9 @@ } }, "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", + "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" }, "for-in": { "version": "1.0.2", @@ -31574,11 +30100,6 @@ } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -31627,14 +30148,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -33145,12 +31658,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true - }, - "prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", - "dev": true } } }, @@ -33708,16 +32215,6 @@ "webpack-sources": "^1.1.0" }, "dependencies": { - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -33978,19 +32475,6 @@ "requires": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" - }, - "dependencies": { - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - } } }, "object-assign": { @@ -34668,13 +33152,6 @@ "integrity": "sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA==", "requires": { "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - } } }, "postcss-minify-gradients": { @@ -34685,13 +33162,6 @@ "cssnano-utils": "^2.0.1", "is-color-stop": "^1.1.0", "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - } } }, "postcss-minify-selectors": { @@ -34701,17 +33171,6 @@ "requires": { "alphanum-sort": "^1.0.2", "postcss-selector-parser": "^6.0.5" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } } }, "postcss-modules-local-by-default": { @@ -34754,13 +33213,6 @@ "integrity": "sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg==", "requires": { "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - } } }, "postcss-normalize-repeat-style": { @@ -34770,13 +33222,6 @@ "requires": { "cssnano-utils": "^2.0.1", "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - } } }, "postcss-normalize-string": { @@ -34785,13 +33230,6 @@ "integrity": "sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA==", "requires": { "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - } } }, "postcss-normalize-timing-functions": { @@ -34801,13 +33239,6 @@ "requires": { "cssnano-utils": "^2.0.1", "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - } } }, "postcss-normalize-unicode": { @@ -34835,11 +33266,6 @@ "version": "1.3.788", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.788.tgz", "integrity": "sha512-dbMIpX4E4/Gk4gzOh1GYS7ls1vGsByWKpIqLviJi1mSmSt5BvrWLLtSqpFE5BaC7Ef4NnI0GMaiddNX2Brw6zA==" - }, - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" } } }, @@ -34851,13 +33277,6 @@ "is-absolute-url": "^3.0.3", "normalize-url": "^6.0.1", "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - } } }, "postcss-normalize-whitespace": { @@ -34866,13 +33285,6 @@ "integrity": "sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA==", "requires": { "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - } } }, "postcss-reduce-idents": { @@ -34935,13 +33347,6 @@ "requires": { "postcss-value-parser": "^4.1.0", "svgo": "^2.3.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - } } }, "postcss-unique-selectors": { @@ -35265,14 +33670,6 @@ "text-table": "0.2.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "requires": { - "@babel/highlight": "^7.10.4" - } - }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -35322,16 +33719,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -35367,100 +33754,23 @@ "slash": "^3.0.0" }, "dependencies": { - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "requires": { - "path-type": "^4.0.0" - } - }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, "ignore": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, "immer": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==" }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" - }, "prompts": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", @@ -35469,29 +33779,6 @@ "kleur": "^3.0.3", "sisteransi": "^1.0.5" } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" - } - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -36018,11 +34305,6 @@ } } }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, "@babel/helper-split-export-declaration": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", @@ -36117,24 +34399,6 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==" }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, "@mdx-js/util": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", @@ -36176,23 +34440,10 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -36722,13 +34973,6 @@ "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "requires": { "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } } }, "shebang-command": { @@ -37275,15 +35519,6 @@ "version": "1.3.788", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.788.tgz", "integrity": "sha512-dbMIpX4E4/Gk4gzOh1GYS7ls1vGsByWKpIqLviJi1mSmSt5BvrWLLtSqpFE5BaC7Ef4NnI0GMaiddNX2Brw6zA==" - }, - "postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } } } }, @@ -37321,27 +35556,10 @@ "stable": "^0.1.8" }, "dependencies": { - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, "commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -37711,18 +35929,6 @@ "is-plain-obj": "^2.0.0", "trough": "^1.0.0", "vfile": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" - } } }, "union-value": { @@ -38144,15 +36350,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==" }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, "commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", @@ -38166,14 +36363,6 @@ "duplexer": "^0.1.2" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, "ws": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", @@ -38718,25 +36907,6 @@ "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" - }, - "dependencies": { - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - } - } - } } }, "wrappy": { From 8678a537c63faa4225599f08735d5131d8ed4d7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Jan 2022 03:46:14 +0000 Subject: [PATCH 22/48] chore(deps): bump shelljs from 0.8.4 to 0.8.5 in /docs Bumps [shelljs](https://github.com/shelljs/shelljs) from 0.8.4 to 0.8.5. - [Release notes](https://github.com/shelljs/shelljs/releases) - [Changelog](https://github.com/shelljs/shelljs/blob/master/CHANGELOG.md) - [Commits](https://github.com/shelljs/shelljs/compare/v0.8.4...v0.8.5) --- updated-dependencies: - dependency-name: shelljs dependency-type: indirect ... Signed-off-by: dependabot[bot] --- docs/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 756a5a16..17aae20f 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -18327,9 +18327,9 @@ "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" }, "node_modules/shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", - "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", "dependencies": { "glob": "^7.0.0", "interpret": "^1.0.0", @@ -34994,9 +34994,9 @@ "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" }, "shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", - "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", "requires": { "glob": "^7.0.0", "interpret": "^1.0.0", From 84365e6def9f9084b6c166d250aa84638c0e288f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Feb 2022 05:16:46 +0000 Subject: [PATCH 23/48] chore(deps-dev): bump json-schema-to-typescript in /docs Bumps [json-schema-to-typescript](https://github.com/bcherny/json-schema-to-typescript) from 10.1.3 to 10.1.5. - [Release notes](https://github.com/bcherny/json-schema-to-typescript/releases) - [Changelog](https://github.com/bcherny/json-schema-to-typescript/blob/master/CHANGELOG.md) - [Commits](https://github.com/bcherny/json-schema-to-typescript/commits) --- updated-dependencies: - dependency-name: json-schema-to-typescript dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/package-lock.json | 52 +++++++++++++++++++++++------------------- docs/package.json | 2 +- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 17aae20f..f799ad70 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -33,7 +33,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-mdx": "^1.13.0", "eslint-plugin-react": "^7.28.0", - "json-schema-to-typescript": "^10.1.3", + "json-schema-to-typescript": "^10.1.5", "mustache": "^4.2.0", "null-loader": "^4.0.0", "prebuild-webpack-plugin": "^1.1.1", @@ -12026,6 +12026,18 @@ "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" }, + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -13884,15 +13896,16 @@ } }, "node_modules/json-schema-to-typescript": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-10.1.3.tgz", - "integrity": "sha512-yiyDK1sSSWhLN2JAuAyAE7jscFJj2hR7AhdF19BmdLh/N/QPdnIqrGa23CSc7z92OSSzKVPclAKof+rV8S8weA==", + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-10.1.5.tgz", + "integrity": "sha512-X8bNNksfCQo6LhEuqNxmZr4eZpPjXZajmimciuk8eWXzZlif9Brq7WuMGD/SOhBKcRKP2SGVDNZbC28WQqx9Rg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.6", "@types/lodash": "^4.14.168", "@types/prettier": "^2.1.5", "cli-color": "^2.0.0", + "get-stdin": "^8.0.0", "glob": "^7.1.6", "glob-promise": "^3.4.0", "is-glob": "^4.0.1", @@ -13902,8 +13915,7 @@ "minimist": "^1.2.5", "mkdirp": "^1.0.4", "mz": "^2.7.0", - "prettier": "^2.2.0", - "stdin": "0.0.1" + "prettier": "^2.2.0" }, "bin": { "json2ts": "dist/src/cli.js" @@ -18767,12 +18779,6 @@ "ci-info": "^1.6.0" } }, - "node_modules/stdin": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/stdin/-/stdin-0.0.1.tgz", - "integrity": "sha1-0wQZgarsPf28d6GzjWNy449ftx4=", - "dev": true - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -30234,6 +30240,12 @@ "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" }, + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -31631,15 +31643,16 @@ } }, "json-schema-to-typescript": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-10.1.3.tgz", - "integrity": "sha512-yiyDK1sSSWhLN2JAuAyAE7jscFJj2hR7AhdF19BmdLh/N/QPdnIqrGa23CSc7z92OSSzKVPclAKof+rV8S8weA==", + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-10.1.5.tgz", + "integrity": "sha512-X8bNNksfCQo6LhEuqNxmZr4eZpPjXZajmimciuk8eWXzZlif9Brq7WuMGD/SOhBKcRKP2SGVDNZbC28WQqx9Rg==", "dev": true, "requires": { "@types/json-schema": "^7.0.6", "@types/lodash": "^4.14.168", "@types/prettier": "^2.1.5", "cli-color": "^2.0.0", + "get-stdin": "^8.0.0", "glob": "^7.1.6", "glob-promise": "^3.4.0", "is-glob": "^4.0.1", @@ -31649,8 +31662,7 @@ "minimist": "^1.2.5", "mkdirp": "^1.0.4", "mz": "^2.7.0", - "prettier": "^2.2.0", - "stdin": "0.0.1" + "prettier": "^2.2.0" }, "dependencies": { "mkdirp": { @@ -35348,12 +35360,6 @@ "ci-info": "^1.6.0" } }, - "stdin": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/stdin/-/stdin-0.0.1.tgz", - "integrity": "sha1-0wQZgarsPf28d6GzjWNy449ftx4=", - "dev": true - }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", diff --git a/docs/package.json b/docs/package.json index 13add5d1..6a5b9f2f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -52,7 +52,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-mdx": "^1.13.0", "eslint-plugin-react": "^7.28.0", - "json-schema-to-typescript": "^10.1.3", + "json-schema-to-typescript": "^10.1.5", "mustache": "^4.2.0", "null-loader": "^4.0.0", "prebuild-webpack-plugin": "^1.1.1", From 85b2d30bd521424686ba7f1c5ac4fe492f5f2ca5 Mon Sep 17 00:00:00 2001 From: Alessandro Bortolin Date: Sat, 9 Oct 2021 18:24:37 +0200 Subject: [PATCH 24/48] feat(lighting): add backlight behavior --- app/CMakeLists.txt | 2 + app/Kconfig | 37 ++- app/dts/behaviors.dtsi | 1 + app/dts/behaviors/backlight.dtsi | 15 ++ .../behaviors/zmk,behavior-backlight.yaml | 8 + app/include/dt-bindings/zmk/backlight.h | 11 + app/include/zmk/backlight.h | 19 ++ app/src/backlight.c | 224 ++++++++++++++++++ app/src/behaviors/behavior_backlight.c | 56 +++++ 9 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 app/dts/behaviors/backlight.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-backlight.yaml create mode 100644 app/include/dt-bindings/zmk/backlight.h create mode 100644 app/include/zmk/backlight.h create mode 100644 app/src/backlight.c create mode 100644 app/src/behaviors/behavior_backlight.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 7681efab..25f6c6cd 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -64,6 +64,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) target_sources(app PRIVATE src/keymap.c) endif() target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c) +target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/behaviors/behavior_backlight.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/behaviors/behavior_bt.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/battery.c) @@ -77,6 +78,7 @@ endif() target_sources_ifdef(CONFIG_USB app PRIVATE src/usb.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/hog.c) target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c) +target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/backlight.c) target_sources(app PRIVATE src/endpoints.c) target_sources(app PRIVATE src/hid_listener.c) target_sources(app PRIVATE src/main.c) diff --git a/app/Kconfig b/app/Kconfig index 76035147..49eec835 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -257,7 +257,7 @@ menu "Display/LED Options" rsource "src/display/Kconfig" -config ZMK_RGB_UNDERGLOW +menuconfig ZMK_RGB_UNDERGLOW bool "RGB Adressable LED Underglow" select LED_STRIP @@ -328,6 +328,39 @@ config ZMK_RGB_UNDERGLOW_ON_START #ZMK_RGB_UNDERGLOW endif +menuconfig ZMK_BACKLIGHT + bool "LED backlight" + select PWM + select LED + select ZMK_LED_PWM + +if ZMK_BACKLIGHT + +config ZMK_BACKLIGHT_BRT_STEP + int "Brightness step in percent" + range 1 100 + default 20 + +config ZMK_BACKLIGHT_BRT_START + int "Default brightness in percent" + range 1 100 + default 40 + +config ZMK_BACKLIGHT_ON_START + bool "Default backlight state" + default y + +config ZMK_BACKLIGHT_AUTO_OFF_IDLE + bool "Turn off backlight when keyboard goes into idle state" + default y + +config ZMK_BACKLIGHT_AUTO_OFF_USB + bool "Turn off backlight when USB is disconnected" + default n + +#ZMK_BACKLIGHT +endif + #Display/LED Options endmenu @@ -378,7 +411,7 @@ config ZMK_COMBO_MAX_KEYS_PER_COMBO int "Maximum number of keys per combo" default 4 -#Display/LED Options +#Combo options endmenu menu "Advanced" diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 06489616..3e797cc9 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -16,3 +16,4 @@ #include #include #include +#include diff --git a/app/dts/behaviors/backlight.dtsi b/app/dts/behaviors/backlight.dtsi new file mode 100644 index 00000000..b05d97ae --- /dev/null +++ b/app/dts/behaviors/backlight.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + / { + behaviors { + /omit-if-no-ref/ bl: behavior_backlight { + compatible = "zmk,behavior-backlight"; + label = "BACKLIGHT"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml b/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml new file mode 100644 index 00000000..e035e15e --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Backlight behavior + +compatible: "zmk,behavior-backlight" + +include: one_param.yaml diff --git a/app/include/dt-bindings/zmk/backlight.h b/app/include/dt-bindings/zmk/backlight.h new file mode 100644 index 00000000..c33e4344 --- /dev/null +++ b/app/include/dt-bindings/zmk/backlight.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define BL_TOG 0 +#define BL_ON 1 +#define BL_OFF 2 +#define BL_INC 3 +#define BL_DEC 4 diff --git a/app/include/zmk/backlight.h b/app/include/zmk/backlight.h new file mode 100644 index 00000000..817efe7a --- /dev/null +++ b/app/include/zmk/backlight.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +int zmk_backlight_set_on(bool on); +bool zmk_backlight_is_on(); + +int zmk_backlight_set_brt(int brt); +int zmk_backlight_get_brt(); + +int zmk_backlight_toggle(); +int zmk_backlight_on(); +int zmk_backlight_off(); +int zmk_backlight_inc(); +int zmk_backlight_dec(); diff --git a/app/src/backlight.c b/app/src/backlight.c new file mode 100644 index 00000000..517e6133 --- /dev/null +++ b/app/src/backlight.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +BUILD_ASSERT(DT_HAS_CHOSEN(zmk_backlight), + "CONFIG_ZMK_BACKLIGHT is enabled but no zmk,backlight chosen node found"); + +static const struct device *const backlight_dev = DEVICE_DT_GET(DT_CHOSEN(zmk_backlight)); + +#define CHILD_COUNT(...) +1 +#define DT_NUM_CHILD(node_id) (DT_FOREACH_CHILD(node_id, CHILD_COUNT)) + +#define BACKLIGHT_NUM_LEDS (DT_NUM_CHILD(DT_CHOSEN(zmk_backlight))) + +struct backlight_state { + uint8_t brightness; + bool on; +}; + +static struct backlight_state state = {.brightness = CONFIG_ZMK_BACKLIGHT_BRT_START, + .on = IS_ENABLED(CONFIG_ZMK_BACKLIGHT_ON_START)}; + +static int zmk_backlight_update() { + uint8_t brt = state.on ? state.brightness : 0; + for (int i = 0; i < BACKLIGHT_NUM_LEDS; i++) { + int rc = led_set_brightness(backlight_dev, i, brt); + if (rc != 0) { + return rc; + } + } + return 0; +} + +#if IS_ENABLED(CONFIG_SETTINGS) +static int backlight_settings_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) { + const char *next; + + if (settings_name_steq(name, "state", &next) && !next) { + if (len != sizeof(state)) { + return -EINVAL; + } + + int rc = read_cb(cb_arg, &state, sizeof(state)); + if (rc < 0) { + return rc; + } + + return zmk_backlight_update(); + } + + return -ENOENT; +} + +static struct settings_handler backlight_conf = {.name = "backlight", + .h_set = backlight_settings_set}; + +static void zmk_backlight_save_state_work() { + settings_save_one("backlight/state", &state, sizeof(state)); +} + +static struct k_delayed_work backlight_save_work; +#endif // IS_ENABLED(CONFIG_SETTINGS) + +static int zmk_backlight_save_state() { +#if IS_ENABLED(CONFIG_SETTINGS) + k_delayed_work_cancel(&backlight_save_work); + return k_delayed_work_submit(&backlight_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); +#else + return 0; +#endif +} + +static int zmk_backlight_init(const struct device *_arg) { + if (!device_is_ready(backlight_dev)) { + LOG_ERR("Backlight device \"%s\" is not ready", backlight_dev->name); + return -ENODEV; + } + +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + + int err = settings_register(&backlight_conf); + if (err) { + LOG_ERR("Failed to register the backlight settings handler (err %d)", err); + return err; + } + + k_delayed_work_init(&backlight_save_work, zmk_backlight_save_state_work); + + settings_load_subtree("backlight"); +#endif + + return zmk_backlight_update(); +} + +int zmk_backlight_set_on(bool on) { + if (!state.on && state.brightness == 0) { + state.brightness = CONFIG_ZMK_BACKLIGHT_BRT_STEP; + } + state.on = on; + + int rc = zmk_backlight_update(); + if (rc != 0) { + return rc; + } + + return zmk_backlight_save_state(); +} + +bool zmk_backlight_is_on() { return state.on; } + +int zmk_backlight_set_brt(int brt) { + state.on = (brt > 0); + state.brightness = CLAMP(brt, 0, 100); + + int rc = zmk_backlight_update(); + if (rc != 0) { + return rc; + } + + return zmk_backlight_save_state(); +} + +int zmk_backlight_get_brt() { return state.on ? state.brightness : 0; } + +int zmk_backlight_toggle() { return zmk_backlight_set_on(!state.on); } + +int zmk_backlight_on() { return zmk_backlight_set_on(true); } + +int zmk_backlight_off() { return zmk_backlight_set_on(false); } + +int zmk_backlight_inc() { + if (!state.on) { + return zmk_backlight_set_brt(MAX(state.brightness, CONFIG_ZMK_BACKLIGHT_BRT_STEP)); + } + return zmk_backlight_set_brt(state.brightness + CONFIG_ZMK_BACKLIGHT_BRT_STEP); +} + +int zmk_backlight_dec() { + return zmk_backlight_set_brt(state.brightness - CONFIG_ZMK_BACKLIGHT_BRT_STEP); +} + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) +static bool auto_off_idle_prev_state = false; +#endif + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) +static bool auto_off_usb_prev_state = false; +#endif + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) || IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) +static int backlight_event_listener(const zmk_event_t *eh) { + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) + if (as_zmk_activity_state_changed(eh)) { + bool new_state = (zmk_activity_get_state() == ZMK_ACTIVITY_ACTIVE); + if (state.on == new_state) { + return 0; + } + if (new_state) { + state.on = auto_off_idle_prev_state; + auto_off_idle_prev_state = false; + } else { + state.on = false; + auto_off_idle_prev_state = true; + } + return zmk_backlight_update(); + } +#endif + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) + if (as_zmk_usb_conn_state_changed(eh)) { + bool new_state = zmk_usb_is_powered(); + if (state.on == new_state) { + return 0; + } + if (new_state) { + state.on = auto_off_usb_prev_state; + auto_off_usb_prev_state = false; + } else { + state.on = false; + auto_off_usb_prev_state = true; + } + return zmk_backlight_update(); + } +#endif + + return -ENOTSUP; +} + +ZMK_LISTENER(backlight, backlight_event_listener); +#endif // IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) || + // IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) +ZMK_SUBSCRIPTION(backlight, zmk_activity_state_changed); +#endif + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) +ZMK_SUBSCRIPTION(backlight, zmk_usb_conn_state_changed); +#endif + +SYS_INIT(zmk_backlight_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/behaviors/behavior_backlight.c b/app/src/behaviors/behavior_backlight.c new file mode 100644 index 00000000..8d921f45 --- /dev/null +++ b/app/src/behaviors/behavior_backlight.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_backlight + +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_backlight_init(const struct device *dev) { return 0; } + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case BL_TOG: + return zmk_backlight_toggle(); + case BL_ON: + return zmk_backlight_on(); + case BL_OFF: + return zmk_backlight_off(); + case BL_INC: + return zmk_backlight_inc(); + case BL_DEC: + return zmk_backlight_dec(); + default: + LOG_ERR("Unknown backlight command: %d", binding->param1); + } + + return -ENOTSUP; +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_backlight_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +DEVICE_DT_INST_DEFINE(0, behavior_backlight_init, device_pm_control_nop, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_backlight_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ From da41391b1f1649d5ed24cb6411927c085268a70b Mon Sep 17 00:00:00 2001 From: Alessandro Bortolin Date: Sat, 9 Oct 2021 18:25:00 +0200 Subject: [PATCH 25/48] feat(docs): add backlight documentation --- docs/blog/2021-01-27-zmk-sotf-4.md | 2 +- docs/docs/behaviors/backlight.md | 48 ++++++++ .../behaviors/{lighting.md => underglow.md} | 15 +-- .../development/hardware-metadata-files.md | 1 + docs/docs/features/backlight.md | 115 ++++++++++++++++++ docs/docs/hardware.mdx | 1 + docs/docs/intro.md | 1 + docs/sidebars.js | 4 +- 8 files changed, 175 insertions(+), 12 deletions(-) create mode 100644 docs/docs/behaviors/backlight.md rename docs/docs/behaviors/{lighting.md => underglow.md} (88%) create mode 100644 docs/docs/features/backlight.md diff --git a/docs/blog/2021-01-27-zmk-sotf-4.md b/docs/blog/2021-01-27-zmk-sotf-4.md index d902b62d..cd84da88 100644 --- a/docs/blog/2021-01-27-zmk-sotf-4.md +++ b/docs/blog/2021-01-27-zmk-sotf-4.md @@ -76,7 +76,7 @@ to your keymap will send `ESC` when pressed on its own, but will send `` ` `` wh #### RGB Underglow Color Selection -[mcrosson] updated the [RGB Underglow behavior](/docs/behaviors/lighting#rgb-underglow) to allow [binding an explicit color selection](/docs/behaviors/lighting#examples) to a key position. +[mcrosson] updated the [RGB Underglow behavior](/docs/behaviors/underglow) to allow [binding an explicit color selection](/docs/behaviors/underglow#examples) to a key position. #### Keymap Upgrader diff --git a/docs/docs/behaviors/backlight.md b/docs/docs/behaviors/backlight.md new file mode 100644 index 00000000..c1a92c90 --- /dev/null +++ b/docs/docs/behaviors/backlight.md @@ -0,0 +1,48 @@ +--- +title: Backlight Behavior +sidebar_label: Backlight +--- + +## Summary + +This page contains [backlight](../features/backlight.md) behaviors supported by ZMK. + +## Backlight Action Defines + +Backlight actions defines are provided through the [`dt-bindings/zmk/backlight.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/backlight.h) header, +which is added at the top of the keymap file: + +``` +#include +``` + +This will allow you to reference the actions defined in this header such as `BL_TOG`. + +Here is a table describing the action for each define: + +| Define | Action | +| -------- | ---------------------------------------- | +| `BL_TOG` | Toggles the backlight on and off | +| `BL_ON` | Turn on backlight on and off | +| `BL_OFF` | Toggles the backlight feature on and off | +| `BL_INC` | Increase backlight brightness | +| `BL_DEC` | Decrease backlight brightness | + +## Behavior Binding + +- Reference: `&bl` +- Parameter #1: The backlight action define, e.g. `BL_TOG` or `BL_INC` + +### Examples + +1. Toggle backlight on/off + + ``` + &bl BL_TOG + ``` + +1. Increase backlight brightness + + ``` + &bl BL_INC + ``` diff --git a/docs/docs/behaviors/lighting.md b/docs/docs/behaviors/underglow.md similarity index 88% rename from docs/docs/behaviors/lighting.md rename to docs/docs/behaviors/underglow.md index 6e6732be..597c2491 100644 --- a/docs/docs/behaviors/lighting.md +++ b/docs/docs/behaviors/underglow.md @@ -1,12 +1,11 @@ --- -title: Lighting Behavior -sidebar_label: Lighting +title: RGB Underglow Behavior +sidebar_label: RGB Underglow --- ## Summary -Lighting is often used for either aesthetics or for the practical purposes of lighting up keys in the dark. -Currently ZMK supports RGB underglow, which can be changed and configured using its behavior. +This page contains [RGB Underglow](../features/underglow.md) behaviors supported by ZMK. ## RGB Action Defines @@ -36,11 +35,7 @@ Here is a table describing the action for each define: | `RGB_EFR` | Cycles the RGB feature's effect reverse | | `RGB_COLOR_HSB` | Sets a specific [HSB (HSV)](https://en.wikipedia.org/wiki/HSL_and_HSV) value for the underglow | -## RGB Underglow - -The "RGB underglow" behavior completes an RGB action given on press. - -### Behavior Binding +## Behavior Binding - Reference: `&rgb_ug` - Parameter #1: The RGB action define, e.g. `RGB_TOG` or `RGB_BRI` @@ -58,7 +53,7 @@ Value Limits: ::: -### Examples +## Examples 1. Toggle underglow on/off diff --git a/docs/docs/development/hardware-metadata-files.md b/docs/docs/development/hardware-metadata-files.md index 5d4902dc..46fad411 100644 --- a/docs/docs/development/hardware-metadata-files.md +++ b/docs/docs/development/hardware-metadata-files.md @@ -94,6 +94,7 @@ Boards and shields should document the sets of hardware features found on them u - `display` - Indicates the hardware includes a display for use with the ZMK display functionality. - `encoder` - Indicates the hardware contains one or more rotary encoders. - `underglow` - Indicates the hardware includes underglow LEDs. +- `backlight` - Indicates the hardware includes backlight LEDs. - `pointer` (future) - Used to indicate the hardware includes one or more pointer inputs, e.g. joystick, touchpad, or trackpoint. ### Siblings diff --git a/docs/docs/features/backlight.md b/docs/docs/features/backlight.md new file mode 100644 index 00000000..a917b166 --- /dev/null +++ b/docs/docs/features/backlight.md @@ -0,0 +1,115 @@ +--- +title: Backlight +sidebar_label: Backlight +--- + +Backlight is a feature used to control array of LEDs, usually placed through or under switches. Unlike [RGB Underglow](underglow.md), backlight currently allows only one color per LED, also LEDs are not addressable, so you can't control individual LEDs. + +## Enabling Backlight + +To enable backlight on your board or shield, simply enable the `CONFIG_ZMK_BACKLIGHT` configuration values in the `.conf` file of your user config directory as such: + +``` +CONFIG_ZMK_BACKLIGHT=y +``` + +If your board or shield does not have backlight configured, refer to [Adding Backlight to a Board](#adding-backlight-to-a-board). + +## Configuring Backlight + +There are various Kconfig options used to configure the backlight feature. These can all be set in the `.conf` file. + +| Option | Description | Default | +| ------------------------------------ | ----------------------------------------------------- | ------- | +| `CONFIG_ZMK_BACKLIGHT_BRT_STEP` | Brightness step in percent | 20 | +| `CONFIG_ZMK_BACKLIGHT_BRT_START` | Default brightness in percent | 40 | +| `CONFIG_ZMK_BACKLIGHT_ON_START` | Default backlight state | y | +| `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE` | Turn off backlight when keyboard goes into idle state | y | +| `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB` | Turn off backlight when USB is disconnected | n | + +## Adding Backlight to a Board + +Backlight is always added to a board, not a shield. +If you have a shield with backlight, you must add a `boards/` directory within your shield folder to define the backlight individually for each board that supports the shield. +Inside the `boards/` folder, you define a `.overlay` for each different board. + +First, you need to enable PWM by adding the following lines to your `.overlay` file: + +``` +&pwm0 { + status = "okay"; + ch0-pin = <45>; + /* ch0-inverted; */ +}; +``` + +The value `ch0-pin` represents the pin that controls the LEDs. To calculate the value to use, you need a bit of math. You need the hardware port and run it through a function. +**32 \* X + Y** = `` where X is first part of the hardware port "PX.01" and Y is the second part of the hardware port "P1.Y". + +For example, _P1.13_ would give you _32 \* 1 + 13_ = `<45>` and _P0.15_ would give you _32 \* 0 + 15_ = `<15>`. + +If your board uses a P-channel MOSFET to control backlight instead of a N-channel MOSFET, you may want to enable `ch0-inverted`. + +Then you have to add the following lines to your `.dtsi` file inside the root devicetree node: + +``` +backlight: pwmleds { + compatible = "pwm-leds"; + label = "Backlight LEDs"; + pwm_led_0 { + pwms = <&pwm0 45>; + }; +}; +``` + +The value inside `pwm_led_0` must be the same as you used before. + +:::info +Note that every LED inside of the backlight node will be treated as a backlight LED, so if you have other PWM LEDs you need to declare them in a separate node. Refer to [Multiple backlight LEDs](#multiple-backlight-leds) if you have multiple backlight LEDs. +::: + +Finally you need to add backlight to the `chosen` element of the root devicetree node: + +``` +chosen { + ... + zmk,backlight = &backlight; +}; +``` + +### Multiple backlight LEDs + +It is possible to control multiple backlight LEDs at the same time. This is useful if, for example, you have a Caps Lock LED connected to a different pin and you want it to be part of the backlight. + +In order to do that, first you need to enable PWM for each pin: + +``` +&pwm0 { + status = "okay"; + ch0-pin = <45>; /* LED 0 */ + ch1-pin = <46>; /* LED 1 */ + ch2-pin = <47>; /* LED 2 */ + ... +}; +``` + +This part may vary based on your MCU as different MCUs may have a different number of modules and channels. + +Then you can simply add each of your LED to the backlight node: + +``` +backlight: pwmleds { + compatible = "pwm-leds"; + label = "Backlight LEDs"; + pwm_led_0 { + pwms = <&pwm0 45>; /* LED 0 */ + }; + pwm_led_1 { + pwms = <&pwm0 46>; /* LED 1 */ + }; + pwm_led_2 { + pwms = <&pwm0 47>; /* LED 2 */ + }; + ... +}; +``` diff --git a/docs/docs/hardware.mdx b/docs/docs/hardware.mdx index ccdd063e..76a0a3cb 100644 --- a/docs/docs/hardware.mdx +++ b/docs/docs/hardware.mdx @@ -18,6 +18,7 @@ In addition to the basic keyboard functionality, there is some initial support f - Encoders - Displays - RGB Underglow +- Backlight Until detailed documentation is available, feel free to ask questions about how these are supported in the [Discord server](https://zmk.dev/community/discord/invite). diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 39a52c6c..b8a6316c 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -28,6 +28,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | [Encoders](features/encoders.md)[^1] | ✅ | ✅ | ✅ | | [Display Support](features/displays.md)[^2] | 🚧 | 🚧 | ✅ | | [RGB Underglow](features/underglow.md) | ✅ | ✅ | ✅ | +| [Backlight](features/backlight.md) | ✅ | ✅ | ✅ | | One Shot Keys | ✅ | ✅ | ✅ | | [Combo Keys](features/combos.md) | ✅ | | ✅ | | Macros | 🚧 | ✅ | ✅ | diff --git a/docs/sidebars.js b/docs/sidebars.js index 38256219..090dcb0f 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -16,6 +16,7 @@ module.exports = { "features/displays", "features/encoders", "features/underglow", + "features/backlight", "features/beta-testing", ], Behaviors: [ @@ -31,7 +32,8 @@ module.exports = { "behaviors/reset", "behaviors/bluetooth", "behaviors/outputs", - "behaviors/lighting", + "behaviors/underglow", + "behaviors/backlight", "behaviors/power", ], Codes: [ From f8bf8bffd54b8394a45dbbae69b1e3f7dc728cd0 Mon Sep 17 00:00:00 2001 From: Alessandro Bortolin Date: Sat, 9 Oct 2021 18:25:09 +0200 Subject: [PATCH 26/48] feat(docs): add backlight to power profiler --- docs/src/components/power-estimate.js | 34 ++++++++- docs/src/data/power.js | 12 +++ docs/src/pages/power-profiler.js | 101 +++++++++++++++++++++++++- schema/hardware-metadata.schema.json | 1 + 4 files changed, 146 insertions(+), 2 deletions(-) diff --git a/docs/src/components/power-estimate.js b/docs/src/components/power-estimate.js index 26198626..2c0a53cd 100644 --- a/docs/src/components/power-estimate.js +++ b/docs/src/components/power-estimate.js @@ -6,7 +6,12 @@ import React from "react"; import PropTypes from "prop-types"; -import { displayPower, underglowPower, zmkBase } from "../data/power"; +import { + displayPower, + underglowPower, + backlightPower, + zmkBase, +} from "../data/power"; import "../css/power-estimate.css"; // Average monthly discharge percent @@ -82,6 +87,7 @@ function PowerEstimate({ batteryMilliAh, usage, underglow, + backlight, display, }) { if (!board || !board.powerSupply.type || !batteryMilliAh) { @@ -180,6 +186,31 @@ function PowerEstimate({ }); } + if (backlight.backlightEnabled) { + let backlightMicroA = + ((board.powerSupply.outputVoltage - backlight.backlightVoltage) / + backlight.backlightResistance) * + 1000000 * + backlight.backlightBrightness * + backlight.backlightQuantity; + + if ( + backlight.backlightBrightness > 0 && + backlight.backlightBrightness < 1 + ) { + backlightMicroA += backlightPower.pwmPower; + } + + const backlightMicroW = backlightMicroA * voltageEquivalent; + const backlightUsage = backlightMicroW * (1 - usage.percentAsleep); + + totalUsage += backlightUsage; + powerUsage.push({ + title: "Backlight", + usage: backlightUsage, + }); + } + if (display.displayEnabled && display.displayType) { const { activePercent, active, sleep } = displayPower[display.displayType]; @@ -260,6 +291,7 @@ PowerEstimate.propTypes = { batteryMilliAh: PropTypes.number, usage: PropTypes.Object, underglow: PropTypes.Object, + backlight: PropTypes.Object, display: PropTypes.Object, }; diff --git a/docs/src/data/power.js b/docs/src/data/power.js index 5fe5912c..28e4b0ed 100644 --- a/docs/src/data/power.js +++ b/docs/src/data/power.js @@ -71,6 +71,18 @@ export const underglowPower = { ledOff: 460, // Quiescent current of a WS2812B }; +export const backlightLEDs = { + White: 3.2, + Blue: 3.0, + Green: 2.2, + Yellow: 2.1, + Red: 1.8, +}; + +export const backlightPower = { + pwmPower: 510, // Estimated power consumption of PWM module +}; + export const displayPower = { // Based on GoodDisplay's 1.02in epaper EPAPER: { diff --git a/docs/src/pages/power-profiler.js b/docs/src/pages/power-profiler.js index e9699926..c2302570 100644 --- a/docs/src/pages/power-profiler.js +++ b/docs/src/pages/power-profiler.js @@ -11,7 +11,7 @@ import styles from "./styles.module.css"; import PowerEstimate from "../components/power-estimate"; import CustomBoardForm from "../components/custom-board-form"; import { useInput } from "../utils/hooks"; -import { zmkBoards } from "../data/power"; +import { zmkBoards, backlightLEDs } from "../data/power"; import "../css/power-profiler.css"; const Disclaimer = `This profiler makes many assumptions about typing @@ -41,6 +41,17 @@ function PowerProfiler() { const { value: glowQuantity, bind: bindGlowQuantity } = useInput(10); const { value: glowBrightness, bind: bindGlowBrightness } = useInput(1); + const { value: backlightEnabled, bind: bindBacklightEnabled } = + useInput(false); + const { value: backlightQuantity, bind: bindBacklightQuantity } = + useInput(60); + const { value: backlightColor, bind: bindBacklightColor } = useInput(""); + const { value: backlightVoltage, bind: bindBacklightVoltage } = useInput(2.2); + const { value: backlightResistance, bind: bindBacklightResistance } = + useInput(100); + const { value: backlightBrightness, bind: bindBacklightBrightness } = + useInput(1); + const { value: displayEnabled, bind: bindDisplayEnabled } = useInput(false); const { value: displayType, bind: bindDisplayType } = useInput(""); @@ -63,6 +74,11 @@ function PowerProfiler() { } : zmkBoards[board]; + const currentBacklightVoltage = + backlightColor === "custom" + ? backlightVoltage + : backlightLEDs[backlightColor || "White"]; + return ( )} +
+
+ + +
@@ -244,6 +322,13 @@ function PowerProfiler() { batteryMilliAh={batteryMilliAh} usage={{ bondedQty, percentAsleep }} underglow={{ glowEnabled, glowBrightness, glowQuantity }} + backlight={{ + backlightEnabled, + backlightVoltage: currentBacklightVoltage, + backlightResistance, + backlightBrightness, + backlightQuantity, + }} display={{ displayEnabled, displayType }} /> @@ -262,6 +354,13 @@ function PowerProfiler() { batteryMilliAh={batteryMilliAh} usage={{ bondedQty, percentAsleep }} underglow={{ glowEnabled, glowBrightness, glowQuantity }} + backlight={{ + backlightEnabled, + backlightVoltage: currentBacklightVoltage, + backlightResistance, + backlightBrightness, + backlightQuantity, + }} display={{ displayEnabled, displayType }} /> )} diff --git a/schema/hardware-metadata.schema.json b/schema/hardware-metadata.schema.json index a74c6ef1..49755749 100644 --- a/schema/hardware-metadata.schema.json +++ b/schema/hardware-metadata.schema.json @@ -55,6 +55,7 @@ "display", "encoder", "underglow", + "backlight", "pointer" ] } From 5614a8bb80e24f7640f0e9f1f82dc41098cded4d Mon Sep 17 00:00:00 2001 From: ReFil <31960031+ReFil@users.noreply.github.com> Date: Mon, 20 Dec 2021 09:40:19 +0000 Subject: [PATCH 27/48] feat(backlight): initial split support --- app/dts/behaviors/backlight.dtsi | 2 +- .../behaviors/zmk,behavior-backlight.yaml | 2 +- app/include/dt-bindings/zmk/backlight.h | 18 ++- app/include/zmk/backlight.h | 13 +- app/src/backlight.c | 114 ++++++++++-------- app/src/behaviors/behavior_backlight.c | 51 ++++++-- 6 files changed, 128 insertions(+), 72 deletions(-) diff --git a/app/dts/behaviors/backlight.dtsi b/app/dts/behaviors/backlight.dtsi index b05d97ae..6127f605 100644 --- a/app/dts/behaviors/backlight.dtsi +++ b/app/dts/behaviors/backlight.dtsi @@ -9,7 +9,7 @@ /omit-if-no-ref/ bl: behavior_backlight { compatible = "zmk,behavior-backlight"; label = "BACKLIGHT"; - #binding-cells = <1>; + #binding-cells = <2>; }; }; }; diff --git a/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml b/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml index e035e15e..159a7c70 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml @@ -5,4 +5,4 @@ description: Backlight behavior compatible: "zmk,behavior-backlight" -include: one_param.yaml +include: two_param.yaml diff --git a/app/include/dt-bindings/zmk/backlight.h b/app/include/dt-bindings/zmk/backlight.h index c33e4344..70572437 100644 --- a/app/include/dt-bindings/zmk/backlight.h +++ b/app/include/dt-bindings/zmk/backlight.h @@ -4,8 +4,16 @@ * SPDX-License-Identifier: MIT */ -#define BL_TOG 0 -#define BL_ON 1 -#define BL_OFF 2 -#define BL_INC 3 -#define BL_DEC 4 +#define BL_TOG_CMD 0 +#define BL_ON_CMD 1 +#define BL_OFF_CMD 2 +#define BL_INC_CMD 3 +#define BL_DEC_CMD 4 +#define BL_SET_CMD 5 + +#define BL_TOG BL_TOG_CMD 0 +#define BL_ON BL_ON_CMD 0 +#define BL_OFF BL_OFF_CMD 0 +#define BL_INC BL_INC_CMD 0 +#define BL_DEC BL_DEC_CMD 0 +#define BL_SET BL_SET_CMD diff --git a/app/include/zmk/backlight.h b/app/include/zmk/backlight.h index 817efe7a..8711d884 100644 --- a/app/include/zmk/backlight.h +++ b/app/include/zmk/backlight.h @@ -6,14 +6,11 @@ #pragma once -int zmk_backlight_set_on(bool on); -bool zmk_backlight_is_on(); - -int zmk_backlight_set_brt(int brt); -int zmk_backlight_get_brt(); - int zmk_backlight_toggle(); +bool zmk_backlight_get_on(); int zmk_backlight_on(); int zmk_backlight_off(); -int zmk_backlight_inc(); -int zmk_backlight_dec(); +uint8_t zmk_backlight_calc_brt(int direction); +int zmk_backlight_set_brt(uint8_t brightness); +int zmk_backlight_adjust_brt(int direction); +int zmk_backlight_get_brt(); diff --git a/app/src/backlight.c b/app/src/backlight.c index 517e6133..fc8831c7 100644 --- a/app/src/backlight.c +++ b/app/src/backlight.c @@ -32,6 +32,8 @@ static const struct device *const backlight_dev = DEVICE_DT_GET(DT_CHOSEN(zmk_ba #define BACKLIGHT_NUM_LEDS (DT_NUM_CHILD(DT_CHOSEN(zmk_backlight))) +#define BRT_MAX 100 + struct backlight_state { uint8_t brightness; bool on; @@ -80,16 +82,7 @@ static void zmk_backlight_save_state_work() { } static struct k_delayed_work backlight_save_work; -#endif // IS_ENABLED(CONFIG_SETTINGS) - -static int zmk_backlight_save_state() { -#if IS_ENABLED(CONFIG_SETTINGS) - k_delayed_work_cancel(&backlight_save_work); - return k_delayed_work_submit(&backlight_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); -#else - return 0; #endif -} static int zmk_backlight_init(const struct device *_arg) { if (!device_is_ready(backlight_dev)) { @@ -114,11 +107,22 @@ static int zmk_backlight_init(const struct device *_arg) { return zmk_backlight_update(); } -int zmk_backlight_set_on(bool on) { +static int zmk_backlight_save_state() { +#if IS_ENABLED(CONFIG_SETTINGS) + k_delayed_work_cancel(&backlight_save_work); + return k_delayed_work_submit(&backlight_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); +#else + return 0; +#endif +} + +bool zmk_backlight_get_on() { return state.on; } + +int zmk_backlight_on() { if (!state.on && state.brightness == 0) { state.brightness = CONFIG_ZMK_BACKLIGHT_BRT_STEP; } - state.on = on; + state.on = true; int rc = zmk_backlight_update(); if (rc != 0) { @@ -128,11 +132,9 @@ int zmk_backlight_set_on(bool on) { return zmk_backlight_save_state(); } -bool zmk_backlight_is_on() { return state.on; } +int zmk_backlight_off() { -int zmk_backlight_set_brt(int brt) { - state.on = (brt > 0); - state.brightness = CLAMP(brt, 0, 100); + state.on = false; int rc = zmk_backlight_update(); if (rc != 0) { @@ -144,21 +146,42 @@ int zmk_backlight_set_brt(int brt) { int zmk_backlight_get_brt() { return state.on ? state.brightness : 0; } -int zmk_backlight_toggle() { return zmk_backlight_set_on(!state.on); } +int zmk_backlight_toggle() { return state.on ? zmk_backlight_off() : zmk_backlight_on(); } -int zmk_backlight_on() { return zmk_backlight_set_on(true); } - -int zmk_backlight_off() { return zmk_backlight_set_on(false); } - -int zmk_backlight_inc() { - if (!state.on) { - return zmk_backlight_set_brt(MAX(state.brightness, CONFIG_ZMK_BACKLIGHT_BRT_STEP)); +int zmk_backlight_set_brt(uint8_t brightness) { + if (brightness > BRT_MAX) { + brightness = BRT_MAX; } - return zmk_backlight_set_brt(state.brightness + CONFIG_ZMK_BACKLIGHT_BRT_STEP); + + state.brightness = brightness; + state.on = (brightness > 0); + + int rc = zmk_backlight_update(); + if (rc != 0) { + return rc; + } + + return zmk_backlight_save_state(); } -int zmk_backlight_dec() { - return zmk_backlight_set_brt(state.brightness - CONFIG_ZMK_BACKLIGHT_BRT_STEP); +uint8_t zmk_backlight_calc_brt(int direction) { + uint8_t brightness = state.brightness; + + int b = state.brightness + (direction * CONFIG_ZMK_BACKLIGHT_BRT_STEP); + return CLAMP(b, 0, BRT_MAX); +} + +int zmk_backlight_adjust_brt(int direction) { + + state.brightness = zmk_backlight_calc_brt(direction); + state.on = (state.brightness > 0); + + int rc = zmk_backlight_update(); + if (rc != 0) { + return rc; + } + + return zmk_backlight_save_state(); } #if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) @@ -170,39 +193,34 @@ static bool auto_off_usb_prev_state = false; #endif #if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) || IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) +static int backlight_auto_state(bool *prev_state, bool *new_state) { + if (state.on == *new_state) { + return 0; + } + if (*new_state) { + state.on = *prev_state; + *prev_state = false; + return zmk_backlight_on(); + } else { + state.on = false; + *prev_state = true; + return zmk_backlight_off(); + } +} + static int backlight_event_listener(const zmk_event_t *eh) { #if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) if (as_zmk_activity_state_changed(eh)) { bool new_state = (zmk_activity_get_state() == ZMK_ACTIVITY_ACTIVE); - if (state.on == new_state) { - return 0; - } - if (new_state) { - state.on = auto_off_idle_prev_state; - auto_off_idle_prev_state = false; - } else { - state.on = false; - auto_off_idle_prev_state = true; - } - return zmk_backlight_update(); + return backlight_auto_state(&auto_off_idle_prev_state, &new_state); } #endif #if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) if (as_zmk_usb_conn_state_changed(eh)) { bool new_state = zmk_usb_is_powered(); - if (state.on == new_state) { - return 0; - } - if (new_state) { - state.on = auto_off_usb_prev_state; - auto_off_usb_prev_state = false; - } else { - state.on = false; - auto_off_usb_prev_state = true; - } - return zmk_backlight_update(); + return backlight_auto_state(&auto_off_usb_prev_state, &new_state); } #endif diff --git a/app/src/behaviors/behavior_backlight.c b/app/src/behaviors/behavior_backlight.c index 8d921f45..3dcbd3c4 100644 --- a/app/src/behaviors/behavior_backlight.c +++ b/app/src/behaviors/behavior_backlight.c @@ -20,21 +20,52 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int behavior_backlight_init(const struct device *dev) { return 0; } +static int +on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case BL_TOG_CMD: { + binding->param1 = zmk_backlight_get_on() ? BL_OFF_CMD : BL_ON_CMD; + break; + } + case BL_INC_CMD: { + uint8_t brightness = zmk_backlight_calc_brt(1); + + binding->param1 = BL_SET_CMD; + binding->param2 = brightness; + break; + } + case BL_DEC_CMD: { + uint8_t brightness = zmk_backlight_calc_brt(-1); + + binding->param1 = BL_SET_CMD; + binding->param2 = brightness; + break; + } + default: + return 0; + } + + LOG_DBG("Backlight relative to absolute (%d/%d)", binding->param1, binding->param2); + + return 0; +} + static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { switch (binding->param1) { - case BL_TOG: + case BL_TOG_CMD: return zmk_backlight_toggle(); - case BL_ON: + case BL_ON_CMD: return zmk_backlight_on(); - case BL_OFF: + case BL_OFF_CMD: return zmk_backlight_off(); - case BL_INC: - return zmk_backlight_inc(); - case BL_DEC: - return zmk_backlight_dec(); - default: - LOG_ERR("Unknown backlight command: %d", binding->param1); + case BL_INC_CMD: + return zmk_backlight_adjust_brt(1); + case BL_DEC_CMD: + return zmk_backlight_adjust_brt(-1); + case BL_SET_CMD: + return zmk_backlight_set_brt(binding->param2); } return -ENOTSUP; @@ -46,6 +77,8 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding, } static const struct behavior_driver_api behavior_backlight_driver_api = { + .binding_convert_central_state_dependent_params = + on_keymap_binding_convert_central_state_dependent_params, .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released, }; From ce843825e8343354d3e9bcc497adcc898602b294 Mon Sep 17 00:00:00 2001 From: Alessandro Bortolin Date: Mon, 20 Dec 2021 11:00:22 +0100 Subject: [PATCH 28/48] refactor(backlight): code cleanup --- app/Kconfig | 2 - app/dts/behaviors/backlight.dtsi | 2 +- app/include/dt-bindings/zmk/backlight.h | 8 +- app/include/zmk/backlight.h | 10 +- app/src/backlight.c | 137 +++++++----------------- app/src/behaviors/behavior_backlight.c | 37 ++++--- docs/docs/features/backlight.md | 4 +- 7 files changed, 67 insertions(+), 133 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index 49eec835..02fef66a 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -352,11 +352,9 @@ config ZMK_BACKLIGHT_ON_START config ZMK_BACKLIGHT_AUTO_OFF_IDLE bool "Turn off backlight when keyboard goes into idle state" - default y config ZMK_BACKLIGHT_AUTO_OFF_USB bool "Turn off backlight when USB is disconnected" - default n #ZMK_BACKLIGHT endif diff --git a/app/dts/behaviors/backlight.dtsi b/app/dts/behaviors/backlight.dtsi index 6127f605..f9bd02b8 100644 --- a/app/dts/behaviors/backlight.dtsi +++ b/app/dts/behaviors/backlight.dtsi @@ -8,7 +8,7 @@ behaviors { /omit-if-no-ref/ bl: behavior_backlight { compatible = "zmk,behavior-backlight"; - label = "BACKLIGHT"; + label = "BCKLGHT"; #binding-cells = <2>; }; }; diff --git a/app/include/dt-bindings/zmk/backlight.h b/app/include/dt-bindings/zmk/backlight.h index 70572437..fa6dc9b1 100644 --- a/app/include/dt-bindings/zmk/backlight.h +++ b/app/include/dt-bindings/zmk/backlight.h @@ -4,16 +4,16 @@ * SPDX-License-Identifier: MIT */ -#define BL_TOG_CMD 0 -#define BL_ON_CMD 1 -#define BL_OFF_CMD 2 +#define BL_ON_CMD 0 +#define BL_OFF_CMD 1 +#define BL_TOG_CMD 2 #define BL_INC_CMD 3 #define BL_DEC_CMD 4 #define BL_SET_CMD 5 -#define BL_TOG BL_TOG_CMD 0 #define BL_ON BL_ON_CMD 0 #define BL_OFF BL_OFF_CMD 0 +#define BL_TOG BL_TOG_CMD 0 #define BL_INC BL_INC_CMD 0 #define BL_DEC BL_DEC_CMD 0 #define BL_SET BL_SET_CMD diff --git a/app/include/zmk/backlight.h b/app/include/zmk/backlight.h index 8711d884..dd7d966a 100644 --- a/app/include/zmk/backlight.h +++ b/app/include/zmk/backlight.h @@ -6,11 +6,11 @@ #pragma once -int zmk_backlight_toggle(); -bool zmk_backlight_get_on(); int zmk_backlight_on(); int zmk_backlight_off(); -uint8_t zmk_backlight_calc_brt(int direction); +int zmk_backlight_toggle(); +bool zmk_backlight_is_on(); + int zmk_backlight_set_brt(uint8_t brightness); -int zmk_backlight_adjust_brt(int direction); -int zmk_backlight_get_brt(); +uint8_t zmk_backlight_get_brt(); +uint8_t zmk_backlight_calc_brt(int direction); diff --git a/app/src/backlight.c b/app/src/backlight.c index fc8831c7..6ef7f8f0 100644 --- a/app/src/backlight.c +++ b/app/src/backlight.c @@ -43,10 +43,11 @@ static struct backlight_state state = {.brightness = CONFIG_ZMK_BACKLIGHT_BRT_ST .on = IS_ENABLED(CONFIG_ZMK_BACKLIGHT_ON_START)}; static int zmk_backlight_update() { - uint8_t brt = state.on ? state.brightness : 0; + uint8_t brt = zmk_backlight_get_brt(); for (int i = 0; i < BACKLIGHT_NUM_LEDS; i++) { int rc = led_set_brightness(backlight_dev, i, brt); if (rc != 0) { + LOG_ERR("Failed to update backlight LED %d: %d", i, rc); return rc; } } @@ -54,34 +55,25 @@ static int zmk_backlight_update() { } #if IS_ENABLED(CONFIG_SETTINGS) -static int backlight_settings_set(const char *name, size_t len, settings_read_cb read_cb, - void *cb_arg) { +static int backlight_settings_load_cb(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg, void *param) { const char *next; - if (settings_name_steq(name, "state", &next) && !next) { if (len != sizeof(state)) { return -EINVAL; } int rc = read_cb(cb_arg, &state, sizeof(state)); - if (rc < 0) { - return rc; - } - - return zmk_backlight_update(); + return MIN(rc, 0); } - return -ENOENT; } -static struct settings_handler backlight_conf = {.name = "backlight", - .h_set = backlight_settings_set}; - -static void zmk_backlight_save_state_work() { +static void backlight_save_work_handler(struct k_work *work) { settings_save_one("backlight/state", &state, sizeof(state)); } -static struct k_delayed_work backlight_save_work; +static K_DELAYED_WORK_DEFINE(backlight_save_work, backlight_save_work_handler); #endif static int zmk_backlight_init(const struct device *_arg) { @@ -92,22 +84,21 @@ static int zmk_backlight_init(const struct device *_arg) { #if IS_ENABLED(CONFIG_SETTINGS) settings_subsys_init(); - - int err = settings_register(&backlight_conf); - if (err) { - LOG_ERR("Failed to register the backlight settings handler (err %d)", err); - return err; + int rc = settings_load_subtree_direct("backlight", backlight_settings_load_cb, NULL); + if (rc != 0) { + LOG_ERR("Failed to load backlight settings: %d", rc); } - - k_delayed_work_init(&backlight_save_work, zmk_backlight_save_state_work); - - settings_load_subtree("backlight"); #endif return zmk_backlight_update(); } -static int zmk_backlight_save_state() { +static int zmk_backlight_update_and_save() { + int rc = zmk_backlight_update(); + if (rc != 0) { + return rc; + } + #if IS_ENABLED(CONFIG_SETTINGS) k_delayed_work_cancel(&backlight_save_work); return k_delayed_work_submit(&backlight_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); @@ -116,111 +107,57 @@ static int zmk_backlight_save_state() { #endif } -bool zmk_backlight_get_on() { return state.on; } - int zmk_backlight_on() { - if (!state.on && state.brightness == 0) { - state.brightness = CONFIG_ZMK_BACKLIGHT_BRT_STEP; - } + state.brightness = MAX(state.brightness, CONFIG_ZMK_BACKLIGHT_BRT_STEP); state.on = true; - - int rc = zmk_backlight_update(); - if (rc != 0) { - return rc; - } - - return zmk_backlight_save_state(); + return zmk_backlight_update_and_save(); } int zmk_backlight_off() { - state.on = false; - - int rc = zmk_backlight_update(); - if (rc != 0) { - return rc; - } - - return zmk_backlight_save_state(); + return zmk_backlight_update_and_save(); } -int zmk_backlight_get_brt() { return state.on ? state.brightness : 0; } - int zmk_backlight_toggle() { return state.on ? zmk_backlight_off() : zmk_backlight_on(); } +bool zmk_backlight_is_on() { return state.on; } + int zmk_backlight_set_brt(uint8_t brightness) { - if (brightness > BRT_MAX) { - brightness = BRT_MAX; - } - - state.brightness = brightness; - state.on = (brightness > 0); - - int rc = zmk_backlight_update(); - if (rc != 0) { - return rc; - } - - return zmk_backlight_save_state(); + state.brightness = MIN(brightness, BRT_MAX); + state.on = (state.brightness > 0); + return zmk_backlight_update_and_save(); } +uint8_t zmk_backlight_get_brt() { return state.on ? state.brightness : 0; } + uint8_t zmk_backlight_calc_brt(int direction) { - uint8_t brightness = state.brightness; - - int b = state.brightness + (direction * CONFIG_ZMK_BACKLIGHT_BRT_STEP); - return CLAMP(b, 0, BRT_MAX); + int brt = state.brightness + (direction * CONFIG_ZMK_BACKLIGHT_BRT_STEP); + return CLAMP(brt, 0, BRT_MAX); } -int zmk_backlight_adjust_brt(int direction) { - - state.brightness = zmk_backlight_calc_brt(direction); - state.on = (state.brightness > 0); - - int rc = zmk_backlight_update(); - if (rc != 0) { - return rc; - } - - return zmk_backlight_save_state(); -} - -#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) -static bool auto_off_idle_prev_state = false; -#endif - -#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) -static bool auto_off_usb_prev_state = false; -#endif - #if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) || IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) -static int backlight_auto_state(bool *prev_state, bool *new_state) { - if (state.on == *new_state) { +static int backlight_auto_state(bool *prev_state, bool new_state) { + if (state.on == new_state) { return 0; } - if (*new_state) { - state.on = *prev_state; - *prev_state = false; - return zmk_backlight_on(); - } else { - state.on = false; - *prev_state = true; - return zmk_backlight_off(); - } + state.on = new_state && *prev_state; + *prev_state = !new_state; + return zmk_backlight_update(); } static int backlight_event_listener(const zmk_event_t *eh) { #if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) if (as_zmk_activity_state_changed(eh)) { - bool new_state = (zmk_activity_get_state() == ZMK_ACTIVITY_ACTIVE); - return backlight_auto_state(&auto_off_idle_prev_state, &new_state); + static bool prev_state = false; + return backlight_auto_state(&prev_state, zmk_activity_get_state() == ZMK_ACTIVITY_ACTIVE); } #endif #if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) if (as_zmk_usb_conn_state_changed(eh)) { - bool new_state = zmk_usb_is_powered(); - return backlight_auto_state(&auto_off_usb_prev_state, &new_state); + static bool prev_state = false; + return backlight_auto_state(&prev_state, zmk_usb_is_powered()); } #endif diff --git a/app/src/behaviors/behavior_backlight.c b/app/src/behaviors/behavior_backlight.c index 3dcbd3c4..8dd6ee58 100644 --- a/app/src/behaviors/behavior_backlight.c +++ b/app/src/behaviors/behavior_backlight.c @@ -24,24 +24,17 @@ static int on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { switch (binding->param1) { - case BL_TOG_CMD: { - binding->param1 = zmk_backlight_get_on() ? BL_OFF_CMD : BL_ON_CMD; + case BL_TOG_CMD: + binding->param1 = zmk_backlight_is_on() ? BL_OFF_CMD : BL_ON_CMD; break; - } - case BL_INC_CMD: { - uint8_t brightness = zmk_backlight_calc_brt(1); - + case BL_INC_CMD: binding->param1 = BL_SET_CMD; - binding->param2 = brightness; + binding->param2 = zmk_backlight_calc_brt(1); break; - } - case BL_DEC_CMD: { - uint8_t brightness = zmk_backlight_calc_brt(-1); - + case BL_DEC_CMD: binding->param1 = BL_SET_CMD; - binding->param2 = brightness; + binding->param2 = zmk_backlight_calc_brt(-1); break; - } default: return 0; } @@ -54,18 +47,24 @@ on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_bin static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { switch (binding->param1) { - case BL_TOG_CMD: - return zmk_backlight_toggle(); case BL_ON_CMD: return zmk_backlight_on(); case BL_OFF_CMD: return zmk_backlight_off(); - case BL_INC_CMD: - return zmk_backlight_adjust_brt(1); - case BL_DEC_CMD: - return zmk_backlight_adjust_brt(-1); + case BL_TOG_CMD: + return zmk_backlight_toggle(); + case BL_INC_CMD: { + uint8_t brt = zmk_backlight_calc_brt(1); + return zmk_backlight_set_brt(brt); + } + case BL_DEC_CMD: { + uint8_t brt = zmk_backlight_calc_brt(-1); + return zmk_backlight_set_brt(brt); + } case BL_SET_CMD: return zmk_backlight_set_brt(binding->param2); + default: + LOG_ERR("Unknown backlight command: %d", binding->param1); } return -ENOTSUP; diff --git a/docs/docs/features/backlight.md b/docs/docs/features/backlight.md index a917b166..f43c7357 100644 --- a/docs/docs/features/backlight.md +++ b/docs/docs/features/backlight.md @@ -24,7 +24,7 @@ There are various Kconfig options used to configure the backlight feature. These | `CONFIG_ZMK_BACKLIGHT_BRT_STEP` | Brightness step in percent | 20 | | `CONFIG_ZMK_BACKLIGHT_BRT_START` | Default brightness in percent | 40 | | `CONFIG_ZMK_BACKLIGHT_ON_START` | Default backlight state | y | -| `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE` | Turn off backlight when keyboard goes into idle state | y | +| `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE` | Turn off backlight when keyboard goes into idle state | n | | `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB` | Turn off backlight when USB is disconnected | n | ## Adding Backlight to a Board @@ -43,7 +43,7 @@ First, you need to enable PWM by adding the following lines to your `.overlay` f }; ``` -The value `ch0-pin` represents the pin that controls the LEDs. To calculate the value to use, you need a bit of math. You need the hardware port and run it through a function. +The value `ch0-pin` represents the pin that controls the LEDs. With nRF52 boards, you can calculate the value to use in the following way: you need the hardware port and run it through a function. **32 \* X + Y** = `` where X is first part of the hardware port "PX.01" and Y is the second part of the hardware port "P1.Y". For example, _P1.13_ would give you _32 \* 1 + 13_ = `<45>` and _P0.15_ would give you _32 \* 0 + 15_ = `<15>`. From 2c0fe3934d461fe8b565f90f3c5d092ba231caf1 Mon Sep 17 00:00:00 2001 From: Alessandro Bortolin Date: Mon, 20 Dec 2021 13:58:31 +0100 Subject: [PATCH 29/48] feat(backlight): add tests --- app/Kconfig | 2 - app/src/backlight.c | 2 + app/tests/backlight/basic/events.patterns | 1 + .../backlight/basic/keycode_events.snapshot | 9 +++++ app/tests/backlight/basic/native_posix.conf | 14 +++++++ app/tests/backlight/basic/native_posix.keymap | 30 ++++++++++++++ app/tests/backlight/behavior_keymap.dtsi | 34 ++++++++++++++++ .../backlight/config-brt/events.patterns | 1 + .../config-brt/keycode_events.snapshot | 3 ++ .../backlight/config-brt/native_posix.conf | 15 +++++++ .../backlight/config-brt/native_posix.keymap | 12 ++++++ app/tests/backlight/config-on/events.patterns | 1 + .../config-on/keycode_events.snapshot | 3 ++ .../backlight/config-on/native_posix.conf | 15 +++++++ .../backlight/config-on/native_posix.keymap | 12 ++++++ .../backlight/config-step/events.patterns | 1 + .../config-step/keycode_events.snapshot | 11 ++++++ .../backlight/config-step/native_posix.conf | 16 ++++++++ .../backlight/config-step/native_posix.keymap | 36 +++++++++++++++++ .../backlight/low-brightness/events.patterns | 1 + .../low-brightness/keycode_events.snapshot | 12 ++++++ .../low-brightness/native_posix.conf | 14 +++++++ .../low-brightness/native_posix.keymap | 39 +++++++++++++++++++ docs/docs/features/backlight.md | 4 +- 24 files changed, 285 insertions(+), 3 deletions(-) create mode 100644 app/tests/backlight/basic/events.patterns create mode 100644 app/tests/backlight/basic/keycode_events.snapshot create mode 100644 app/tests/backlight/basic/native_posix.conf create mode 100644 app/tests/backlight/basic/native_posix.keymap create mode 100644 app/tests/backlight/behavior_keymap.dtsi create mode 100644 app/tests/backlight/config-brt/events.patterns create mode 100644 app/tests/backlight/config-brt/keycode_events.snapshot create mode 100644 app/tests/backlight/config-brt/native_posix.conf create mode 100644 app/tests/backlight/config-brt/native_posix.keymap create mode 100644 app/tests/backlight/config-on/events.patterns create mode 100644 app/tests/backlight/config-on/keycode_events.snapshot create mode 100644 app/tests/backlight/config-on/native_posix.conf create mode 100644 app/tests/backlight/config-on/native_posix.keymap create mode 100644 app/tests/backlight/config-step/events.patterns create mode 100644 app/tests/backlight/config-step/keycode_events.snapshot create mode 100644 app/tests/backlight/config-step/native_posix.conf create mode 100644 app/tests/backlight/config-step/native_posix.keymap create mode 100644 app/tests/backlight/low-brightness/events.patterns create mode 100644 app/tests/backlight/low-brightness/keycode_events.snapshot create mode 100644 app/tests/backlight/low-brightness/native_posix.conf create mode 100644 app/tests/backlight/low-brightness/native_posix.keymap diff --git a/app/Kconfig b/app/Kconfig index 02fef66a..1c9f929d 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -330,9 +330,7 @@ endif menuconfig ZMK_BACKLIGHT bool "LED backlight" - select PWM select LED - select ZMK_LED_PWM if ZMK_BACKLIGHT diff --git a/app/src/backlight.c b/app/src/backlight.c index 6ef7f8f0..46e3c9e3 100644 --- a/app/src/backlight.c +++ b/app/src/backlight.c @@ -44,6 +44,8 @@ static struct backlight_state state = {.brightness = CONFIG_ZMK_BACKLIGHT_BRT_ST static int zmk_backlight_update() { uint8_t brt = zmk_backlight_get_brt(); + LOG_DBG("Update backlight brightness: %d%%", brt); + for (int i = 0; i < BACKLIGHT_NUM_LEDS; i++) { int rc = led_set_brightness(backlight_dev, i, brt); if (rc != 0) { diff --git a/app/tests/backlight/basic/events.patterns b/app/tests/backlight/basic/events.patterns new file mode 100644 index 00000000..bb11bc15 --- /dev/null +++ b/app/tests/backlight/basic/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/basic/keycode_events.snapshot b/app/tests/backlight/basic/keycode_events.snapshot new file mode 100644 index 00000000..4aa184cd --- /dev/null +++ b/app/tests/backlight/basic/keycode_events.snapshot @@ -0,0 +1,9 @@ +Update backlight brightness: 40% +Update backlight brightness: 60% +Update backlight brightness: 80% +Update backlight brightness: 60% +Update backlight brightness: 40% +Update backlight brightness: 0% +Update backlight brightness: 0% +Update backlight brightness: 40% +Update backlight brightness: 40% diff --git a/app/tests/backlight/basic/native_posix.conf b/app/tests/backlight/basic/native_posix.conf new file mode 100644 index 00000000..565121d3 --- /dev/null +++ b/app/tests/backlight/basic/native_posix.conf @@ -0,0 +1,14 @@ +CONFIG_KSCAN=n +CONFIG_ZMK_KSCAN_MOCK_DRIVER=y +CONFIG_ZMK_KSCAN_GPIO_DRIVER=n +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y diff --git a/app/tests/backlight/basic/native_posix.keymap b/app/tests/backlight/basic/native_posix.keymap new file mode 100644 index 00000000..185dbf7c --- /dev/null +++ b/app/tests/backlight/basic/native_posix.keymap @@ -0,0 +1,30 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* BL_ON */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* BL_ON */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/backlight/behavior_keymap.dtsi b/app/tests/backlight/behavior_keymap.dtsi new file mode 100644 index 00000000..26869272 --- /dev/null +++ b/app/tests/backlight/behavior_keymap.dtsi @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +/ { + chosen { + zmk,backlight = &backlight; + }; + + backlight: leds { + compatible = "gpio-leds"; + led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Backlight LED 0"; + }; + led_1 { + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + label = "Backlight LED 1"; + }; + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &bl BL_INC &bl BL_DEC + &bl BL_ON &bl BL_OFF + >; + }; + }; +}; diff --git a/app/tests/backlight/config-brt/events.patterns b/app/tests/backlight/config-brt/events.patterns new file mode 100644 index 00000000..bb11bc15 --- /dev/null +++ b/app/tests/backlight/config-brt/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/config-brt/keycode_events.snapshot b/app/tests/backlight/config-brt/keycode_events.snapshot new file mode 100644 index 00000000..3297a7cd --- /dev/null +++ b/app/tests/backlight/config-brt/keycode_events.snapshot @@ -0,0 +1,3 @@ +Update backlight brightness: 60% +Update backlight brightness: 80% +Update backlight brightness: 60% diff --git a/app/tests/backlight/config-brt/native_posix.conf b/app/tests/backlight/config-brt/native_posix.conf new file mode 100644 index 00000000..0d0758c0 --- /dev/null +++ b/app/tests/backlight/config-brt/native_posix.conf @@ -0,0 +1,15 @@ +CONFIG_KSCAN=n +CONFIG_ZMK_KSCAN_MOCK_DRIVER=y +CONFIG_ZMK_KSCAN_GPIO_DRIVER=n +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_BRT_START=60 diff --git a/app/tests/backlight/config-brt/native_posix.keymap b/app/tests/backlight/config-brt/native_posix.keymap new file mode 100644 index 00000000..6617c9f6 --- /dev/null +++ b/app/tests/backlight/config-brt/native_posix.keymap @@ -0,0 +1,12 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/backlight/config-on/events.patterns b/app/tests/backlight/config-on/events.patterns new file mode 100644 index 00000000..bb11bc15 --- /dev/null +++ b/app/tests/backlight/config-on/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/config-on/keycode_events.snapshot b/app/tests/backlight/config-on/keycode_events.snapshot new file mode 100644 index 00000000..8797af58 --- /dev/null +++ b/app/tests/backlight/config-on/keycode_events.snapshot @@ -0,0 +1,3 @@ +Update backlight brightness: 0% +Update backlight brightness: 40% +Update backlight brightness: 0% diff --git a/app/tests/backlight/config-on/native_posix.conf b/app/tests/backlight/config-on/native_posix.conf new file mode 100644 index 00000000..241c66a7 --- /dev/null +++ b/app/tests/backlight/config-on/native_posix.conf @@ -0,0 +1,15 @@ +CONFIG_KSCAN=n +CONFIG_ZMK_KSCAN_MOCK_DRIVER=y +CONFIG_ZMK_KSCAN_GPIO_DRIVER=n +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_ON_START=n diff --git a/app/tests/backlight/config-on/native_posix.keymap b/app/tests/backlight/config-on/native_posix.keymap new file mode 100644 index 00000000..a95ccd93 --- /dev/null +++ b/app/tests/backlight/config-on/native_posix.keymap @@ -0,0 +1,12 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_ON */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + >; +}; diff --git a/app/tests/backlight/config-step/events.patterns b/app/tests/backlight/config-step/events.patterns new file mode 100644 index 00000000..bb11bc15 --- /dev/null +++ b/app/tests/backlight/config-step/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/config-step/keycode_events.snapshot b/app/tests/backlight/config-step/keycode_events.snapshot new file mode 100644 index 00000000..4532fed4 --- /dev/null +++ b/app/tests/backlight/config-step/keycode_events.snapshot @@ -0,0 +1,11 @@ +Update backlight brightness: 60% +Update backlight brightness: 90% +Update backlight brightness: 100% +Update backlight brightness: 100% +Update backlight brightness: 70% +Update backlight brightness: 40% +Update backlight brightness: 10% +Update backlight brightness: 0% +Update backlight brightness: 0% +Update backlight brightness: 30% +Update backlight brightness: 60% diff --git a/app/tests/backlight/config-step/native_posix.conf b/app/tests/backlight/config-step/native_posix.conf new file mode 100644 index 00000000..4df7a861 --- /dev/null +++ b/app/tests/backlight/config-step/native_posix.conf @@ -0,0 +1,16 @@ +CONFIG_KSCAN=n +CONFIG_ZMK_KSCAN_MOCK_DRIVER=y +CONFIG_ZMK_KSCAN_GPIO_DRIVER=n +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_BRT_START=60 +CONFIG_ZMK_BACKLIGHT_BRT_STEP=30 diff --git a/app/tests/backlight/config-step/native_posix.keymap b/app/tests/backlight/config-step/native_posix.keymap new file mode 100644 index 00000000..96fbe96a --- /dev/null +++ b/app/tests/backlight/config-step/native_posix.keymap @@ -0,0 +1,36 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/backlight/low-brightness/events.patterns b/app/tests/backlight/low-brightness/events.patterns new file mode 100644 index 00000000..bb11bc15 --- /dev/null +++ b/app/tests/backlight/low-brightness/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/low-brightness/keycode_events.snapshot b/app/tests/backlight/low-brightness/keycode_events.snapshot new file mode 100644 index 00000000..9fee3247 --- /dev/null +++ b/app/tests/backlight/low-brightness/keycode_events.snapshot @@ -0,0 +1,12 @@ +Update backlight brightness: 40% +Update backlight brightness: 20% +Update backlight brightness: 0% +Update backlight brightness: 20% +Update backlight brightness: 0% +Update backlight brightness: 40% +Update backlight brightness: 60% +Update backlight brightness: 0% +Update backlight brightness: 40% +Update backlight brightness: 20% +Update backlight brightness: 0% +Update backlight brightness: 20% diff --git a/app/tests/backlight/low-brightness/native_posix.conf b/app/tests/backlight/low-brightness/native_posix.conf new file mode 100644 index 00000000..565121d3 --- /dev/null +++ b/app/tests/backlight/low-brightness/native_posix.conf @@ -0,0 +1,14 @@ +CONFIG_KSCAN=n +CONFIG_ZMK_KSCAN_MOCK_DRIVER=y +CONFIG_ZMK_KSCAN_GPIO_DRIVER=n +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y diff --git a/app/tests/backlight/low-brightness/native_posix.keymap b/app/tests/backlight/low-brightness/native_posix.keymap new file mode 100644 index 00000000..3b01f700 --- /dev/null +++ b/app/tests/backlight/low-brightness/native_posix.keymap @@ -0,0 +1,39 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_ON */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/docs/docs/features/backlight.md b/docs/docs/features/backlight.md index f43c7357..379cc770 100644 --- a/docs/docs/features/backlight.md +++ b/docs/docs/features/backlight.md @@ -7,9 +7,11 @@ Backlight is a feature used to control array of LEDs, usually placed through or ## Enabling Backlight -To enable backlight on your board or shield, simply enable the `CONFIG_ZMK_BACKLIGHT` configuration values in the `.conf` file of your user config directory as such: +To enable backlight on your board or shield, add the following lines to your `.conf` file of your user config directory as such: ``` +CONFIG_PWM=y +CONFIG_LED_PWM=y CONFIG_ZMK_BACKLIGHT=y ``` From 13a45153004a63dccc421463ddac9ac9075e32cd Mon Sep 17 00:00:00 2001 From: Alessandro Bortolin Date: Sat, 22 Jan 2022 11:57:51 +0100 Subject: [PATCH 30/48] feat(backlight): add command to cycle brightness --- app/include/dt-bindings/zmk/backlight.h | 4 +- app/include/zmk/backlight.h | 1 + app/src/backlight.c | 8 ++ app/src/behaviors/behavior_backlight.c | 8 ++ app/tests/backlight/cycle/events.patterns | 1 + .../backlight/cycle/keycode_events.snapshot | 14 ++++ app/tests/backlight/cycle/native_posix.conf | 14 ++++ app/tests/backlight/cycle/native_posix.keymap | 78 +++++++++++++++++++ docs/docs/behaviors/backlight.md | 21 ++--- 9 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 app/tests/backlight/cycle/events.patterns create mode 100644 app/tests/backlight/cycle/keycode_events.snapshot create mode 100644 app/tests/backlight/cycle/native_posix.conf create mode 100644 app/tests/backlight/cycle/native_posix.keymap diff --git a/app/include/dt-bindings/zmk/backlight.h b/app/include/dt-bindings/zmk/backlight.h index fa6dc9b1..0802e2ce 100644 --- a/app/include/dt-bindings/zmk/backlight.h +++ b/app/include/dt-bindings/zmk/backlight.h @@ -9,11 +9,13 @@ #define BL_TOG_CMD 2 #define BL_INC_CMD 3 #define BL_DEC_CMD 4 -#define BL_SET_CMD 5 +#define BL_CYCLE_CMD 5 +#define BL_SET_CMD 6 #define BL_ON BL_ON_CMD 0 #define BL_OFF BL_OFF_CMD 0 #define BL_TOG BL_TOG_CMD 0 #define BL_INC BL_INC_CMD 0 #define BL_DEC BL_DEC_CMD 0 +#define BL_CYCLE BL_CYCLE_CMD 0 #define BL_SET BL_SET_CMD diff --git a/app/include/zmk/backlight.h b/app/include/zmk/backlight.h index dd7d966a..a0f52431 100644 --- a/app/include/zmk/backlight.h +++ b/app/include/zmk/backlight.h @@ -14,3 +14,4 @@ bool zmk_backlight_is_on(); int zmk_backlight_set_brt(uint8_t brightness); uint8_t zmk_backlight_get_brt(); uint8_t zmk_backlight_calc_brt(int direction); +uint8_t zmk_backlight_calc_brt_cycle(); diff --git a/app/src/backlight.c b/app/src/backlight.c index 46e3c9e3..e8708642 100644 --- a/app/src/backlight.c +++ b/app/src/backlight.c @@ -137,6 +137,14 @@ uint8_t zmk_backlight_calc_brt(int direction) { return CLAMP(brt, 0, BRT_MAX); } +uint8_t zmk_backlight_calc_brt_cycle() { + if (state.brightness == BRT_MAX) { + return 0; + } else { + return zmk_backlight_calc_brt(1); + } +} + #if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) || IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) static int backlight_auto_state(bool *prev_state, bool new_state) { if (state.on == new_state) { diff --git a/app/src/behaviors/behavior_backlight.c b/app/src/behaviors/behavior_backlight.c index 8dd6ee58..bdad828d 100644 --- a/app/src/behaviors/behavior_backlight.c +++ b/app/src/behaviors/behavior_backlight.c @@ -35,6 +35,10 @@ on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_bin binding->param1 = BL_SET_CMD; binding->param2 = zmk_backlight_calc_brt(-1); break; + case BL_CYCLE_CMD: + binding->param1 = BL_SET_CMD; + binding->param2 = zmk_backlight_calc_brt_cycle(); + break; default: return 0; } @@ -61,6 +65,10 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, uint8_t brt = zmk_backlight_calc_brt(-1); return zmk_backlight_set_brt(brt); } + case BL_CYCLE_CMD: { + uint8_t brt = zmk_backlight_calc_brt_cycle(); + return zmk_backlight_set_brt(brt); + } case BL_SET_CMD: return zmk_backlight_set_brt(binding->param2); default: diff --git a/app/tests/backlight/cycle/events.patterns b/app/tests/backlight/cycle/events.patterns new file mode 100644 index 00000000..bb11bc15 --- /dev/null +++ b/app/tests/backlight/cycle/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/cycle/keycode_events.snapshot b/app/tests/backlight/cycle/keycode_events.snapshot new file mode 100644 index 00000000..70d0988c --- /dev/null +++ b/app/tests/backlight/cycle/keycode_events.snapshot @@ -0,0 +1,14 @@ +Update backlight brightness: 40% +Update backlight brightness: 60% +Update backlight brightness: 80% +Update backlight brightness: 100% +Update backlight brightness: 0% +Update backlight brightness: 20% +Update backlight brightness: 40% +Update backlight brightness: 60% +Update backlight brightness: 80% +Update backlight brightness: 100% +Update backlight brightness: 0% +Update backlight brightness: 20% +Update backlight brightness: 40% +Update backlight brightness: 60% diff --git a/app/tests/backlight/cycle/native_posix.conf b/app/tests/backlight/cycle/native_posix.conf new file mode 100644 index 00000000..565121d3 --- /dev/null +++ b/app/tests/backlight/cycle/native_posix.conf @@ -0,0 +1,14 @@ +CONFIG_KSCAN=n +CONFIG_ZMK_KSCAN_MOCK_DRIVER=y +CONFIG_ZMK_KSCAN_GPIO_DRIVER=n +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y diff --git a/app/tests/backlight/cycle/native_posix.keymap b/app/tests/backlight/cycle/native_posix.keymap new file mode 100644 index 00000000..a2f3c830 --- /dev/null +++ b/app/tests/backlight/cycle/native_posix.keymap @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +/ { + chosen { + zmk,backlight = &backlight; + }; + + backlight: leds { + compatible = "gpio-leds"; + led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Backlight LED 0"; + }; + led_1 { + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + label = "Backlight LED 1"; + }; + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &bl BL_CYCLE &none + &none &none + >; + }; + }; +}; + +&kscan { + events = < + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/docs/docs/behaviors/backlight.md b/docs/docs/behaviors/backlight.md index c1a92c90..e8d3340e 100644 --- a/docs/docs/behaviors/backlight.md +++ b/docs/docs/behaviors/backlight.md @@ -20,18 +20,21 @@ This will allow you to reference the actions defined in this header such as `BL_ Here is a table describing the action for each define: -| Define | Action | -| -------- | ---------------------------------------- | -| `BL_TOG` | Toggles the backlight on and off | -| `BL_ON` | Turn on backlight on and off | -| `BL_OFF` | Toggles the backlight feature on and off | -| `BL_INC` | Increase backlight brightness | -| `BL_DEC` | Decrease backlight brightness | +| Define | Action | +| ---------- | --------------------------- | +| `BL_ON` | Turn on backlight | +| `BL_OFF` | Turn off backlight | +| `BL_TOG` | Toggle backlight on and off | +| `BL_INC` | Increase brightness | +| `BL_DEC` | Decrease brightness | +| `BL_CYCLE` | Cycle brightness | +| `BL_SET` | Set a specific brightness | ## Behavior Binding - Reference: `&bl` - Parameter #1: The backlight action define, e.g. `BL_TOG` or `BL_INC` +- Parameter #2: Only applies to `BL_SET`and is the brightness value ### Examples @@ -41,8 +44,8 @@ Here is a table describing the action for each define: &bl BL_TOG ``` -1. Increase backlight brightness +1. Sets a specific brightness ``` - &bl BL_INC + &bl BL_SET 50 ``` From be94e049633e2481165ba5b1f9bd07a51b07e62c Mon Sep 17 00:00:00 2001 From: Alessandro Bortolin Date: Fri, 21 Jan 2022 22:58:25 +0100 Subject: [PATCH 31/48] docs(backlight): improve documentation --- docs/docs/features/backlight.md | 146 ++++++++++++++++++++++++++++---- 1 file changed, 128 insertions(+), 18 deletions(-) diff --git a/docs/docs/features/backlight.md b/docs/docs/features/backlight.md index 379cc770..ef1c0521 100644 --- a/docs/docs/features/backlight.md +++ b/docs/docs/features/backlight.md @@ -3,19 +3,20 @@ title: Backlight sidebar_label: Backlight --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + Backlight is a feature used to control array of LEDs, usually placed through or under switches. Unlike [RGB Underglow](underglow.md), backlight currently allows only one color per LED, also LEDs are not addressable, so you can't control individual LEDs. ## Enabling Backlight -To enable backlight on your board or shield, add the following lines to your `.conf` file of your user config directory as such: +To enable backlight on your board or shield, add the following line to your `.conf` file of your user config directory as such: ``` -CONFIG_PWM=y -CONFIG_LED_PWM=y CONFIG_ZMK_BACKLIGHT=y ``` -If your board or shield does not have backlight configured, refer to [Adding Backlight to a Board](#adding-backlight-to-a-board). +If your board or shield does not have backlight configured, refer to [Adding Backlight to a board or a shield](#adding-backlight-to-a-board-or-a-shield). ## Configuring Backlight @@ -29,13 +30,31 @@ There are various Kconfig options used to configure the backlight feature. These | `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE` | Turn off backlight when keyboard goes into idle state | n | | `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB` | Turn off backlight when USB is disconnected | n | -## Adding Backlight to a Board +## Adding Backlight to a board or a shield -Backlight is always added to a board, not a shield. -If you have a shield with backlight, you must add a `boards/` directory within your shield folder to define the backlight individually for each board that supports the shield. -Inside the `boards/` folder, you define a `.overlay` for each different board. + + -First, you need to enable PWM by adding the following lines to your `.overlay` file: +First, you must enable PWM by adding the following lines to your `Kconfig.defconfig` file: + +``` +if ZMK_BACKLIGHT + +config PWM + default y + +config LED_PWM + default y + +endif # ZMK_BACKLIGHT +``` + +Then you have to add the following lines to your `.dts` file: ``` &pwm0 { @@ -52,14 +71,17 @@ For example, _P1.13_ would give you _32 \* 1 + 13_ = `<45>` and _P0.15_ would gi If your board uses a P-channel MOSFET to control backlight instead of a N-channel MOSFET, you may want to enable `ch0-inverted`. -Then you have to add the following lines to your `.dtsi` file inside the root devicetree node: +Then you have to add the following lines inside the root devicetree node on the same file as before: ``` -backlight: pwmleds { - compatible = "pwm-leds"; - label = "Backlight LEDs"; - pwm_led_0 { - pwms = <&pwm0 45>; +/ { + backlight: pwmleds { + compatible = "pwm-leds"; + label = "Backlight LEDs"; + pwm_led_0 { + pwms = <&pwm0 45>; + label = "Backlight LED 0"; + }; }; }; ``` @@ -73,12 +95,100 @@ Note that every LED inside of the backlight node will be treated as a backlight Finally you need to add backlight to the `chosen` element of the root devicetree node: ``` -chosen { - ... - zmk,backlight = &backlight; +/ { + chosen { + zmk,backlight = &backlight; + }; +}: +``` + + + + +You must first add a `boards/` directory within your shield folder. For each board that supports the shield you must create a `.defconfig` file and a `.overlay` file inside the `boards/` folder. + +Inside your `.defconfig` file, add the following lines: + +``` +if ZMK_BACKLIGHT + +config PWM + default y + +config LED_PWM + default y + +endif # ZMK_BACKLIGHT +``` + +Then add the following lines to your `.overlay` file: + +``` +&pwm0 { + status = "okay"; + ch0-pin = <45>; + /* ch0-inverted; */ }; ``` +The value `ch0-pin` represents the pin that controls the LEDs. With nRF52 boards, you can calculate the value to use in the following way: you need the hardware port and run it through a function. +**32 \* X + Y** = `` where X is first part of the hardware port "PX.01" and Y is the second part of the hardware port "P1.Y". + +For example, _P1.13_ would give you _32 \* 1 + 13_ = `<45>` and _P0.15_ would give you _32 \* 0 + 15_ = `<15>`. + +If your shield uses a P-channel MOSFET to control backlight instead of a N-channel MOSFET, you may want to enable `ch0-inverted`. + +Then you have to add the following lines inside the root devicetree node on the same file: + +``` +/ { + backlight: pwmleds { + compatible = "pwm-leds"; + label = "Backlight LEDs"; + pwm_led_0 { + pwms = <&pwm0 45>; + label = "Backlight LED 0"; + }; + }; +}; +``` + +The value inside `pwm_led_0` must be the same as you used before. + +:::info +Note that every LED inside of the backlight node will be treated as a backlight LED, so if you have other PWM LEDs you need to declare them in a separate node. Refer to [Multiple backlight LEDs](#multiple-backlight-leds) if you have multiple backlight LEDs. +::: + +Finally you need to add backlight to the `chosen` element of the root devicetree node: + +``` +/ { + chosen { + zmk,backlight = &backlight; + }; +}: +``` + +Optionally, on Pro Micro compatible shields you can add a LED GPIO node to your devicetree, this could be useful if you want your shield to be compatible with newer or untested boards. To do that you have to enable `CONFIG_LED_GPIO` in your `.conf` file and then add the following lines inside the root devicetree node of your `.dtsi` or `.dts` file: + +``` +/ { + backlight: gpioleds { + compatible = "gpio-leds"; + label = "Backlight LEDs"; + gpio_led_0 { + gpios = <&pro_micro 20 GPIO_ACTIVE_HIGH>; + label = "Backlight LED 0"; + }; + }; +}; +``` + +If no suitable `.overlay` file is found, this node will act as a fallback, however, without PWM, backlight has limited functionality. + + + + ### Multiple backlight LEDs It is possible to control multiple backlight LEDs at the same time. This is useful if, for example, you have a Caps Lock LED connected to a different pin and you want it to be part of the backlight. From e2a90974e3ef859dfef9e5d47a59b61e8bb7a478 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sun, 6 Feb 2022 21:04:42 -0500 Subject: [PATCH 32/48] fix(lighting): Proper split backlight support. Ensure the backlight behavior is run globally. --- app/src/behaviors/behavior_backlight.c | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/behaviors/behavior_backlight.c b/app/src/behaviors/behavior_backlight.c index bdad828d..8876c1f1 100644 --- a/app/src/behaviors/behavior_backlight.c +++ b/app/src/behaviors/behavior_backlight.c @@ -88,6 +88,7 @@ static const struct behavior_driver_api behavior_backlight_driver_api = { on_keymap_binding_convert_central_state_dependent_params, .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released, + .locality = BEHAVIOR_LOCALITY_GLOBAL, }; DEVICE_DT_INST_DEFINE(0, behavior_backlight_init, device_pm_control_nop, NULL, NULL, APPLICATION, From 5c4bf8a3bb2be96b47ddde0e3fa639ebbad404ad Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Sun, 6 Feb 2022 21:28:56 -0800 Subject: [PATCH 33/48] feat(docs): Document locality for reset behaviors --- docs/docs/behaviors/reset.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/docs/behaviors/reset.md b/docs/docs/behaviors/reset.md index 8cf122b4..c06a13b7 100644 --- a/docs/docs/behaviors/reset.md +++ b/docs/docs/behaviors/reset.md @@ -41,3 +41,11 @@ Example: ``` &bootloader ``` + +## Split Keyboards + +Both basic and bootloader reset behaviors are source-specific: This means that it affects the side of the keyboard that contains the behavior binding for split keyboards. For example if you press a key with the `&reset` binding on the left half of the keyboard, the left half will be reset. If you want to be able to reset both sides you can put the bindings on both sides of the keyboard and activate it on the side you would like to reset. + +:::note Peripheral invocation +The peripheral side of the keyboard has to be paired and connected to the central side in order to be able to activate these behaviors, even if it is possible to trigger the behavior using only keys on that side. This is because the key bindings are processed on the central side which would then instruct the peripheral side to reset. +::: From c0b5985ac788002f03511a6a42109f21b510bfbf Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Sun, 6 Feb 2022 21:35:50 -0800 Subject: [PATCH 34/48] feat(docs): Document locality for power management behaviors --- docs/docs/behaviors/power.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/docs/behaviors/power.md b/docs/docs/behaviors/power.md index 0de50552..80580609 100644 --- a/docs/docs/behaviors/power.md +++ b/docs/docs/behaviors/power.md @@ -62,3 +62,7 @@ Here is a table describing the command for each define: ``` &ext_power EP_TOG ``` + +## Split Keyboards + +Power management behaviors are global: This means that when triggered, they affects both the central and peripheral side of split keyboards. From a1ef7c8090b4dc7b85605b877c56abcc44b2ef4d Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Sun, 6 Feb 2022 21:53:30 -0800 Subject: [PATCH 35/48] feat(docs): Document locality for RGB underglow behaviors --- docs/docs/behaviors/underglow.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/docs/behaviors/underglow.md b/docs/docs/behaviors/underglow.md index 597c2491..a6a47719 100644 --- a/docs/docs/behaviors/underglow.md +++ b/docs/docs/behaviors/underglow.md @@ -66,3 +66,7 @@ Value Limits: ``` &rgb_ug RGB_COLOR_HSB(128,100,100) ``` + +## Split Keyboards + +RGB underglow behaviors are global: This means that when triggered, they affect both the central and peripheral side of split keyboards. From 76268bae8ffebc304d971342b14cbfcbca2f0b8a Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Sun, 6 Feb 2022 21:54:05 -0800 Subject: [PATCH 36/48] feat(docs): Document locality for backlight behaviors --- docs/docs/behaviors/backlight.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/docs/behaviors/backlight.md b/docs/docs/behaviors/backlight.md index e8d3340e..cb9a85a8 100644 --- a/docs/docs/behaviors/backlight.md +++ b/docs/docs/behaviors/backlight.md @@ -49,3 +49,7 @@ Here is a table describing the action for each define: ``` &bl BL_SET 50 ``` + +## Split Keyboards + +Backlight behaviors are global: This means that when triggered, they affect both the central and peripheral side of split keyboards. From c18c3d910653557db3c3e65b1440ee805f1d38cf Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Sun, 6 Feb 2022 23:03:33 -0800 Subject: [PATCH 37/48] feat(docs): Add note for combos invoking source-specific behaviors --- docs/docs/features/combos.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/docs/features/combos.md b/docs/docs/features/combos.md index 1a19cfe4..550bd251 100644 --- a/docs/docs/features/combos.md +++ b/docs/docs/features/combos.md @@ -43,6 +43,10 @@ Key positions are numbered like the keys in your keymap, starting at 0. So, if t - Fully overlapping combos like `0 1` and `0 1 2` are supported. - You are not limited to `&kp` bindings. You can use all ZMK behaviors there, like `&mo`, `&bt`, `&mt`, `<` etc. +:::note Source-specific behaviors on split keyboards +Invoking a source-specific behavior such as one of the [reset behaviors](behaviors/reset.md) using a combo will always trigger it on the central side of the keyboard, regardless of the side that the keys corresponding to `key-positions` are on. +::: + ### Advanced configuration There are three global combo parameters which are set through KConfig. You can set them in the `.conf` file in the same directory as your keymap file. From cfd0d3d81af858dc08fb72f26b31a59a0938b51f Mon Sep 17 00:00:00 2001 From: okke Date: Wed, 26 Jan 2022 20:42:14 +0100 Subject: [PATCH 38/48] Behaviors: Add 'ignore-modifiers' option to sticky keys To combine multiple sticky modifiers, the sticky keys must ignore other (sticky) modifier keypresses. This behavior is important for "callum-style mods", where all modifiers are sticky mods. Fixes #829 --- app/dts/behaviors/sticky_key.dtsi | 1 + .../behaviors/zmk,behavior-sticky-key.yaml | 2 + app/src/behaviors/behavior_sticky_key.c | 9 +++- .../10-callum-mods/events.patterns | 1 + .../10-callum-mods/keycode_events.snapshot | 8 ++++ .../10-callum-mods/native_posix.keymap | 43 +++++++++++++++++++ 6 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 app/tests/sticky-keys/10-callum-mods/events.patterns create mode 100644 app/tests/sticky-keys/10-callum-mods/keycode_events.snapshot create mode 100644 app/tests/sticky-keys/10-callum-mods/native_posix.keymap diff --git a/app/dts/behaviors/sticky_key.dtsi b/app/dts/behaviors/sticky_key.dtsi index 64032085..886d35b7 100644 --- a/app/dts/behaviors/sticky_key.dtsi +++ b/app/dts/behaviors/sticky_key.dtsi @@ -12,6 +12,7 @@ #binding-cells = <1>; release-after-ms = <1000>; bindings = <&kp>; + ignore-modifiers; }; /omit-if-no-ref/ sl: behavior_sticky_layer { compatible = "zmk,behavior-sticky-key"; diff --git a/app/dts/bindings/behaviors/zmk,behavior-sticky-key.yaml b/app/dts/bindings/behaviors/zmk,behavior-sticky-key.yaml index 1c2ab7f3..c04883c0 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-sticky-key.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-sticky-key.yaml @@ -15,3 +15,5 @@ properties: type: int quick-release: type: boolean + ignore-modifiers: + type: boolean diff --git a/app/src/behaviors/behavior_sticky_key.c b/app/src/behaviors/behavior_sticky_key.c index 825ec7a6..3c75a7a3 100644 --- a/app/src/behaviors/behavior_sticky_key.c +++ b/app/src/behaviors/behavior_sticky_key.c @@ -31,6 +31,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); struct behavior_sticky_key_config { uint32_t release_after_ms; bool quick_release; + bool ignore_modifiers; struct zmk_behavior_binding behavior; }; @@ -201,7 +202,7 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) { continue; } - // If events were queued, the timer event may be queued late or not at all. + // If this event was queued, the timer may be triggered late or not at all. // Release the sticky key if the timer should've run out in the meantime. if (sticky_key->release_at != 0 && ev->timestamp > sticky_key->release_at) { stop_timer(sticky_key); @@ -210,6 +211,11 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) { } if (ev->state) { // key down + if (sticky_key->config->ignore_modifiers && is_mod(ev->usage_page, ev->keycode)) { + // ignore modifier key press so we can stack sticky keys and combine with other + // modifiers + continue; + } if (sticky_key->modified_key_usage_page != 0 || sticky_key->modified_key_keycode != 0) { // this sticky key is already in use for a keycode continue; @@ -270,6 +276,7 @@ static struct behavior_sticky_key_data behavior_sticky_key_data; static struct behavior_sticky_key_config behavior_sticky_key_config_##n = { \ .behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, DT_DRV_INST(n)), \ .release_after_ms = DT_INST_PROP(n, release_after_ms), \ + .ignore_modifiers = DT_INST_PROP(n, ignore_modifiers), \ .quick_release = DT_INST_PROP(n, quick_release), \ }; \ DEVICE_DT_INST_DEFINE(n, behavior_sticky_key_init, device_pm_control_nop, \ diff --git a/app/tests/sticky-keys/10-callum-mods/events.patterns b/app/tests/sticky-keys/10-callum-mods/events.patterns new file mode 100644 index 00000000..b1342af4 --- /dev/null +++ b/app/tests/sticky-keys/10-callum-mods/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/sticky-keys/10-callum-mods/keycode_events.snapshot b/app/tests/sticky-keys/10-callum-mods/keycode_events.snapshot new file mode 100644 index 00000000..fd2217a5 --- /dev/null +++ b/app/tests/sticky-keys/10-callum-mods/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/10-callum-mods/native_posix.keymap b/app/tests/sticky-keys/10-callum-mods/native_posix.keymap new file mode 100644 index 00000000..9febf08c --- /dev/null +++ b/app/tests/sticky-keys/10-callum-mods/native_posix.keymap @@ -0,0 +1,43 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &sk E &sl 1 + &kp A &kp B>; + }; + + lower_layer { + bindings = < + &sk LEFT_CONTROL &kp X + &sk LEFT_SHIFT &kp Z>; + }; + }; +}; + +&kscan { + events = < + /* press sl lower_layer */ + ZMK_MOCK_PRESS(0,1,10) + /* tap sk LEFT_CONTROL */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* tap sk LEFT_SHIFT */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* release sl lower_layer */ + ZMK_MOCK_RELEASE(0,1,10) + /* tap A (with left control and left shift enabled) */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* tap A (no sticky keys anymore) */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file From 7474d985c95ab477b97f5715b97329fa0cb46adc Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Fri, 11 Feb 2022 18:05:04 +0800 Subject: [PATCH 39/48] docs: Add guide to build additional keyboards with GH Actions (#1126) Co-authored-by: Cem Aksoylar --- docs/docs/customization.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/docs/customization.md b/docs/docs/customization.md index 31576e9a..47ebe417 100644 --- a/docs/docs/customization.md +++ b/docs/docs/customization.md @@ -56,3 +56,28 @@ For normal keyboards, follow the same flashing instructions as before to flash y For split keyboards, only the central (left) side will need to be reflashed if you are just updating your keymap. More troubleshooting information for split keyboards can be found [here](troubleshooting.md#split-keyboard-halves-unable-to-pair). + +## Building Additional Keyboards + +You can build additional keyboards with GitHub actions by appending them to `build.yml` in your `zmk-config` folder. For instance assume that we have set up a Corne shield with nice!nano during [initial setup](user-setup.md) and we want to add a Lily58 shield with nice!nano v2. The following is an example `build.yaml` file that would accomplish that: + +``` +include: + - board: nice_nano + shield: corne_left + - board: nice_nano + shield: corne_right + - board: nice_nano_v2 + shield: lily58_left + - board: nice_nano_v2 + shield: lily58_right +``` + +In addition to updating `build.yaml`, Lily58's shield files should also be added into the `config` sub-folder inside `zmk-config` together with your Corne files, e.g.: + +``` +corne.conf +corne.keymap +lily58.conf +lily58.keymap +``` From 22ed4488433d579cde9dcb2f50a3ba105234bff4 Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Fri, 11 Feb 2022 21:06:23 -0800 Subject: [PATCH 40/48] fix(docs): Replace deprecated keycode in positional-hold-tap example --- docs/docs/behaviors/hold-tap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/behaviors/hold-tap.md b/docs/docs/behaviors/hold-tap.md index edb9d593..e53c09b6 100644 --- a/docs/docs/behaviors/hold-tap.md +++ b/docs/docs/behaviors/hold-tap.md @@ -129,8 +129,8 @@ The following are suggested hold-tap configurations that work well with home row compatible = "zmk,keymap"; default_layer { bindings = < - // position 0 pos 1 pos 2 pos 3 pos 4 pos 5 pos 6 pos 7 pos 8 pos 9 pos 10 - &lh_pht LSFT A &lh_pht LGUI S &lh_pht LALT D &lh_pht LCTL F &kp G &kp H &kp I &kp J &kp K &kp L &kp SCLN + // position 0 pos 1 pos 2 pos 3 pos 4 pos 5 pos 6 pos 7 pos 8 pos 9 pos 10 + &lh_pht LSFT A &lh_pht LGUI S &lh_pht LALT D &lh_pht LCTL F &kp G &kp H &kp I &kp J &kp K &kp L &kp SEMI >; }; }; From 5c4f26ae741567df430fce08e5e6966855a9dadb Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Fri, 11 Feb 2022 21:07:41 -0800 Subject: [PATCH 41/48] fix(docs): Tweak label of left-hand positional hold-tap example behavior We see folks copying this behavior node and duplicating it for the right hand, then forgetting to modify the "label" value and getting confusing runtime behavior. If we modify the label to be left-specific like this it might be a better hint to change it when duplicating it. --- docs/docs/behaviors/hold-tap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/behaviors/hold-tap.md b/docs/docs/behaviors/hold-tap.md index e53c09b6..f7c386b3 100644 --- a/docs/docs/behaviors/hold-tap.md +++ b/docs/docs/behaviors/hold-tap.md @@ -115,7 +115,7 @@ The following are suggested hold-tap configurations that work well with home row behaviors { lh_pht: left_hand_positional_hold_tap { compatible = "zmk,behavior-hold-tap"; - label = "POSITIONAL_HOLD_TAP"; + label = "LEFT_POSITIONAL_HOLD_TAP"; #binding-cells = <2>; flavor = "tap-unless-interrupted"; tapping-term-ms = <100>; // <---[[produces tap if held longer than tapping-term-ms]] From 8e91e5ada1cc42910008ee8eac08d6ab50eb6894 Mon Sep 17 00:00:00 2001 From: Dom H Date: Sat, 12 Feb 2022 08:46:08 +0000 Subject: [PATCH 42/48] fix(docs): Add `behaviors/key-repeat` to sidebar --- docs/sidebars.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sidebars.js b/docs/sidebars.js index 090dcb0f..647399a7 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -29,6 +29,7 @@ module.exports = { "behaviors/sticky-key", "behaviors/sticky-layer", "behaviors/caps-word", + "behaviors/key-repeat", "behaviors/reset", "behaviors/bluetooth", "behaviors/outputs", From 43ffa6c76077a446ee0ebc8ebc39ebc09eae4b57 Mon Sep 17 00:00:00 2001 From: chadbailey59 Date: Wed, 16 Feb 2022 05:46:15 -0600 Subject: [PATCH 43/48] docs: Clarifications within New Shield page (#1130) Co-authored-by: Cem Aksoylar --- docs/docs/development/new-shield.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/docs/development/new-shield.md b/docs/docs/development/new-shield.md index 6f65d869..26542310 100644 --- a/docs/docs/development/new-shield.md +++ b/docs/docs/development/new-shield.md @@ -48,16 +48,16 @@ shield to get it picked up for ZMK, `Kconfig.shield` and `Kconfig.defconfig`. ### Kconfig.shield -The `Kconfig.shield` file defines any additional Kconfig settings that may be relevant when using this keyboard. For most keyboards, there is just one additional configuration value for the shield itself, e.g.: +The `Kconfig.shield` file defines any additional Kconfig settings that may be relevant when using this keyboard. For most keyboards, there is just one additional configuration value for the shield itself. ``` config SHIELD_MY_BOARD def_bool $(shields_list_contains,my_board) ``` -This will make sure the new configuration `SHIELD_MY_BOARD` is set to true whenever `my_board` is added as a shield in your build. +This will make sure that a new configuration value named `SHIELD_MY_BOARD` is set to true whenever `my_board` is used as the shield name, either as the `SHIELD` variable [in a local build](build-flash.md) or in your `build.yaml` file [when using Github Actions](../customization). Note that this configuration value will be used in `Kconfig.defconfig` to set other properties about your shield, so make sure that they match. -**For split boards**, you will need to add configurations for the left and right sides. +**For split boards**, you will need to add configurations for the left and right sides. For example, if your split halves are named `my_board_left` and `my_board_right`, it would look like this: ``` config SHIELD_MY_BOARD_LEFT @@ -84,7 +84,7 @@ Do not make the keyboard name too long, otherwise the bluetooth advertising migh if SHIELD_MY_BOARD config ZMK_KEYBOARD_NAME - default "My Awesome Keyboard" + default "My Board" endif ``` @@ -98,7 +98,7 @@ Finally, you'll want to turn on the split option for both sides. This can all be if SHIELD_MY_BOARD_LEFT config ZMK_KEYBOARD_NAME - default "My Awesome Keyboard" + default "My Board" config ZMK_SPLIT_BLE_ROLE_CENTRAL default y From 322cc14da67fcfb31ece80a7b288a1aef616ad93 Mon Sep 17 00:00:00 2001 From: Dom H Date: Wed, 16 Feb 2022 12:07:56 +0000 Subject: [PATCH 44/48] fix(docs): Remove trailing whitespace Otherwise, prettier fails. --- docs/docs/development/new-shield.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/development/new-shield.md b/docs/docs/development/new-shield.md index 26542310..dc4db850 100644 --- a/docs/docs/development/new-shield.md +++ b/docs/docs/development/new-shield.md @@ -55,7 +55,7 @@ config SHIELD_MY_BOARD def_bool $(shields_list_contains,my_board) ``` -This will make sure that a new configuration value named `SHIELD_MY_BOARD` is set to true whenever `my_board` is used as the shield name, either as the `SHIELD` variable [in a local build](build-flash.md) or in your `build.yaml` file [when using Github Actions](../customization). Note that this configuration value will be used in `Kconfig.defconfig` to set other properties about your shield, so make sure that they match. +This will make sure that a new configuration value named `SHIELD_MY_BOARD` is set to true whenever `my_board` is used as the shield name, either as the `SHIELD` variable [in a local build](build-flash.md) or in your `build.yaml` file [when using Github Actions](../customization). Note that this configuration value will be used in `Kconfig.defconfig` to set other properties about your shield, so make sure that they match. **For split boards**, you will need to add configurations for the left and right sides. For example, if your split halves are named `my_board_left` and `my_board_right`, it would look like this: From 5cc9b8f71a5abe3fabbf6187fff2953b6d0bcefb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 12:13:21 +0000 Subject: [PATCH 45/48] chore(deps): bump follow-redirects from 1.14.7 to 1.14.8 in /docs Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] --- docs/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index f799ad70..166a8d72 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -11678,9 +11678,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "funding": [ { "type": "individual", @@ -29980,9 +29980,9 @@ } }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "for-in": { "version": "1.0.2", From b54128331eb03ac02edbc642a313c5f2e2139da5 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Thu, 3 Feb 2022 06:10:03 +0000 Subject: [PATCH 46/48] feat(shields): Add Kyria Rev2 shield. * New matrix pin selections. * New encoder pins. --- app/boards/shields/kyria/Kconfig.defconfig | 4 +- app/boards/shields/kyria/Kconfig.shield | 13 ++++ app/boards/shields/kyria/kyria.dtsi | 76 +++++-------------- app/boards/shields/kyria/kyria_common.dtsi | 59 ++++++++++++++ app/boards/shields/kyria/kyria_rev2.conf | 10 +++ app/boards/shields/kyria/kyria_rev2.dtsi | 55 ++++++++++++++ app/boards/shields/kyria/kyria_rev2.zmk.yml | 15 ++++ app/boards/shields/kyria/kyria_rev2_left.conf | 0 .../shields/kyria/kyria_rev2_left.overlay | 30 ++++++++ .../shields/kyria/kyria_rev2_right.conf | 0 .../shields/kyria/kyria_rev2_right.overlay | 34 +++++++++ 11 files changed, 237 insertions(+), 59 deletions(-) create mode 100644 app/boards/shields/kyria/kyria_common.dtsi create mode 100644 app/boards/shields/kyria/kyria_rev2.conf create mode 100644 app/boards/shields/kyria/kyria_rev2.dtsi create mode 100644 app/boards/shields/kyria/kyria_rev2.zmk.yml create mode 100644 app/boards/shields/kyria/kyria_rev2_left.conf create mode 100644 app/boards/shields/kyria/kyria_rev2_left.overlay create mode 100644 app/boards/shields/kyria/kyria_rev2_right.conf create mode 100644 app/boards/shields/kyria/kyria_rev2_right.overlay diff --git a/app/boards/shields/kyria/Kconfig.defconfig b/app/boards/shields/kyria/Kconfig.defconfig index 57a701a9..74a22520 100644 --- a/app/boards/shields/kyria/Kconfig.defconfig +++ b/app/boards/shields/kyria/Kconfig.defconfig @@ -1,5 +1,5 @@ -if SHIELD_KYRIA_LEFT +if SHIELD_KYRIA_LEFT || SHIELD_KYRIA_REV2_LEFT config ZMK_KEYBOARD_NAME default "Kyria" @@ -9,7 +9,7 @@ config ZMK_SPLIT_BLE_ROLE_CENTRAL endif -if SHIELD_KYRIA_LEFT || SHIELD_KYRIA_RIGHT +if SHIELD_KYRIA config ZMK_SPLIT default y diff --git a/app/boards/shields/kyria/Kconfig.shield b/app/boards/shields/kyria/Kconfig.shield index 7dee0449..6304f5d5 100644 --- a/app/boards/shields/kyria/Kconfig.shield +++ b/app/boards/shields/kyria/Kconfig.shield @@ -1,8 +1,21 @@ # Copyright (c) 2020 Pete Johanson # SPDX-License-Identifier: MIT +config SHIELD_KYRIA + bool + config SHIELD_KYRIA_LEFT def_bool $(shields_list_contains,kyria_left) + select SHIELD_KYRIA config SHIELD_KYRIA_RIGHT def_bool $(shields_list_contains,kyria_right) + select SHIELD_KYRIA + +config SHIELD_KYRIA_REV2_LEFT + def_bool $(shields_list_contains,kyria_rev2_left) + select SHIELD_KYRIA + +config SHIELD_KYRIA_REV2_RIGHT + def_bool $(shields_list_contains,kyria_rev2_right) + select SHIELD_KYRIA diff --git a/app/boards/shields/kyria/kyria.dtsi b/app/boards/shields/kyria/kyria.dtsi index 2d5114ec..1b0ca940 100644 --- a/app/boards/shields/kyria/kyria.dtsi +++ b/app/boards/shields/kyria/kyria.dtsi @@ -1,14 +1,13 @@ /* - * Copyright (c) 2020 Pete Johanson + * Copyright (c) 2022 The ZMK Contributors * * SPDX-License-Identifier: MIT */ -#include +#include "kyria_common.dtsi" / { chosen { - zmk,kscan = &kscan0; zmk,matrix_transform = &default_transform; }; @@ -43,60 +42,23 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) >; }; - - kscan0: kscan { - compatible = "zmk,kscan-gpio-matrix"; - label = "KSCAN"; - - diode-direction = "col2row"; - row-gpios - = <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - ; - - }; - - left_encoder: encoder_left { - compatible = "alps,ec11"; - label = "LEFT_ENCODER"; - a-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; - b-gpios = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; - resolution = <4>; - status = "disabled"; - }; - - right_encoder: encoder_right { - compatible = "alps,ec11"; - label = "RIGHT_ENCODER"; - a-gpios = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; - b-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; - resolution = <4>; - status = "disabled"; - }; - - sensors { - compatible = "zmk,keymap-sensors"; - sensors = <&left_encoder &right_encoder>; - }; - - // TODO: RGB node(s) }; -&pro_micro_i2c { - status = "okay"; - - ssd1306@3c { - compatible = "solomon,ssd1306fb"; - reg = <0x3c>; - label = "DISPLAY"; - width = <128>; - height = <64>; - segment-offset = <0>; - page-offset = <0>; - display-offset = <0>; - multiplex-ratio = <63>; - prechargep = <0x22>; - }; +&kscan0 { + row-gpios + = <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; +}; + +&left_encoder { + a-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; +}; + +&right_encoder { + a-gpios = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; }; diff --git a/app/boards/shields/kyria/kyria_common.dtsi b/app/boards/shields/kyria/kyria_common.dtsi new file mode 100644 index 00000000..479f090c --- /dev/null +++ b/app/boards/shields/kyria/kyria_common.dtsi @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + label = "LEFT_ENCODER"; + resolution = <4>; + status = "disabled"; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + label = "RIGHT_ENCODER"; + resolution = <4>; + status = "disabled"; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + }; + + // TODO: RGB node(s) +}; + +&pro_micro_i2c { + status = "okay"; + + ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <64>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <63>; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/kyria/kyria_rev2.conf b/app/boards/shields/kyria/kyria_rev2.conf new file mode 100644 index 00000000..7a0b5b6c --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2.conf @@ -0,0 +1,10 @@ +# Uncomment these two line to add support for encoders to your firmware +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Kyria OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/kyria/kyria_rev2.dtsi b/app/boards/shields/kyria/kyria_rev2.dtsi new file mode 100644 index 00000000..7c7d9efe --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2.dtsi @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_common.dtsi" + +/ { + chosen { + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | MX6 | MX5 | MX4 | MX3 | MX2 | MX1 | | MX1 | MX2 | MX3 | MX4 | MX5 | MX6 | +// | MX12 | MX11 | MX10 | MX9 | MX8 | MX7 | | MX7 | MX8 | MX9 | MX10 | MX11 | MX12 | +// | MX20 | MX19 | MX18 | MX17 | MX16 | MX15 | MX14 | MX13 | | MX13 | MX14 | MX15 | MX16 | MX17 | MX18 | MX19 | MX20 | +// | MX25 | MX24 | MX23 | MX22 | MX21 | | MX21 | MX22 | MX23 | MX24 | MX25 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(1,15) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,14) RC(2,15) + RC(3,2) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) + >; + }; + +// | MX5 | MX4 | MX3 | MX2 | MX1 | | MX1 | MX2 | MX3 | MX4 | MX5 | +// | MX11 | MX10 | MX9 | MX8 | MX7 | | MX7 | MX8 | MX9 | MX10 | MX11 | +// | MX19 | MX18 | MX17 | MX16 | MX15 | MX14 | MX13 | | MX13 | MX14 | MX15 | MX16 | MX17 | MX18 | MX19 | +// | MX25 | MX24 | MX23 | MX22 | MX21 | | MX21 | MX22 | MX23 | MX24 | MX25 | + five_column_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <4>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + >; + }; +}; + +&left_encoder { + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; +}; + +&right_encoder { + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; +}; \ No newline at end of file diff --git a/app/boards/shields/kyria/kyria_rev2.zmk.yml b/app/boards/shields/kyria/kyria_rev2.zmk.yml new file mode 100644 index 00000000..d6b3b108 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: kyria_rev2 +name: Kyria Rev2 +type: shield +url: https://splitkb.com/products/kyria-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - kyria_left + - kyria_right diff --git a/app/boards/shields/kyria/kyria_rev2_left.conf b/app/boards/shields/kyria/kyria_rev2_left.conf new file mode 100644 index 00000000..e69de29b diff --git a/app/boards/shields/kyria/kyria_rev2_left.overlay b/app/boards/shields/kyria/kyria_rev2_left.overlay new file mode 100644 index 00000000..cee2e2a8 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2_left.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_rev2.dtsi" + +&kscan0 { + row-gpios + = <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/kyria/kyria_rev2_right.conf b/app/boards/shields/kyria/kyria_rev2_right.conf new file mode 100644 index 00000000..e69de29b diff --git a/app/boards/shields/kyria/kyria_rev2_right.overlay b/app/boards/shields/kyria/kyria_rev2_right.overlay new file mode 100644 index 00000000..7476bcba --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2_right.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_rev2.dtsi" + +&default_transform { + col-offset = <8>; +}; + +&kscan0 { + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; From 7b1b979461ee4ac6835a648befd4b6ec16adefd5 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sun, 20 Feb 2022 16:11:50 +0000 Subject: [PATCH 47/48] fix(shields): Proper siblings for Kyria Rev2. --- app/boards/shields/kyria/kyria_rev2.zmk.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/boards/shields/kyria/kyria_rev2.zmk.yml b/app/boards/shields/kyria/kyria_rev2.zmk.yml index d6b3b108..6488f690 100644 --- a/app/boards/shields/kyria/kyria_rev2.zmk.yml +++ b/app/boards/shields/kyria/kyria_rev2.zmk.yml @@ -11,5 +11,5 @@ features: - encoder - underglow siblings: - - kyria_left - - kyria_right + - kyria_rev2_left + - kyria_rev2_right From 1d5b48cb52791335c818c55b348da2af943ba78d Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sun, 20 Feb 2022 16:24:55 +0000 Subject: [PATCH 48/48] fix(shields): Add missing kyria_rev2.keymap Needed for setup.sh script, which assumes the shield ID name, not the shield dir name for downloading. --- app/boards/shields/kyria/kyria_rev2.keymap | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 app/boards/shields/kyria/kyria_rev2.keymap diff --git a/app/boards/shields/kyria/kyria_rev2.keymap b/app/boards/shields/kyria/kyria_rev2.keymap new file mode 100644 index 00000000..a8804dd9 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2.keymap @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// --------------------------------------------------------------------------------------------------------------------------------- +// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ | +// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | L SHIFT | L SHIFT | N | M | , | . | / | CTRL | +// | GUI | DEL | RET | SPACE | ESC | | RET | SPACE | TAB | BSPC | R-ALT | + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &kp LSHFT &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +};