diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index b5e7b034..f3d36665 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -35,7 +35,6 @@ target_sources(app PRIVATE src/events/modifiers_state_changed.c) target_sources(app PRIVATE src/events/sensor_event.c) 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_mod_tap.c) target_sources(app PRIVATE src/behaviors/behavior_tap_hold.c) target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c) target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 4cfb7a0f..fdcf426b 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/app/dts/behaviors/homerow_tap.dtsi b/app/dts/behaviors/homerow_tap.dtsi new file mode 100644 index 00000000..3c4dec68 --- /dev/null +++ b/app/dts/behaviors/homerow_tap.dtsi @@ -0,0 +1,12 @@ +/ { + behaviors { + ht: behavior_homerow_mod { + compatible = "zmk,behavior-tap-hold"; + label = "homerow_mod"; + #binding-cells = <2>; + flavor = "balanced"; + tapping_term_ms = <200>; + bindings = <&kp>, <&kp>; + }; + }; +}; diff --git a/app/dts/behaviors/layer_tap.dtsi b/app/dts/behaviors/layer_tap.dtsi new file mode 100644 index 00000000..1c51f80d --- /dev/null +++ b/app/dts/behaviors/layer_tap.dtsi @@ -0,0 +1,12 @@ +/ { + behaviors { + lt: behavior_layer_tap { + compatible = "zmk,behavior-tap-hold"; + label = "LAYER_TAP"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping_term_ms = <200>; + bindings = <&mo>, <&kp>; + }; + }; +}; diff --git a/app/dts/behaviors/mod_tap.dtsi b/app/dts/behaviors/mod_tap.dtsi index 8e3b4e91..8dfbd052 100644 --- a/app/dts/behaviors/mod_tap.dtsi +++ b/app/dts/behaviors/mod_tap.dtsi @@ -1,9 +1,12 @@ / { behaviors { mt: behavior_mod_tap { - compatible = "zmk,behavior-mod-tap"; + compatible = "zmk,behavior-tap-hold"; label = "MOD_TAP"; #binding-cells = <2>; + flavor = "hold-preferred"; + tapping_term_ms = <200>; + bindings = <&kp>, <&kp>; }; }; }; diff --git a/app/dts/bindings/behaviors/zmk,behavior-mod-tap.yaml b/app/dts/bindings/behaviors/zmk,behavior-mod-tap.yaml deleted file mode 100644 index 7911082f..00000000 --- a/app/dts/bindings/behaviors/zmk,behavior-mod-tap.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2020, Pete Johanson -# SPDX-License-Identifier: MIT - -description: Mod-Tap Beavhior - -compatible: "zmk,behavior-mod-tap" - -include: two_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-tap-hold.yaml b/app/dts/bindings/behaviors/zmk,behavior-tap-hold.yaml index d6d041b0..4edb67b8 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-tap-hold.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-tap-hold.yaml @@ -5,11 +5,11 @@ description: Hold or Tap behavior compatible: "zmk,behavior-tap-hold" -include: zero_param.yaml +include: two_param.yaml properties: bindings: - type: phandle-array + type: phandles required: true tapping_term_ms: type: int diff --git a/app/src/behaviors/behavior_mod_tap.c b/app/src/behaviors/behavior_mod_tap.c deleted file mode 100644 index 5a2f60e2..00000000 --- a/app/src/behaviors/behavior_mod_tap.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2020 Peter Johanson - * - * SPDX-License-Identifier: MIT - */ - -#define DT_DRV_COMPAT zmk_behavior_mod_tap - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - -#define ZMK_BHV_MOD_TAP_MAX_HELD 4 -#define ZMK_BHV_MOD_TAP_MAX_PENDING_KC 4 - -struct active_mod_tap_item { - u32_t keycode; - u8_t mods; - bool pending; - zmk_mod_flags active_mods; -}; - -struct captured_keycode_state_change_item { - struct keycode_state_changed* event; - zmk_mod_flags active_mods; -}; - -struct behavior_mod_tap_config { }; -struct behavior_mod_tap_data { - struct active_mod_tap_item active_mod_taps[ZMK_BHV_MOD_TAP_MAX_HELD]; - struct captured_keycode_state_change_item captured_keycode_events[ZMK_BHV_MOD_TAP_MAX_PENDING_KC]; -}; - -bool have_pending_mods(char *label) { - struct device *dev = device_get_binding(label); - struct behavior_mod_tap_data *data = dev->driver_data; - - for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) { - if (data->active_mod_taps[i].mods) { - LOG_DBG("Found pending mods for %d and keycode 0x%02X", data->active_mod_taps[i].mods, data->active_mod_taps[i].keycode); - return true; - } - } - - return false; -} - -struct captured_keycode_state_change_item* find_pending_keycode(struct behavior_mod_tap_data *data, u32_t keycode) -{ - for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; i++) { - if (data->captured_keycode_events[i].event == NULL) { - continue; - } - - if (data->captured_keycode_events[i].event->keycode == keycode) { - return &data->captured_keycode_events[i]; - } - } - - return NULL; -} - -zmk_mod_flags behavior_mod_tap_active_mods(struct behavior_mod_tap_data *data) -{ - zmk_mod_flags mods = 0; - - for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) { - mods |= data->active_mod_taps[i].mods; - } - - return mods; -} - -int behavior_mod_tap_capture_keycode_event(struct behavior_mod_tap_data *data, struct keycode_state_changed *ev) -{ - for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; i++) { - if (data->captured_keycode_events[i].event != NULL) { - continue; - } - - data->captured_keycode_events[i].event = ev; - data->captured_keycode_events[i].active_mods = behavior_mod_tap_active_mods(data); - return 0; - } - - return -ENOMEM; -} - -void behavior_mod_tap_update_active_mods_state(struct behavior_mod_tap_data *data, zmk_mod_flags used_flags) -{ - for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) { - if ((data->active_mod_taps[i].mods & used_flags) == data->active_mod_taps[i].mods) { - data->active_mod_taps[i].pending = false; - } - } -} - -// How to pass context to subscription?! -int behavior_mod_tap_listener(const struct zmk_event_header *eh) -{ - if (is_keycode_state_changed(eh) && have_pending_mods(DT_INST_LABEL(0))) { - struct device *dev = device_get_binding(DT_INST_LABEL(0)); - struct keycode_state_changed *ev = cast_keycode_state_changed(eh); - struct behavior_mod_tap_data *data = dev->driver_data; - struct captured_keycode_state_change_item* pending_keycode; - if (ev->state) { - LOG_DBG("Have pending mods, capturing keycode 0x%02X event to ressend later", ev->keycode); - behavior_mod_tap_capture_keycode_event(data, ev); - return ZMK_EV_EVENT_CAPTURED; - } else if ((pending_keycode = find_pending_keycode(data, ev->keycode)) != NULL) { - LOG_DBG("Key released, going to activate mods 0x%02X then send pending key press for keycode 0x%02X", - pending_keycode->active_mods, pending_keycode->event->keycode); - - zmk_hid_register_mods(pending_keycode->active_mods); - behavior_mod_tap_update_active_mods_state(data, pending_keycode->active_mods); - - ZMK_EVENT_RELEASE(pending_keycode->event); - k_msleep(10); - - pending_keycode->event = NULL; - pending_keycode->active_mods = 0; - } - } - return 0; -} - -ZMK_LISTENER(behavior_mod_tap, behavior_mod_tap_listener); -ZMK_SUBSCRIPTION(behavior_mod_tap, keycode_state_changed); - -static int behavior_mod_tap_init(struct device *dev) -{ - return 0; -}; - - -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t mods, u32_t keycode) -{ - struct behavior_mod_tap_data *data = dev->driver_data; - LOG_DBG("mods: %d, keycode: 0x%02X", mods, keycode); - for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) { - if (data->active_mod_taps[i].mods != 0) { - continue; - } - - zmk_mod_flags active_mods = behavior_mod_tap_active_mods(data); - - data->active_mod_taps[i].active_mods = active_mods; - data->active_mod_taps[i].mods = mods; - data->active_mod_taps[i].keycode = keycode; - data->active_mod_taps[i].pending = true; - - return 0; - } - - LOG_WRN("Failed to record mod-tap activation, at maximum concurrent mod-tap activations"); - - return -ENOMEM; -} - -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t mods, u32_t keycode) -{ - struct behavior_mod_tap_data *data = dev->driver_data; - LOG_DBG("mods: %d, keycode: %d", mods, keycode); - - for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) { - struct active_mod_tap_item *item = &data->active_mod_taps[i]; - if (item->mods == mods && item->keycode == keycode) { - if (item->pending) { - LOG_DBG("Sending un-triggered mod-tap for keycode: 0x%02X", keycode); - - if (item->active_mods) { - LOG_DBG("Registering recorded active mods captured when mod-tap initially activated: 0x%02X", item->active_mods); - behavior_mod_tap_update_active_mods_state(data, item->active_mods); - zmk_hid_register_mods(item->active_mods); - } - - struct keycode_state_changed *key_press = create_keycode_state_changed(USAGE_KEYPAD, item->keycode, true); - ZMK_EVENT_RAISE_AFTER(key_press, behavior_mod_tap); - k_msleep(10); - - for (int j = 0; j < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; j++) { - if (data->captured_keycode_events[j].event == NULL) { - continue; - } - - struct keycode_state_changed *ev = data->captured_keycode_events[j].event; - data->captured_keycode_events[j].event = NULL; - data->captured_keycode_events[j].active_mods = 0; - LOG_DBG("Re-sending latched key press for usage page 0x%02X keycode 0x%02X state %s", ev->usage_page, ev->keycode, (ev->state ? "pressed" : "released")); - ZMK_EVENT_RELEASE(ev); - k_msleep(10); - } - - struct keycode_state_changed *key_release = create_keycode_state_changed(USAGE_KEYPAD, keycode, false); - LOG_DBG("Sending un-triggered mod-tap release for keycode: 0x%02X", keycode); - ZMK_EVENT_RAISE_AFTER(key_release, behavior_mod_tap); - k_msleep(10); - - if (item->active_mods) { - LOG_DBG("Unregistering recorded active mods captured when mod-tap initially activated: 0x%02X", item->active_mods); - zmk_hid_unregister_mods(item->active_mods); - zmk_endpoints_send_report(USAGE_KEYPAD); - } - - - } else { - LOG_DBG("Releasing triggered mods: %d", mods); - zmk_hid_unregister_mods(mods); - zmk_endpoints_send_report(USAGE_KEYPAD); - } - - item->mods = 0; - item->keycode = 0; - item->active_mods = 0; - - LOG_DBG("Removing mods %d from active_mods for other held mod-taps", mods); - for (int j = 0; j < ZMK_BHV_MOD_TAP_MAX_HELD; j++) { - if (data->active_mod_taps[j].active_mods & mods) { - LOG_DBG("Removing 0x%02X from active mod tap mods 0x%02X keycode 0x%02X", mods, data->active_mod_taps[j].mods, data->active_mod_taps[j].keycode); - data->active_mod_taps[j].active_mods &= ~mods; - } - } - break; - } - } - - return 0; -} - -static const struct behavior_driver_api behavior_mod_tap_driver_api = { - .binding_pressed = on_keymap_binding_pressed, - .binding_released = on_keymap_binding_released, -}; - -static const struct behavior_mod_tap_config behavior_mod_tap_config = {}; - -static struct behavior_mod_tap_data behavior_mod_tap_data; - -DEVICE_AND_API_INIT(behavior_mod_tap, DT_INST_LABEL(0), behavior_mod_tap_init, - &behavior_mod_tap_data, - &behavior_mod_tap_config, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, - &behavior_mod_tap_driver_api); diff --git a/app/src/behaviors/behavior_tap_hold.c b/app/src/behaviors/behavior_tap_hold.c index bf4e498d..568fd8ee 100644 --- a/app/src/behaviors/behavior_tap_hold.c +++ b/app/src/behaviors/behavior_tap_hold.c @@ -46,6 +46,8 @@ struct behavior_tap_hold_config { // this data is specific for each tap-hold struct active_tap_hold { s32_t position; + u32_t param_hold; + u32_t param_tap; bool is_decided; bool is_hold; const struct behavior_tap_hold_config *config; @@ -158,7 +160,7 @@ static struct active_tap_hold *find_tap_hold(u32_t position) return NULL; } -static struct active_tap_hold *store_tap_hold(u32_t position, const struct behavior_tap_hold_config *config) +static struct active_tap_hold *store_tap_hold(u32_t position, u32_t param_hold, u32_t param_tap, const struct behavior_tap_hold_config *config) { for (int i = 0; i < ZMK_BHV_TAP_HOLD_MAX_HELD; i++) { if (active_tap_holds[i].position != ZMK_BHV_TAP_HOLD_POSITION_NOT_USED) { @@ -168,6 +170,8 @@ static struct active_tap_hold *store_tap_hold(u32_t position, const struct behav active_tap_holds[i].is_decided = false; active_tap_holds[i].is_hold = false; active_tap_holds[i].config = config; + active_tap_holds[i].param_hold = param_hold; + active_tap_holds[i].param_tap = param_tap; return &active_tap_holds[i]; } return NULL; @@ -271,16 +275,18 @@ static void decide_tap_hold(struct active_tap_hold *tap_hold, enum decision_mome struct zmk_behavior_binding *behavior; if (tap_hold->is_hold) { behavior = &tap_hold->config->behaviors->hold; + struct device *behavior_device = device_get_binding(behavior->behavior_dev); + behavior_keymap_binding_pressed(behavior_device, tap_hold->position, tap_hold->param_hold, 0); } else { behavior = &tap_hold->config->behaviors->tap; + struct device *behavior_device = device_get_binding(behavior->behavior_dev); + behavior_keymap_binding_pressed(behavior_device, tap_hold->position, tap_hold->param_tap, 0); } - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_pressed(behavior_device, tap_hold->position, behavior->param1, behavior->param2); release_captured_events(); } /************************************************************ tap_hold_binding and key handlers */ -static int on_tap_hold_binding_pressed(struct device *dev, u32_t position, u32_t _, u32_t __) +static int on_tap_hold_binding_pressed(struct device *dev, u32_t position, u32_t param_hold, u32_t param_tap) { const struct behavior_tap_hold_config *cfg = dev->config_info; @@ -290,7 +296,7 @@ static int on_tap_hold_binding_pressed(struct device *dev, u32_t position, u32_t return 0; } - struct active_tap_hold *tap_hold = store_tap_hold(position, cfg); + struct active_tap_hold *tap_hold = store_tap_hold(position, param_hold, param_tap, cfg); if (tap_hold == NULL) { LOG_ERR("unable to store tap-hold info, did you press more than %d tap-holds?", ZMK_BHV_TAP_HOLD_MAX_HELD); return 0; @@ -321,12 +327,14 @@ static int on_tap_hold_binding_released(struct device *dev, u32_t position, u32_ struct zmk_behavior_binding *behavior; if (tap_hold->is_hold) { behavior = &tap_hold->config->behaviors->hold; + struct device *behavior_device = device_get_binding(behavior->behavior_dev); + behavior_keymap_binding_released(behavior_device, tap_hold->position, tap_hold->param_hold, 0); } else { behavior = &tap_hold->config->behaviors->tap; + struct device *behavior_device = device_get_binding(behavior->behavior_dev); + behavior_keymap_binding_released(behavior_device, tap_hold->position, tap_hold->param_tap, 0); } - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_released(behavior_device, tap_hold->position, behavior->param1, behavior->param2); if (work_cancel_result == -EINPROGRESS) { // let the timer handler clean up @@ -455,15 +463,15 @@ static struct behavior_tap_hold_data behavior_tap_hold_data; #define _TRANSFORM_ENTRY(idx, node) \ { \ .behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \ - .param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), (DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \ - .param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), (DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \ + .param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), (DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), (DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \ }, #define KP_INST(n) \ static k_timeout_t behavior_tap_hold_config_##n##_gettime() { return K_MSEC(DT_INST_PROP(n, tapping_term_ms)); } \ static struct behavior_tap_hold_behaviors behavior_tap_hold_behaviors_##n = { \ - .tap = _TRANSFORM_ENTRY(0, n) \ - .hold = _TRANSFORM_ENTRY(1, n) \ + .hold = _TRANSFORM_ENTRY(0, n) \ + .tap = _TRANSFORM_ENTRY(1, n) \ }; \ static struct behavior_tap_hold_config behavior_tap_hold_config_##n = { \ .behaviors = &behavior_tap_hold_behaviors_##n, \ diff --git a/app/tests/tap-hold/balanced/behavior_keymap.dtsi b/app/tests/tap-hold/balanced/behavior_keymap.dtsi index a1314204..3fbc77ea 100644 --- a/app/tests/tap-hold/balanced/behavior_keymap.dtsi +++ b/app/tests/tap-hold/balanced/behavior_keymap.dtsi @@ -3,46 +3,14 @@ #include / { - behaviors { - fsf: behavior_f_shift { - compatible = "zmk,behavior-tap-hold"; - label = "f-shift"; - #binding-cells = <0>; - tapping_term_ms = <300>; - bindings = <&kp F>, <&kp LSFT>; - flavor = "balanced"; - }; - - jct: behavior_j_ctrl { - compatible = "zmk,behavior-tap-hold"; - label = "j-ctrl"; - #binding-cells = <0>; - tapping_term_ms = <300>; - bindings = <&kp J>, <&kp LCTL>; - flavor = "balanced"; - }; - }; - keymap { compatible = "zmk,keymap"; label ="Default keymap"; default_layer { bindings = < - &fsf &jct + &ht LSFT F &ht LCTL J &kp D &kp RCTL>; }; - - lower_layer { - bindings = < - &cp M_NEXT &trans - &kp L &kp J>; - }; - - raise_layer { - bindings = < - &kp W &kp U - &kp X &kp M>; - }; }; }; diff --git a/app/tests/tap-hold/hold-preferred/behavior_keymap.dtsi b/app/tests/tap-hold/hold-preferred/behavior_keymap.dtsi index 1ab4cf9d..f5de70be 100644 --- a/app/tests/tap-hold/hold-preferred/behavior_keymap.dtsi +++ b/app/tests/tap-hold/hold-preferred/behavior_keymap.dtsi @@ -3,46 +3,14 @@ #include / { - behaviors { - fsf: behavior_f_shift { - compatible = "zmk,behavior-tap-hold"; - label = "f-shift"; - #binding-cells = <0>; - tapping_term_ms = <300>; - bindings = <&kp F>, <&kp LSFT>; - flavor = "hold-preferred"; - }; - - jct: behavior_j_ctrl { - compatible = "zmk,behavior-tap-hold"; - label = "j-ctrl"; - #binding-cells = <0>; - tapping_term_ms = <300>; - bindings = <&kp J>, <&kp LCTL>; - flavor = "hold-preferred"; - }; - }; - keymap { compatible = "zmk,keymap"; label ="Default keymap"; default_layer { bindings = < - &fsf &jct + &mt LSFT F &mt LCTL J &kp D &kp RCTL>; }; - - lower_layer { - bindings = < - &cp M_NEXT &trans - &kp L &kp J>; - }; - - raise_layer { - bindings = < - &kp W &kp U - &kp X &kp M>; - }; }; }; diff --git a/app/tests/tap-hold/tap-preferred/behavior_keymap.dtsi b/app/tests/tap-hold/tap-preferred/behavior_keymap.dtsi index 809209f5..26a0f47a 100644 --- a/app/tests/tap-hold/tap-preferred/behavior_keymap.dtsi +++ b/app/tests/tap-hold/tap-preferred/behavior_keymap.dtsi @@ -4,22 +4,13 @@ / { behaviors { - fsf: behavior_f_shift { + tp: behavior_tap_preferred { compatible = "zmk,behavior-tap-hold"; - label = "f-shift"; - #binding-cells = <0>; - tapping_term_ms = <300>; - bindings = <&kp F>, <&kp LSFT>; - flavor = "tap-preferred"; - }; - - jct: behavior_j_ctrl { - compatible = "zmk,behavior-tap-hold"; - label = "j-ctrl"; - #binding-cells = <0>; - tapping_term_ms = <300>; - bindings = <&kp J>, <&kp LCTL>; + label = "MOD_TAP"; + #binding-cells = <2>; flavor = "tap-preferred"; + tapping_term_ms = <200>; + bindings = <&kp>, <&kp>; }; }; @@ -29,20 +20,8 @@ default_layer { bindings = < - &fsf &jct + &mt LSFT F &mt LCTL J &kp D &kp RCTL>; }; - - lower_layer { - bindings = < - &cp M_NEXT &trans - &kp L &kp J>; - }; - - raise_layer { - bindings = < - &kp W &kp U - &kp X &kp M>; - }; }; };