From 6d2babd26e38e0c5665d6694282a6cc7f9a3f4fb Mon Sep 17 00:00:00 2001 From: Okke Formsma Date: Wed, 10 Mar 2021 20:10:04 +0100 Subject: [PATCH] feat(behavior): Macros --- app/CMakeLists.txt | 1 + .../behaviors/zmk,behavior-macro.yaml | 16 ++++ app/src/behaviors/behavior_macro.c | 89 +++++++++++++++++++ app/tests/macro/key-down/events.patterns | 1 + .../macro/key-down/keycode_events.snapshot | 6 ++ app/tests/macro/key-down/native_posix.keymap | 39 ++++++++ 6 files changed, 152 insertions(+) create mode 100644 app/dts/bindings/behaviors/zmk,behavior-macro.yaml create mode 100644 app/src/behaviors/behavior_macro.c create mode 100644 app/tests/macro/key-down/events.patterns create mode 100644 app/tests/macro/key-down/keycode_events.snapshot create mode 100644 app/tests/macro/key-down/native_posix.keymap diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index e283487f..5af5765c 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -46,6 +46,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) 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_macro.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/bindings/behaviors/zmk,behavior-macro.yaml b/app/dts/bindings/behaviors/zmk,behavior-macro.yaml new file mode 100644 index 00000000..71b7ff87 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-macro.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro + +compatible: "zmk,behavior-macro" + +include: zero_param.yaml + +properties: + bindings: + type: phandle-array + required: true + sleep: + type: int + default: 10 diff --git a/app/src/behaviors/behavior_macro.c b/app/src/behaviors/behavior_macro.c new file mode 100644 index 00000000..3470dbf9 --- /dev/null +++ b/app/src/behaviors/behavior_macro.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT zmk_behavior_macro + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +struct behavior_macro_config { + int sleep; + int behavior_count; + struct zmk_behavior_binding *behaviors; +}; + +static int behavior_macro_init(const struct device *dev) { return 0; } + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct behavior_macro_config *cfg = dev->config; + + for (int index = 0; index < cfg->behavior_count; index++) { + const struct device *behavior = device_get_binding(cfg->behaviors[index].behavior_dev); + if (!behavior) { + break; + } + behavior_keymap_binding_pressed(&cfg->behaviors[index], event); + k_msleep(cfg->sleep); + behavior_keymap_binding_released(&cfg->behaviors[index], event); + if (index + 1 < cfg->behavior_count) { + k_msleep(cfg->sleep); + } + } + return ZMK_BEHAVIOR_OPAQUE; +} + +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_macro_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +#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))), \ + }, + +#define TRANSFORMED_BINDINGS(node) \ + { UTIL_LISTIFY(DT_INST_PROP_LEN(node, bindings), _TRANSFORM_ENTRY, node) } + +#define KP_INST(n) \ + static struct zmk_behavior_binding \ + behavior_macro_config_##n##_bindings[DT_INST_PROP_LEN(n, bindings)] = \ + TRANSFORMED_BINDINGS(n); \ + static struct behavior_macro_config behavior_macro_config_##n = { \ + .behaviors = behavior_macro_config_##n##_bindings, \ + .behavior_count = DT_INST_PROP_LEN(n, bindings), \ + .sleep = DT_INST_PROP(n, sleep), \ + }; \ + DEVICE_AND_API_INIT(behavior_macro_##n, DT_INST_LABEL(n), behavior_macro_init, NULL, \ + &behavior_macro_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_macro_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) +#endif \ No newline at end of file diff --git a/app/tests/macro/key-down/events.patterns b/app/tests/macro/key-down/events.patterns new file mode 100644 index 00000000..833100f6 --- /dev/null +++ b/app/tests/macro/key-down/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/macro/key-down/keycode_events.snapshot b/app/tests/macro/key-down/keycode_events.snapshot new file mode 100644 index 00000000..7ad856db --- /dev/null +++ b/app/tests/macro/key-down/keycode_events.snapshot @@ -0,0 +1,6 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macro/key-down/native_posix.keymap b/app/tests/macro/key-down/native_posix.keymap new file mode 100644 index 00000000..7e5edb5a --- /dev/null +++ b/app/tests/macro/key-down/native_posix.keymap @@ -0,0 +1,39 @@ +#include +#include +#include + +/ { + behaviors { + macro_1: macro_1 { + compatible = "zmk,behavior-macro"; + label = "MACRO_1"; + #binding-cells = <0>; + bindings = <&kp A>, <&kp B>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + ¯o_1 &kp C + &none &none + >; + }; + }; +}; + + +&kscan { + events = < + /* press combo */ + ZMK_MOCK_PRESS(0,0,10) + /* press and release other key */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* release combo */ + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file