Skip to content

Commit

Permalink
feat: Add array of behaviors
Browse files Browse the repository at this point in the history
  • Loading branch information
Nick-Munnich committed Jan 13, 2025
1 parent ae1381d commit 40b4401
Show file tree
Hide file tree
Showing 15 changed files with 182 additions and 23 deletions.
1 change: 1 addition & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.c)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_STUDIO_UNLOCK app PRIVATE src/behaviors/behavior_studio_unlock.c)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_INPUT_TWO_AXIS app PRIVATE src/behaviors/behavior_input_two_axis.c)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_ARRAY app PRIVATE src/behaviors/behavior_array.c)
target_sources(app PRIVATE src/combo.c)
target_sources(app PRIVATE src/behaviors/behavior_combo_trigger.c)
target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)
Expand Down
5 changes: 5 additions & 0 deletions app/Kconfig.behaviors
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,8 @@ config ZMK_BEHAVIOR_MACRO
bool
default y
depends on DT_HAS_ZMK_BEHAVIOR_MACRO_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_ONE_PARAM_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_TWO_PARAM_ENABLED

config ZMK_BEHAVIOR_ARRAY
bool
default y
depends on DT_HAS_ZMK_BEHAVIOR_ARRAY_ENABLED
13 changes: 13 additions & 0 deletions app/dts/bindings/behaviors/zmk,behavior-array.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT

description: Array of Behaviors

compatible: "zmk,behavior-array"

include: one_param.yaml

properties:
bindings:
type: phandle-array
required: true
79 changes: 79 additions & 0 deletions app/src/behaviors/behavior_array.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2025 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#define DT_DRV_COMPAT zmk_behavior_array

#include <zephyr/device.h>
#include <drivers/behavior.h>
#include <zephyr/logging/log.h>
#include <zmk/keymap.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)

struct behavior_array_config {
size_t behavior_count;
struct zmk_behavior_binding *behaviors;
};

static int on_array_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
const struct behavior_array_config *cfg = dev->config;
int index = binding->param1;

if (index >= cfg->behavior_count || index < 0) {
LOG_ERR("Trying to trigger an index beyond the size of the behavior array.");
return -ENOTSUP;
}
return zmk_behavior_invoke_binding((struct zmk_behavior_binding *)&cfg->behaviors[index], event,
true);
}

static int on_array_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
const struct behavior_array_config *cfg = dev->config;
int index = binding->param1;

if (index >= cfg->behavior_count || index < 0) {
LOG_ERR("Trying to trigger an index beyond the size of the behavior array.");
return -ENOTSUP;
}
return zmk_behavior_invoke_binding((struct zmk_behavior_binding *)&cfg->behaviors[index], event,
false);
}

static const struct behavior_driver_api behavior_array_driver_api = {
.binding_pressed = on_array_binding_pressed,
.binding_released = on_array_binding_released,
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
};

static int behavior_array_init(const struct device *dev) { return 0; }

#define _TRANSFORM_ENTRY(idx, node) ZMK_KEYMAP_EXTRACT_BINDING(idx, node)

#define TRANSFORMED_BINDINGS(node) \
{LISTIFY(DT_INST_PROP_LEN(node, bindings), _TRANSFORM_ENTRY, (, ), DT_DRV_INST(node))}

#define ARR_INST(n) \
static struct zmk_behavior_binding \
behavior_array_config_##n##_bindings[DT_INST_PROP_LEN(n, bindings)] = \
TRANSFORMED_BINDINGS(n); \
static struct behavior_array_config behavior_array_config_##n = { \
.behaviors = behavior_array_config_##n##_bindings, \
.behavior_count = DT_INST_PROP_LEN(n, bindings)}; \
BEHAVIOR_DT_INST_DEFINE(n, behavior_array_init, NULL, NULL, &behavior_array_config_##n, \
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
&behavior_array_driver_api);

DT_INST_FOREACH_STATUS_OKAY(ARR_INST)

#endif
1 change: 1 addition & 0 deletions app/tests/array/1-indicies/events.patterns
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s/.*hid_listener_keycode_//p
4 changes: 4 additions & 0 deletions app/tests/array/1-indicies/keycode_events.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
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
10 changes: 10 additions & 0 deletions app/tests/array/1-indicies/native_posix_64.keymap
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "../behavior_keymap.dtsi"

