feat(behaviors): Add reusable sensor behaviors.
* Add new sensor behaviors that either take full bindings add definition, or accept parameters when bound in the keymap. * Remove existing hard-coded key press sensor behavior and instead leverage new generic sensor behaviors to achieve the same functionality. Co-authored-by: nick@conway.dev
This commit is contained in:
parent
9a73650041
commit
3db163aa2c
17 changed files with 301 additions and 107 deletions
|
@ -51,7 +51,9 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||||
target_sources(app PRIVATE src/behaviors/behavior_to_layer.c)
|
target_sources(app PRIVATE src/behaviors/behavior_to_layer.c)
|
||||||
target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
|
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_none.c)
|
||||||
target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
|
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE app PRIVATE src/behaviors/behavior_sensor_rotate.c)
|
||||||
|
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR app PRIVATE src/behaviors/behavior_sensor_rotate_var.c)
|
||||||
|
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON app PRIVATE src/behaviors/behavior_sensor_rotate_common.c)
|
||||||
target_sources(app PRIVATE src/combo.c)
|
target_sources(app PRIVATE src/combo.c)
|
||||||
target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)
|
target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)
|
||||||
target_sources(app PRIVATE src/behavior_queue.c)
|
target_sources(app PRIVATE src/behavior_queue.c)
|
||||||
|
|
|
@ -350,11 +350,7 @@ config ZMK_BEHAVIORS_QUEUE_SIZE
|
||||||
int "Maximum number of behaviors to allow queueing from a macro or other complex behavior"
|
int "Maximum number of behaviors to allow queueing from a macro or other complex behavior"
|
||||||
default 64
|
default 64
|
||||||
|
|
||||||
DT_COMPAT_ZMK_BEHAVIOR_KEY_TOGGLE := zmk,behavior-key-toggle
|
rsource "Kconfig.behaviors"
|
||||||
|
|
||||||
config ZMK_BEHAVIOR_KEY_TOGGLE
|
|
||||||
bool
|
|
||||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BEHAVIOR_KEY_TOGGLE))
|
|
||||||
|
|
||||||
config ZMK_MACRO_DEFAULT_WAIT_MS
|
config ZMK_MACRO_DEFAULT_WAIT_MS
|
||||||
int "Default time to wait (in milliseconds) before triggering the next behavior in macros"
|
int "Default time to wait (in milliseconds) before triggering the next behavior in macros"
|
||||||
|
|
24
app/Kconfig.behaviors
Normal file
24
app/Kconfig.behaviors
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright (c) 2023 The ZMK Contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
config ZMK_BEHAVIOR_KEY_TOGGLE
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_ZMK_BEHAVIOR_KEY_TOGGLE_ENABLED
|
||||||
|
|
||||||
|
|
||||||
|
config ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
|
||||||
|
config ZMK_BEHAVIOR_SENSOR_ROTATE
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_ZMK_BEHAVIOR_SENSOR_ROTATE_ENABLED
|
||||||
|
select ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON
|
||||||
|
|
||||||
|
config ZMK_BEHAVIOR_SENSOR_ROTATE_VAR
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR_ENABLED
|
||||||
|
select ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON
|
|
@ -8,9 +8,10 @@
|
||||||
behaviors {
|
behaviors {
|
||||||
/* DEPRECATED: `inc_dec_cp` will be removed in the future */
|
/* DEPRECATED: `inc_dec_cp` will be removed in the future */
|
||||||
/omit-if-no-ref/ inc_dec_cp: inc_dec_kp: behavior_sensor_rotate_key_press {
|
/omit-if-no-ref/ inc_dec_cp: inc_dec_kp: behavior_sensor_rotate_key_press {
|
||||||
compatible = "zmk,behavior-sensor-rotate-key-press";
|
compatible = "zmk,behavior-sensor-rotate-var";
|
||||||
label = "ENC_KEY_PRESS";
|
label = "ENC_KEY_PRESS";
|
||||||
#sensor-binding-cells = <2>;
|
#sensor-binding-cells = <2>;
|
||||||
|
bindings = <&kp>, <&kp>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
# Copyright (c) 2020 The ZMK Contributors
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
description: Sensor rotate key press/release behavior
|
|
||||||
|
|
||||||
compatible: "zmk,behavior-sensor-rotate-key-press"
|
|
||||||
|
|
||||||
properties:
|
|
||||||
label:
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
"#sensor-binding-cells":
|
|
||||||
type: int
|
|
||||||
required: true
|
|
||||||
const: 2
|
|
||||||
|
|
||||||
sensor-binding-cells:
|
|
||||||
- param1
|
|
||||||
- param2
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Copyright (c) 2022 The ZMK Contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
description: Sensor rotate behavior
|
||||||
|
|
||||||
|
compatible: "zmk,behavior-sensor-rotate-var"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
"#sensor-binding-cells":
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
const: 2
|
||||||
|
bindings:
|
||||||
|
type: phandles
|
||||||
|
required: true
|
||||||
|
tap-ms:
|
||||||
|
type: int
|
||||||
|
default: 5
|
||||||
|
|
||||||
|
sensor-binding-cells:
|
||||||
|
- param1
|
||||||
|
- param2
|
21
app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml
Normal file
21
app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Copyright (c) 2022 The ZMK Contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
description: Sensor rotate behavior
|
||||||
|
|
||||||
|
compatible: "zmk,behavior-sensor-rotate"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
"#sensor-binding-cells":
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
const: 0
|
||||||
|
bindings:
|
||||||
|
type: phandle-array
|
||||||
|
required: true
|
||||||
|
tap-ms:
|
||||||
|
type: int
|
||||||
|
default: 5
|
|
@ -26,8 +26,7 @@ typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *b
|
||||||
struct zmk_behavior_binding_event event);
|
struct zmk_behavior_binding_event event);
|
||||||
typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding,
|
typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding,
|
||||||
const struct device *sensor,
|
const struct device *sensor,
|
||||||
uint32_t virtual_key_position,
|
struct zmk_behavior_binding_event event);
|
||||||
int64_t timestamp);
|
|
||||||
|
|
||||||
enum behavior_locality {
|
enum behavior_locality {
|
||||||
BEHAVIOR_LOCALITY_CENTRAL,
|
BEHAVIOR_LOCALITY_CENTRAL,
|
||||||
|
@ -161,13 +160,12 @@ static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_bi
|
||||||
*/
|
*/
|
||||||
__syscall int behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding,
|
__syscall int behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding,
|
||||||
const struct device *sensor,
|
const struct device *sensor,
|
||||||
uint32_t virtual_key_position,
|
struct zmk_behavior_binding_event event);
|
||||||
int64_t timestamp);
|
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding,
|
z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding,
|
||||||
const struct device *sensor,
|
const struct device *sensor,
|
||||||
uint32_t virtual_key_position, int64_t timestamp) {
|
struct zmk_behavior_binding_event event) {
|
||||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||||
|
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
|
@ -180,7 +178,7 @@ z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *bin
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return api->sensor_binding_triggered(binding, sensor, virtual_key_position, timestamp);
|
return api->sensor_binding_triggered(binding, sensor, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
40
app/src/behaviors/behavior_sensor_rotate.c
Normal file
40
app/src/behaviors/behavior_sensor_rotate.c
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT zmk_behavior_sensor_rotate
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
|
||||||
|
#include <drivers/behavior.h>
|
||||||
|
|
||||||
|
#include "behavior_sensor_rotate_common.h"
|
||||||
|
|
||||||
|
static const struct behavior_driver_api behavior_sensor_rotate_driver_api = {
|
||||||
|
.sensor_binding_triggered = zmk_behavior_sensor_rotate_common_trigger};
|
||||||
|
|
||||||
|
static int behavior_sensor_rotate_init(const struct device *dev) { return 0; };
|
||||||
|
|
||||||
|
#define _TRANSFORM_ENTRY(idx, node) \
|
||||||
|
{ \
|
||||||
|
.behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(node, bindings, idx), label), \
|
||||||
|
.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 SENSOR_ROTATE_INST(n) \
|
||||||
|
static struct behavior_sensor_rotate_config behavior_sensor_rotate_config_##n = { \
|
||||||
|
.cw_binding = _TRANSFORM_ENTRY(0, n), \
|
||||||
|
.ccw_binding = _TRANSFORM_ENTRY(1, n), \
|
||||||
|
.tap_ms = DT_INST_PROP_OR(n, tap_ms, 5), \
|
||||||
|
.override_params = false, \
|
||||||
|
}; \
|
||||||
|
DEVICE_DT_INST_DEFINE( \
|
||||||
|
n, behavior_sensor_rotate_init, NULL, NULL, &behavior_sensor_rotate_config_##n, \
|
||||||
|
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sensor_rotate_driver_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_INST)
|
52
app/src/behaviors/behavior_sensor_rotate_common.c
Normal file
52
app/src/behaviors/behavior_sensor_rotate_common.c
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/drivers/sensor.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
|
#include <zmk/behavior_queue.h>
|
||||||
|
|
||||||
|
#include "behavior_sensor_rotate_common.h"
|
||||||
|
|
||||||
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
|
int zmk_behavior_sensor_rotate_common_trigger(struct zmk_behavior_binding *binding,
|
||||||
|
const struct device *sensor,
|
||||||
|
struct zmk_behavior_binding_event event) {
|
||||||
|
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||||
|
const struct behavior_sensor_rotate_config *cfg = dev->config;
|
||||||
|
|
||||||
|
struct sensor_value value;
|
||||||
|
|
||||||
|
const int err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value);
|
||||||
|
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_WRN("Failed to get sensor rotation value: %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct zmk_behavior_binding triggered_binding;
|
||||||
|
switch (value.val1) {
|
||||||
|
case 1:
|
||||||
|
triggered_binding = cfg->cw_binding;
|
||||||
|
if (cfg->override_params) {
|
||||||
|
triggered_binding.param1 = binding->param1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
triggered_binding = cfg->ccw_binding;
|
||||||
|
if (cfg->override_params) {
|
||||||
|
triggered_binding.param1 = binding->param2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Sensor binding: %s", binding->behavior_dev);
|
||||||
|
|
||||||
|
zmk_behavior_queue_add(event.position, triggered_binding, true, cfg->tap_ms);
|
||||||
|
zmk_behavior_queue_add(event.position, triggered_binding, false, 0);
|
||||||
|
|
||||||
|
return ZMK_BEHAVIOR_OPAQUE;
|
||||||
|
}
|
13
app/src/behaviors/behavior_sensor_rotate_common.h
Normal file
13
app/src/behaviors/behavior_sensor_rotate_common.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
#include <zmk/behavior.h>
|
||||||
|
|
||||||
|
struct behavior_sensor_rotate_config {
|
||||||
|
struct zmk_behavior_binding cw_binding;
|
||||||
|
struct zmk_behavior_binding ccw_binding;
|
||||||
|
int tap_ms;
|
||||||
|
bool override_params;
|
||||||
|
};
|
||||||
|
|
||||||
|
int zmk_behavior_sensor_rotate_common_trigger(struct zmk_behavior_binding *binding,
|
||||||
|
const struct device *sensor,
|
||||||
|
struct zmk_behavior_binding_event event);
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 The ZMK Contributors
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DT_DRV_COMPAT zmk_behavior_sensor_rotate_key_press
|
|
||||||
|
|
||||||
#include <zephyr/device.h>
|
|
||||||
#include <zephyr/drivers/sensor.h>
|
|
||||||
#include <zephyr/logging/log.h>
|
|
||||||
|
|
||||||
#include <drivers/behavior.h>
|
|
||||||
#include <zmk/event_manager.h>
|
|
||||||
#include <zmk/events/keycode_state_changed.h>
|
|
||||||
|
|
||||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|
||||||
|
|
||||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
|
||||||
|
|
||||||
static int behavior_sensor_rotate_key_press_init(const struct device *dev) { return 0; };
|
|
||||||
|
|
||||||
static int on_sensor_binding_triggered(struct zmk_behavior_binding *binding,
|
|
||||||
const struct device *sensor, uint32_t virtual_key_position,
|
|
||||||
int64_t timestamp) {
|
|
||||||
struct sensor_value value;
|
|
||||||
int err;
|
|
||||||
uint32_t keycode;
|
|
||||||
LOG_DBG("inc keycode 0x%02X dec keycode 0x%02X", binding->param1, binding->param2);
|
|
||||||
|
|
||||||
err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
LOG_WRN("Failed to ge sensor rotation value: %d", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (value.val1) {
|
|
||||||
case 1:
|
|
||||||
keycode = binding->param1;
|
|
||||||
break;
|
|
||||||
case -1:
|
|
||||||
keycode = binding->param2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DBG("SEND %d", keycode);
|
|
||||||
|
|
||||||
ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(keycode, true, timestamp));
|
|
||||||
|
|
||||||
// TODO: Better way to do this?
|
|
||||||
k_msleep(5);
|
|
||||||
|
|
||||||
return ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(keycode, false, timestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_sensor_rotate_key_press_driver_api = {
|
|
||||||
.sensor_binding_triggered = on_sensor_binding_triggered};
|
|
||||||
|
|
||||||
#define KP_INST(n) \
|
|
||||||
DEVICE_DT_INST_DEFINE(n, behavior_sensor_rotate_key_press_init, NULL, NULL, NULL, APPLICATION, \
|
|
||||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
|
||||||
&behavior_sensor_rotate_key_press_driver_api);
|
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
|
||||||
|
|
||||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
|
31
app/src/behaviors/behavior_sensor_rotate_var.c
Normal file
31
app/src/behaviors/behavior_sensor_rotate_var.c
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT zmk_behavior_sensor_rotate_var
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
|
||||||
|
#include <drivers/behavior.h>
|
||||||
|
|
||||||
|
#include "behavior_sensor_rotate_common.h"
|
||||||
|
|
||||||
|
static const struct behavior_driver_api behavior_sensor_rotate_var_driver_api = {
|
||||||
|
.sensor_binding_triggered = zmk_behavior_sensor_rotate_common_trigger};
|
||||||
|
|
||||||
|
static int behavior_sensor_rotate_var_init(const struct device *dev) { return 0; };
|
||||||
|
|
||||||
|
#define SENSOR_ROTATE_VAR_INST(n) \
|
||||||
|
static struct behavior_sensor_rotate_config behavior_sensor_rotate_var_config_##n = { \
|
||||||
|
.cw_binding = {.behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 0), label)}, \
|
||||||
|
.ccw_binding = {.behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 1), label)}, \
|
||||||
|
.tap_ms = DT_INST_PROP(n, tap_ms), \
|
||||||
|
.override_params = true, \
|
||||||
|
}; \
|
||||||
|
DEVICE_DT_INST_DEFINE( \
|
||||||
|
n, behavior_sensor_rotate_var_init, NULL, NULL, &behavior_sensor_rotate_var_config_##n, \
|
||||||
|
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sensor_rotate_var_driver_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_VAR_INST)
|
|
@ -270,8 +270,9 @@ int zmk_keymap_sensor_triggered(uint8_t sensor_number, const struct device *sens
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_number);
|
struct zmk_behavior_binding_event event = {
|
||||||
ret = behavior_sensor_keymap_binding_triggered(binding, sensor, position, timestamp);
|
.position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_number), .timestamp = timestamp};
|
||||||
|
ret = behavior_sensor_keymap_binding_triggered(binding, sensor, event);
|
||||||
|
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
LOG_DBG("behavior processing to continue to next layer");
|
LOG_DBG("behavior processing to continue to next layer");
|
||||||
|
|
77
docs/docs/behaviors/sensor-rotate.md
Normal file
77
docs/docs/behaviors/sensor-rotate.md
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
---
|
||||||
|
title: Sensor Rotation
|
||||||
|
sidebar_label: Sensor Rotation
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
The Sensor Rotation behavior triggers a different behavior, depending on whether the sensor is rotated clockwise or counter-clockwise. Two variants of this behavior are available, allowing either fully specifying the
|
||||||
|
two behaviors and their parameters together, or allowing binding the sensor rotation with different clockwise and counterclockwise parameters in the keymap itself.
|
||||||
|
|
||||||
|
## Sensor Rotation
|
||||||
|
|
||||||
|
The standard sensor rotation behavior allows fully binding behaviors to be invoked:
|
||||||
|
|
||||||
|
- If rotated counter-clockwise, the first bound behavior is triggered.
|
||||||
|
- If rotated clockwise, the second bound behavior is triggered.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Here is an example that binds the [RGB Underglow Behavior](/docs/behaviors/underglow.md) to change the RGB brightness:
|
||||||
|
|
||||||
|
```
|
||||||
|
/ {
|
||||||
|
behaviors {
|
||||||
|
rgb_encoder: rgb_encoder {
|
||||||
|
compatible = "zmk,behavior-sensor-rotate";
|
||||||
|
label = "RGB_ENCODER";
|
||||||
|
#sensor-binding-cells = <0>;
|
||||||
|
bindings = <&rgb_ug RGB_BRD>, <&rgb_ug RGB_BRI>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
keymap {
|
||||||
|
compatible = "zmk,keymap";
|
||||||
|
|
||||||
|
base {
|
||||||
|
...
|
||||||
|
sensor-bindings = <&rgb_encoder>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Variable Sensor Rotation
|
||||||
|
|
||||||
|
The variable sensor rotation behavior is configured with two behaviors that each expect a single parameter,
|
||||||
|
allowing the sensor rotation instance to be bound with two parameters at usage time.
|
||||||
|
|
||||||
|
- If rotated counter-clockwise, the first bound behavior is triggered with the first parameter passed to the sensor rotation.
|
||||||
|
- If rotated clockwise, the second bound behavior is triggered with the second parameter passed to the sensor rotation.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Here is an example, showing how send key presses on rotation:
|
||||||
|
|
||||||
|
First, defining the sensor rotation itself, binding the [Key Press Behavior](/docs/behaviors/key-press.md) twice, then binding it in the `sensor-bindings` property of a keymap layer:
|
||||||
|
|
||||||
|
```
|
||||||
|
/ {
|
||||||
|
behaviors {
|
||||||
|
rot_kp: behavior_sensor_rotate_kp {
|
||||||
|
compatible = "zmk,behavior-sensor-rotate-var";
|
||||||
|
label = "ENC_KP";
|
||||||
|
#sensor-binding-cells = <2>;
|
||||||
|
bindings = <&kp>, <&kp>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
keymap {
|
||||||
|
compatible = "zmk,keymap";
|
||||||
|
base {
|
||||||
|
...
|
||||||
|
sensor-bindings = <&rot_kp PG_DN PG_UP>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
|
@ -23,17 +23,17 @@ Keyboards and macropads with encoder support will typically take the two EC11 pi
|
||||||
|
|
||||||
### Rotation
|
### Rotation
|
||||||
|
|
||||||
Rotation is handled separately as a type of sensor. The behavior for this is set in `sensor-bindings`, which is defined in each keymap layer in the following format:
|
Rotation is handled separately as a type of sensor. The behavior for this is set in `sensor-bindings`. See [Sensor Rotation](../behaviors/sensor-rotate.md) for customizing this behavior.
|
||||||
|
|
||||||
```
|
```
|
||||||
sensor-bindings = <BINDING CW_KEY CCW_KEY>;
|
sensor-bindings = <BINDING [CW_KEY] [CCW_KEY]>;
|
||||||
```
|
```
|
||||||
|
|
||||||
- `BINDING`, for now, has only one behavior available; `&inc_dec_kp` for key presses (see [Key Press](../behaviors/key-press.md) for details on available keycodes).
|
- `BINDING` is either a user-defined behavior, or `&inc_dec_kp` for key presses (see [Key Press](../behaviors/key-press.md) for details on available keycodes).
|
||||||
- `CW_KEY` is the keycode activated by a clockwise turn.
|
- `CW_KEY` is the keycode activated by a clockwise turn.
|
||||||
- `CCW_KEY` is the keycode activated by a counter-clockwise turn.
|
- `CCW_KEY` is the keycode activated by a counter-clockwise turn.
|
||||||
|
|
||||||
Additional encoders can be configured by adding more `BINDING CW_KEY CCW_KEY` sets immediately after the first.
|
Additional encoders can be configured by adding more bindings immediately after the first.
|
||||||
|
|
||||||
As an example, a complete `sensor-bindings` for a Kyria with two encoders could look like:
|
As an example, a complete `sensor-bindings` for a Kyria with two encoders could look like:
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ module.exports = {
|
||||||
"behaviors/tap-dance",
|
"behaviors/tap-dance",
|
||||||
"behaviors/caps-word",
|
"behaviors/caps-word",
|
||||||
"behaviors/key-repeat",
|
"behaviors/key-repeat",
|
||||||
|
"behaviors/sensor-rotate",
|
||||||
"behaviors/reset",
|
"behaviors/reset",
|
||||||
"behaviors/bluetooth",
|
"behaviors/bluetooth",
|
||||||
"behaviors/outputs",
|
"behaviors/outputs",
|
||||||
|
|
Loading…
Add table
Reference in a new issue