mirror of https://github.com/zmkfirmware/zmk.git
chore: Add basic tests for Studio's layer manipulation (#3164)
chore: Add test behaviors for Studio testing chore: Add basic tests for studio layer adjustment chore: Fixes from code review
This commit is contained in:
parent
70ab6b243a
commit
19582174f3
|
|
@ -11,11 +11,12 @@
|
|||
#include <zephyr/devicetree.h>
|
||||
|
||||
#define ZMK_KEYMAP_LAYERS_FOREACH(_fn) \
|
||||
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_STUDIO), (DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), _fn)), \
|
||||
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING), \
|
||||
(DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), _fn)), \
|
||||
(DT_FOREACH_CHILD_STATUS_OKAY(DT_INST(0, zmk_keymap), _fn)))
|
||||
|
||||
#define ZMK_KEYMAP_LAYERS_FOREACH_SEP(_fn, _sep) \
|
||||
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_STUDIO), \
|
||||
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING), \
|
||||
(DT_FOREACH_CHILD_SEP(DT_INST(0, zmk_keymap), _fn, _sep)), \
|
||||
(DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_INST(0, zmk_keymap), _fn, _sep)))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
zephyr_include_directories(include)
|
||||
|
||||
add_subdirectory(drivers)
|
||||
add_subdirectory(test-behaviors)
|
||||
add_subdirectory(lib)
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
rsource "drivers/Kconfig"
|
||||
rsource "lib/Kconfig"
|
||||
rsource "lib/Kconfig"
|
||||
rsource "test-behaviors/Kconfig"
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2025 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Layer Adder Behavior
|
||||
|
||||
compatible: "zmk,behavior-add-layer"
|
||||
|
||||
include: zero_param.yaml
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2025 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Layer Mover Behavior
|
||||
|
||||
compatible: "zmk,behavior-move-layer"
|
||||
|
||||
include: two_param.yaml
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2025 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Layer Remover Behavior
|
||||
|
||||
compatible: "zmk,behavior-remove-layer"
|
||||
|
||||
include: one_param.yaml
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright (c) 2025 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Layer Binding Setter Behavior
|
||||
|
||||
compatible: "zmk,behavior-set-layer-binding-at-idx"
|
||||
|
||||
include: two_param.yaml
|
||||
|
||||
properties:
|
||||
bindings:
|
||||
type: phandle-array
|
||||
required: true
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
if (((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) AND CONFIG_ZMK_TEST_BEHAVIORS)
|
||||
target_sources(app PRIVATE behavior_add_layer.c)
|
||||
target_sources(app PRIVATE behavior_move_layer.c)
|
||||
target_sources(app PRIVATE behavior_remove_layer.c)
|
||||
target_sources(app PRIVATE behavior_set_layer_binding_at_idx.c)
|
||||
endif()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
config ZMK_TEST_BEHAVIORS
|
||||
bool "Include behaviors used for testing purposes"
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2025 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_add_layer
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if (IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)) && (DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT))
|
||||
|
||||
static int on_add_layer_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
int new_layer = zmk_keymap_add_layer();
|
||||
if (new_layer >= 0) {
|
||||
LOG_DBG("Added layer %d", new_layer);
|
||||
return 0;
|
||||
}
|
||||
switch (new_layer) {
|
||||
case -ENOSPC:
|
||||
LOG_ERR("No more layers can be added. Out of memory.");
|
||||
return -ENOSPC;
|
||||
default:
|
||||
LOG_ERR("Unknown error adding layer: %d", new_layer);
|
||||
return new_layer;
|
||||
}
|
||||
}
|
||||
|
||||
static int on_add_layer_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_add_layer_driver_api = {
|
||||
.binding_pressed = on_add_layer_binding_pressed,
|
||||
.binding_released = on_add_layer_binding_released};
|
||||
|
||||
BEHAVIOR_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||||
&behavior_add_layer_driver_api);
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) AND
|
||||
// DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2025 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_move_layer
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if (IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)) && (DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT))
|
||||
|
||||
static int on_move_layer_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
int result = zmk_keymap_move_layer(binding->param1, binding->param2);
|
||||
|
||||
if (result < 0) {
|
||||
LOG_ERR("Failed to move layer from index %d to index %d (err: %d)", binding->param1,
|
||||
binding->param2, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
LOG_DBG("Moved layer from index %d to index %d", binding->param1, binding->param2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_move_layer_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_move_layer_driver_api = {
|
||||
.binding_pressed = on_move_layer_binding_pressed,
|
||||
.binding_released = on_move_layer_binding_released};
|
||||
|
||||
BEHAVIOR_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||||
&behavior_move_layer_driver_api);
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) AND
|
||||
// DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2025 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_remove_layer
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if (IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)) && (DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT))
|
||||
|
||||
static int on_remove_layer_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
int result = zmk_keymap_remove_layer(binding->param1);
|
||||
if (result >= 0) {
|
||||
LOG_DBG("Removed layer at index %d", binding->param1);
|
||||
return 0;
|
||||
}
|
||||
switch (result) {
|
||||
case -EINVAL:
|
||||
LOG_ERR("Layer at index %d not found", binding->param1);
|
||||
return -EINVAL;
|
||||
default:
|
||||
LOG_DBG("Unknown error removing layer at index %d: %d", binding->param1, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static int on_remove_layer_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_remove_layer_driver_api = {
|
||||
.binding_pressed = on_remove_layer_binding_pressed,
|
||||
.binding_released = on_remove_layer_binding_released};
|
||||
|
||||
BEHAVIOR_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||||
&behavior_remove_layer_driver_api);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) AND
|
||||
// DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2025 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_set_layer_binding_at_idx
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
struct behavior_set_layer_binding_at_idx_config {
|
||||
size_t bindings_len;
|
||||
struct zmk_behavior_binding *bindings;
|
||||
};
|
||||
|
||||
struct behavior_set_layer_binding_at_idx_data {
|
||||
size_t current_idx;
|
||||
};
|
||||
|
||||
static int on_set_layer_binding_at_idx_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_set_layer_binding_at_idx_config *cfg = dev->config;
|
||||
struct behavior_set_layer_binding_at_idx_data *data = dev->data;
|
||||
|
||||
if (cfg->bindings_len == 0) {
|
||||
LOG_ERR("No bindings configured");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct zmk_behavior_binding *binding_to_set = &cfg->bindings[data->current_idx];
|
||||
|
||||
int result =
|
||||
zmk_keymap_set_layer_binding_at_idx(binding->param1, binding->param2, *binding_to_set);
|
||||
|
||||
if (result < 0) {
|
||||
LOG_ERR("Failed to set binding at layer %d, index %d (err: %d)", binding->param1,
|
||||
binding->param2, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
LOG_DBG("Set binding at layer %d, index %d to binding %zu/%zu", binding->param1,
|
||||
binding->param2, data->current_idx + 1, cfg->bindings_len);
|
||||
|
||||
// Move to next binding, wrap around if at end
|
||||
data->current_idx = (data->current_idx + 1) % cfg->bindings_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_set_layer_binding_at_idx_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_set_layer_binding_at_idx_driver_api = {
|
||||
.binding_pressed = on_set_layer_binding_at_idx_binding_pressed,
|
||||
.binding_released = on_set_layer_binding_at_idx_binding_released};
|
||||
|
||||
static int behavior_set_layer_binding_at_idx_init(const struct device *dev) {
|
||||
struct behavior_set_layer_binding_at_idx_data *data = dev->data;
|
||||
data->current_idx = 0;
|
||||
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 SET_LAYER_BINDING_AT_IDX_INST(n) \
|
||||
static struct behavior_set_layer_binding_at_idx_data \
|
||||
behavior_set_layer_binding_at_idx_data_##n = {}; \
|
||||
\
|
||||
static const struct zmk_behavior_binding \
|
||||
behavior_set_layer_binding_at_idx_config_##n##_bindings[DT_INST_PROP_LEN(n, bindings)] = \
|
||||
TRANSFORMED_BINDINGS(n); \
|
||||
static const struct behavior_set_layer_binding_at_idx_config \
|
||||
behavior_set_layer_binding_at_idx_config_##n = { \
|
||||
.bindings_len = DT_INST_PROP_LEN(n, bindings), \
|
||||
.bindings = behavior_set_layer_binding_at_idx_config_##n##_bindings}; \
|
||||
\
|
||||
BEHAVIOR_DT_INST_DEFINE(n, behavior_set_layer_binding_at_idx_init, NULL, \
|
||||
&behavior_set_layer_binding_at_idx_data_##n, \
|
||||
&behavior_set_layer_binding_at_idx_config_##n, POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&behavior_set_layer_binding_at_idx_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SET_LAYER_BINDING_AT_IDX_INST)
|
||||
|
||||
#endif // DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
|
@ -41,6 +41,12 @@ build_cmd="west build ${ZMK_SRC_DIR:+-s $ZMK_SRC_DIR} -d ${ZMK_BUILD_DIR}/tests/
|
|||
-b native_sim/native/64 -p -- -DCONFIG_ASSERT=y -DZMK_CONFIG="$(realpath $path)" \
|
||||
${ZMK_EXTRA_MODULES:+-DZMK_EXTRA_MODULES="$(realpath ${ZMK_EXTRA_MODULES})"}"
|
||||
|
||||
# Add extra cmake arguments from file if it exists
|
||||
if [ -f "$path/extra-cmake-args" ]; then
|
||||
extra_args=$(cat "$path/extra-cmake-args" | tr '\n' ' ')
|
||||
build_cmd="$build_cmd $extra_args"
|
||||
fi
|
||||
|
||||
build_log_tmp="${ZMK_BUILD_DIR}/tmp/$testcase/build.log"
|
||||
build_log="${ZMK_BUILD_DIR}/tests/$testcase/build.log"
|
||||
mkdir -p $(dirname $build_log_tmp)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
s/.*on_add_layer_binding_pressed/add_layer/p
|
||||
s/.*on_set_layer_binding_at_idx_binding_pressed/set_layer_binding/p
|
||||
s/.*layer_changed/layer_changed/p
|
||||
s/.*hid_listener_keycode_//p
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
-DCONFIG_ZMK_BEHAVIOR_METADATA=y
|
||||
-DCONFIG_ZMK_BEHAVIOR_LOCAL_IDS=y
|
||||
-DCONFIG_ZMK_KEYMAP_LAYER_REORDERING=y
|
||||
-DCONFIG_ZMK_KEYMAP_SETTINGS_STORAGE=y
|
||||
-DCONFIG_SETTINGS=y
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
add_layer: Added layer 1
|
||||
set_layer_binding: Set binding at layer 1, index 0 to binding 1/2
|
||||
layer_changed: layer 1 state 1 locked 0
|
||||
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
layer_changed: layer 1 state 0 locked 0
|
||||
|
|
@ -0,0 +1 @@
|
|||
CONFIG_ZMK_TEST_BEHAVIORS=y
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
// Test adding a layer, setting a binding, activating it, and pressing the binding
|
||||
&kscan {
|
||||
events = <
|
||||
// add a new layer
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
// set binding A at layer 1, position 0
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
// activate layer 1 with momentary
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
// press position 0 on new layer (should be A)
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
// release momentary layer 1
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
>;
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
add_layer: add_layer {
|
||||
compatible = "zmk,behavior-add-layer";
|
||||
#binding-cells = <0>;
|
||||
};
|
||||
|
||||
set_binding: set_binding {
|
||||
compatible = "zmk,behavior-set-layer-binding-at-idx";
|
||||
#binding-cells = <2>;
|
||||
bindings = <&kp A>, <&kp B>;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&add_layer &set_binding 1 0
|
||||
&mo 1 &kp B>;
|
||||
};
|
||||
|
||||
layer_1 {
|
||||
status = "reserved";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
s/.*layer_changed/layer_changed/p
|
||||
s/.*hid_listener_keycode_//p
|
||||
s/.*on_move_layer_binding_pressed/move_layer/p
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
-DCONFIG_ZMK_BEHAVIOR_METADATA=y
|
||||
-DCONFIG_ZMK_BEHAVIOR_LOCAL_IDS=y
|
||||
-DCONFIG_ZMK_KEYMAP_LAYER_REORDERING=y
|
||||
-DCONFIG_ZMK_KEYMAP_SETTINGS_STORAGE=y
|
||||
-DCONFIG_SETTINGS=y
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
move_layer: Moved layer from index 1 to index 2
|
||||
layer_changed: layer 1 state 1 locked 0
|
||||
layer_changed: layer 2 state 1 locked 0
|
||||
pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||
released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||
layer_changed: layer 2 state 0 locked 0
|
||||
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
|
|
@ -0,0 +1 @@
|
|||
CONFIG_ZMK_TEST_BEHAVIORS=y
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
// Test moving a layer: swap layers 1 and 2, turn both on,
|
||||
// press transparent on layer 1 at index 2
|
||||
// which should fall through to layer 2 at index 1
|
||||
&kscan {
|
||||
events = <
|
||||
// move layer 1 to position 2 (effectively swapping layers 1 and 2)
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
// activate layers 1 and 2
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_PRESS(1,1,10)
|
||||
// press position 0,1 on layer 2 - should output C from layer 2 at index 1
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
// release layer 2 (at index 1)
|
||||
ZMK_MOCK_RELEASE(1,1,10)
|
||||
// press position 0,1 again - should output A from default layer
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
move_layer: move_layer {
|
||||
compatible = "zmk,behavior-move-layer";
|
||||
#binding-cells = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&move_layer 1 2 &kp A
|
||||
&mo 1 &mo 2>;
|
||||
};
|
||||
|
||||
layer_1 {
|
||||
bindings = <
|
||||
&kp B &trans
|
||||
&trans &trans>;
|
||||
};
|
||||
|
||||
layer_2 {
|
||||
bindings = <
|
||||
&trans &kp C
|
||||
&trans &trans>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
s/.*layer_changed/layer_changed/p
|
||||
s/.*hid_listener_keycode_//p
|
||||
s/.*on_remove_layer_binding_pressed/remove_layer/p
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
-DCONFIG_ZMK_BEHAVIOR_METADATA=y
|
||||
-DCONFIG_ZMK_BEHAVIOR_LOCAL_IDS=y
|
||||
-DCONFIG_ZMK_KEYMAP_LAYER_REORDERING=y
|
||||
-DCONFIG_ZMK_KEYMAP_SETTINGS_STORAGE=y
|
||||
-DCONFIG_SETTINGS=y
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
remove_layer: Removed layer at index 1
|
||||
layer_changed: layer 1 state 1 locked 1
|
||||
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
layer_changed: layer 2 state 1 locked 1
|
||||
pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||
released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||
|
|
@ -0,0 +1 @@
|
|||
CONFIG_ZMK_TEST_BEHAVIORS=y
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
// Test removing layer 1
|
||||
&kscan {
|
||||
events = <
|
||||
// remove layer 1
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
// toggle layer 1 on
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
// press position 0,0 - should output A (layer 0) because layer 1 was removed
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
// toggle layer 2 on
|
||||
ZMK_MOCK_PRESS(1,1,10)
|
||||
ZMK_MOCK_RELEASE(1,1,10)
|
||||
// press position 0,0 - should output C (layer 2)
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
remove_layer_behavior: remove_layer_behavior {
|
||||
compatible = "zmk,behavior-remove-layer";
|
||||
#binding-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&kp A &tog 1
|
||||
&remove_layer_behavior 1 &tog 2>;
|
||||
};
|
||||
|
||||
layer_1 {
|
||||
bindings = <
|
||||
&kp B &tog 1
|
||||
&remove_layer_behavior 0 &trans>;
|
||||
};
|
||||
|
||||
layer_2 {
|
||||
bindings = <
|
||||
&kp C &trans
|
||||
&none &trans>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
s/.*layer_changed/layer_changed/p
|
||||
s/.*hid_listener_keycode_//p
|
||||
s/.*on_remove_layer_binding_pressed/remove_layer/p
|
||||
s/.*tog_keymap_binding_pressed/tog_pressed/p
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
-DCONFIG_ZMK_BEHAVIOR_METADATA=y
|
||||
-DCONFIG_ZMK_BEHAVIOR_LOCAL_IDS=y
|
||||
-DCONFIG_ZMK_KEYMAP_LAYER_REORDERING=y
|
||||
-DCONFIG_ZMK_KEYMAP_SETTINGS_STORAGE=y
|
||||
-DCONFIG_SETTINGS=y
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
tog_pressed: position 1 layer 1
|
||||
layer_changed: layer 1 state 1 locked 1
|
||||
remove_layer: Removed layer at index 0
|
||||
pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
tog_pressed: position 1 layer 1
|
||||
pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
|
|
@ -0,0 +1 @@
|
|||
CONFIG_ZMK_TEST_BEHAVIORS=y
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
// Test removing layer 0: layer 1 becomes bottom layer
|
||||
&kscan {
|
||||
events = <
|
||||
// toggle layer 1 on
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
// remove layer 0
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
// press position 0,0 - should output B (layer 1)
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
// try to toggle layer 1 off
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
// press position 0,0 - should output B
|
||||
// (layer 1 is now the bottom layer, so shouldn't be disabled)
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
This test fails because the keymap function handling position state changes doesn't work correctly when the default layer is removed.
|
||||
The iteration loop's end condition is incorrect.
|
||||
Loading…
Reference in New Issue