&kscan {
events = <
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_RELEASE(0,0,10)
ZMK_MOCK_PRESS(0,1,10)
ZMK_MOCK_RELEASE(0,1,10)
>;
};
1 change: 1 addition & 0 deletions app/tests/array/2a-nesting/events.patterns
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s/.*hid_listener_keycode_//p
4 changes: 4 additions & 0 deletions app/tests/array/2a-nesting/keycode_events.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pressed: usage_page 0x07 keycode 0x29 implicit_mods 0x00 explicit_mods 0x00
released: usage_page 0x07 keycode 0x29 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
10 changes: 10 additions & 0 deletions app/tests/array/2a-nesting/native_posix_64.keymap
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "../behavior_keymap.dtsi"

&kscan {
events = <
ZMK_MOCK_PRESS(1,0,10)
ZMK_MOCK_RELEASE(1,0,10)
ZMK_MOCK_PRESS(1,0,500)
ZMK_MOCK_RELEASE(1,0,10)
>;
};
1 change: 1 addition & 0 deletions app/tests/array/2b-nesting/events.patterns
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s/.*hid_listener_keycode_//p
4 changes: 4 additions & 0 deletions app/tests/array/2b-nesting/keycode_events.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00
pressed: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00
released: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00
released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00
10 changes: 10 additions & 0 deletions app/tests/array/2b-nesting/native_posix_64.keymap
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "../behavior_keymap.dtsi"

&kscan {
events = <
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_PRESS(1,1,10)
ZMK_MOCK_RELEASE(1,1,10)
ZMK_MOCK_RELEASE(0,0,10)
>;
};
32 changes: 32 additions & 0 deletions app/tests/array/behavior_keymap.dtsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>

/ {
behaviors {
arr: behavior_array {
compatible = "zmk,behavior-array";
#binding-cells = <1>;
bindings = <&mt LEFT_SHIFT A &kp B &kp C &gresc>;
};

ht_bal: behavior_hold_tap_balanced {
compatible = "zmk,behavior-hold-tap";
#binding-cells = <2>;
flavor = "balanced";
tapping-term-ms = <200>;
bindings = <&arr>, <&arr>;
};
};

keymap {
compatible = "zmk,keymap";

default_layer {
bindings = <
&arr 0 &arr 1
&ht_bal 2 3 &arr 3
>;
};
};
};
30 changes: 7 additions & 23 deletions app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,16 @@
};
};

macros {
ZMK_MACRO(combo1_macro, bindings
= <&macro_press &mt LEFT_CONTROL A>
, <&macro_pause_for_release>
, <&macro_release &mt LEFT_CONTROL A>;
)
ZMK_MACRO(combo2_macro, bindings
= <&macro_press &mt RIGHT_CONTROL B>
, <&macro_pause_for_release>
, <&macro_release &mt RIGHT_CONTROL B>;
)
};

behaviors {
combo1: combo_trigger1{
compatible = "zmk,behavior-combo-trigger";
#binding-cells = <2>;
fallback-behavior = <&combo1_macro>;
arr: behavior_array {
compatible = "zmk,behavior-array";
#binding-cells = <1>;
bindings = <&mt LEFT_CONTROL A &mt RIGHT_CONTROL B &none>;
};
combo2: combo_trigger2{
combo: combo_trigger1{
compatible = "zmk,behavior-combo-trigger";
#binding-cells = <2>;
fallback-behavior = <&combo2_macro>;
fallback-behavior = <&arr>;
};
};

Expand All @@ -55,16 +42,13 @@

default_layer {
bindings = <
&combo1 0 0 &combo2 1 0 &none &none
&combo 0 0 &combo 1 1 &combo 2 2 &combo 3 2
>;
};
};
};

&kscan {
// There is an issue with the test setup where it exits
// before timeout of the second press
// The third
events = <
ZMK_MOCK_PRESS(0,0,0)
ZMK_MOCK_PRESS(0,1,300)
Expand Down

0 comments on commit 40b4401

Please sign in to comment.