mirror of https://github.com/zmkfirmware/zmk.git
feat: Refactor behaviors, sensor to raise behavior_binding_event
This commit is contained in:
parent
ac7f75b859
commit
d88dbd252c
|
|
@ -38,6 +38,7 @@ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c)
|
|||
target_sources_ifdef(CONFIG_ZMK_GPIO_KEY_WAKEUP_TRIGGER app PRIVATE src/gpio_key_wakeup_trigger.c)
|
||||
target_sources(app PRIVATE src/events/activity_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/position_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/behavior_binding_event.c)
|
||||
target_sources(app PRIVATE src/events/sensor_event.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c)
|
||||
|
|
|
|||
|
|
@ -56,20 +56,8 @@ struct behavior_parameter_metadata {
|
|||
const struct behavior_parameter_metadata_set *sets;
|
||||
};
|
||||
|
||||
enum behavior_sensor_binding_process_mode {
|
||||
BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER,
|
||||
BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD,
|
||||
};
|
||||
|
||||
typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event);
|
||||
typedef int (*behavior_sensor_keymap_binding_process_callback_t)(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode);
|
||||
typedef int (*behavior_sensor_keymap_binding_accept_data_callback_t)(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data channel_data[channel_data_size]);
|
||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||
typedef int (*behavior_get_parameter_metadata_t)(
|
||||
const struct device *behavior, struct behavior_parameter_metadata *param_metadata);
|
||||
|
|
@ -86,8 +74,7 @@ __subsystem struct behavior_driver_api {
|
|||
behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params;
|
||||
behavior_keymap_binding_callback_t binding_pressed;
|
||||
behavior_keymap_binding_callback_t binding_released;
|
||||
behavior_sensor_keymap_binding_accept_data_callback_t sensor_binding_accept_data;
|
||||
behavior_sensor_keymap_binding_process_callback_t sensor_binding_process;
|
||||
behavior_keymap_binding_callback_t sensor_binding_process;
|
||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||
behavior_get_parameter_metadata_t get_parameter_metadata;
|
||||
const struct behavior_parameter_metadata *parameter_metadata;
|
||||
|
|
@ -371,41 +358,6 @@ static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_bi
|
|||
return api->binding_released(binding, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle the a sensor keymap binding processing any incoming data from the sensor
|
||||
* @param binding Sensor keymap binding which was triggered.
|
||||
* @param sensor Pointer to the sensor device structure for the sensor driver instance.
|
||||
* @param virtual_key_position ZMK_KEYMAP_LEN + sensor number
|
||||
* @param timestamp Time at which the binding was triggered.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval Negative errno code if failure.
|
||||
*/
|
||||
__syscall int behavior_sensor_keymap_binding_accept_data(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data *channel_data);
|
||||
|
||||
static inline int z_impl_behavior_sensor_keymap_binding_accept_data(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data *channel_data) {
|
||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
|
||||
if (dev == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
|
||||
|
||||
if (api->sensor_binding_accept_data == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return api->sensor_binding_accept_data(binding, event, sensor_config, channel_data_size,
|
||||
channel_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle the keymap sensor binding being triggered after updating any local data
|
||||
* @param dev Pointer to the device structure for the driver instance.
|
||||
|
|
@ -418,14 +370,12 @@ static inline int z_impl_behavior_sensor_keymap_binding_accept_data(
|
|||
// clang-format off
|
||||
__syscall int behavior_sensor_keymap_binding_process(
|
||||
struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode);
|
||||
struct zmk_behavior_binding_event event);
|
||||
// clang-format on
|
||||
|
||||
static inline int
|
||||
z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode) {
|
||||
struct zmk_behavior_binding_event event) {
|
||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
|
||||
if (dev == NULL) {
|
||||
|
|
@ -438,9 +388,8 @@ z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *bindi
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return api->sensor_binding_process(binding, event, mode);
|
||||
return api->sensor_binding_process(binding, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -8,29 +8,10 @@
|
|||
|
||||
#include <zephyr/device.h>
|
||||
|
||||
// TODO: Remove this
|
||||
|
||||
#define ZMK_BEHAVIOR_OPAQUE 0
|
||||
#define ZMK_BEHAVIOR_TRANSPARENT 1
|
||||
|
||||
typedef uint16_t zmk_behavior_local_id_t;
|
||||
|
||||
struct zmk_behavior_binding {
|
||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS)
|
||||
zmk_behavior_local_id_t local_id;
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS)
|
||||
const char *behavior_dev;
|
||||
uint32_t param1;
|
||||
uint32_t param2;
|
||||
};
|
||||
|
||||
struct zmk_behavior_binding_event {
|
||||
int layer;
|
||||
uint32_t position;
|
||||
int64_t timestamp;
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
uint8_t source;
|
||||
#endif
|
||||
};
|
||||
|
||||
#include <zmk/events/behavior_binding_event.h>
|
||||
/**
|
||||
* @brief Get a const struct device* for a behavior from its @p name field.
|
||||
*
|
||||
|
|
@ -54,6 +35,8 @@ const struct device *zmk_behavior_get_binding(const char *name);
|
|||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval Negative errno code if failure.
|
||||
*
|
||||
* Deprecated. Raise the event directly instead.
|
||||
*/
|
||||
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
|
||||
struct zmk_behavior_binding_event event, bool pressed);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2025 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
typedef uint16_t zmk_behavior_local_id_t;
|
||||
|
||||
struct zmk_behavior_binding {
|
||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS)
|
||||
zmk_behavior_local_id_t local_id;
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS)
|
||||
const char *behavior_dev;
|
||||
uint32_t param1;
|
||||
uint32_t param2;
|
||||
};
|
||||
|
||||
enum trigger_type { PRESS, RELEASE, SENSOR };
|
||||
|
||||
struct zmk_behavior_binding_event {
|
||||
const struct zmk_behavior_binding *binding;
|
||||
int layer;
|
||||
uint32_t position;
|
||||
int64_t timestamp;
|
||||
enum trigger_type type;
|
||||
uint8_t source;
|
||||
};
|
||||
|
||||
ZMK_EVENT_DECLARE(zmk_behavior_binding_event);
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
#include <zmk/events/behavior_binding_event.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
|
||||
|
|
@ -68,6 +69,13 @@ int zmk_keymap_restore_layer(zmk_keymap_layer_id_t id, zmk_keymap_layer_index_t
|
|||
int zmk_keymap_move_layer(zmk_keymap_layer_index_t start_idx, zmk_keymap_layer_index_t dest_idx);
|
||||
|
||||
int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t size);
|
||||
uint8_t zmk_keymap_map_layer_id_to_index(zmk_keymap_layer_id_t layer_id);
|
||||
|
||||
#define LAYER_ID_TO_INDEX(_layer) zmk_keymap_map_layer_id_to_index(_layer)
|
||||
|
||||
#else
|
||||
|
||||
#define LAYER_ID_TO_INDEX(_layer) _layer
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -83,8 +91,9 @@ int zmk_keymap_save_changes(void);
|
|||
int zmk_keymap_discard_changes(void);
|
||||
int zmk_keymap_reset_settings(void);
|
||||
|
||||
int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
|
||||
int64_t timestamp);
|
||||
int zmk_keymap_raise_binding_event_at_layer_index(zmk_keymap_layer_id_t layer_index, uint8_t source,
|
||||
uint32_t position, enum trigger_type type,
|
||||
int64_t timestamp);
|
||||
|
||||
#define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \
|
||||
{ \
|
||||
|
|
|
|||
|
|
@ -24,9 +24,20 @@ struct zmk_sensor_config {
|
|||
uint16_t triggers_per_rotation;
|
||||
};
|
||||
|
||||
struct zmk_sensor_data {
|
||||
struct sensor_value remainder;
|
||||
int num_triggers;
|
||||
};
|
||||
|
||||
// This struct is also used for data transfer for splits, so any changes to the size, layout, etc
|
||||
// is a breaking change for the split GATT service protocol.
|
||||
struct zmk_sensor_channel_data {
|
||||
struct sensor_value value;
|
||||
enum sensor_channel channel;
|
||||
} __packed;
|
||||
|
||||
struct zmk_sensor_data *zmk_sensor_get_data(uint32_t sensor_idx);
|
||||
|
||||
void zmk_sensor_set_num_triggers(uint32_t sensor_idx, int num_triggers);
|
||||
|
||||
void zmk_sensor_set_remainder(uint32_t sensor_idx, struct sensor_value remainder);
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||
|
||||
int zmk_split_central_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event, bool state);
|
||||
struct zmk_behavior_binding_event *event);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,12 @@
|
|||
|
||||
#include <drivers/behavior.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/matrix.h>
|
||||
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
#include <zmk/events/behavior_binding_event.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
|
@ -55,29 +57,59 @@ const struct device *z_impl_behavior_get_binding(const char *name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// TODO: Delete this method as part of a breaking release
|
||||
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
|
||||
struct zmk_behavior_binding_event event, bool pressed) {
|
||||
LOG_DBG("`zmk_behavior_invoke_binding` is deprecated. Please raise a "
|
||||
"`zmk_behavior_binding_event` instead.");
|
||||
return raise_zmk_behavior_binding_event((struct zmk_behavior_binding_event){
|
||||
.binding = src_binding,
|
||||
.layer = event.layer,
|
||||
.position = event.position,
|
||||
.timestamp = event.timestamp,
|
||||
.type = pressed ? PRESS : RELEASE,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = event.source,
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Pass the event in as pointers, rather than copying in the struct
|
||||
// Make this change as part of a breaking release
|
||||
static int invoke_locally(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event, bool pressed) {
|
||||
if (pressed) {
|
||||
return behavior_keymap_binding_pressed(binding, event);
|
||||
} else {
|
||||
return behavior_keymap_binding_released(binding, event);
|
||||
struct zmk_behavior_binding_event *event) {
|
||||
switch (event->type) {
|
||||
case PRESS:
|
||||
return behavior_keymap_binding_pressed(binding, *event);
|
||||
case RELEASE:
|
||||
return behavior_keymap_binding_released(binding, *event);
|
||||
case SENSOR:
|
||||
return behavior_sensor_keymap_binding_process(binding, *event);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
|
||||
struct zmk_behavior_binding_event event, bool pressed) {
|
||||
// We want to make a copy of this, since it may be converted from
|
||||
// relative to absolute before being invoked
|
||||
struct zmk_behavior_binding binding = *src_binding;
|
||||
|
||||
const struct device *behavior = zmk_behavior_get_binding(binding.behavior_dev);
|
||||
|
||||
if (!behavior) {
|
||||
LOG_WRN("No behavior assigned to %d on layer %d", event.position, event.layer);
|
||||
return 1;
|
||||
int behavior_listener(const zmk_event_t *eh) {
|
||||
struct zmk_behavior_binding_event *event = as_zmk_behavior_binding_event(eh);
|
||||
if (event == NULL) {
|
||||
LOG_ERR("An invalid event was passed as an argument somehow.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, event);
|
||||
const struct device *behavior = zmk_behavior_get_binding(event->binding->behavior_dev);
|
||||
if (!behavior) {
|
||||
LOG_WRN("No behavior assigned to %d on layer %d", event->position, event->layer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copying the behavior is necessary so that
|
||||
* behavior_keymap_binding_convert_central_state_dependent_params (used for e.g. certain
|
||||
* RGB behaviors) does not modify it, e.g. if the behavior is stored in a combo_cfg
|
||||
*/
|
||||
struct zmk_behavior_binding binding = *(event->binding);
|
||||
int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, *event);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to convert relative to absolute behavior binding (err %d)", err);
|
||||
return err;
|
||||
|
|
@ -92,29 +124,31 @@ int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
|
|||
|
||||
switch (locality) {
|
||||
case BEHAVIOR_LOCALITY_CENTRAL:
|
||||
return invoke_locally(&binding, event, pressed);
|
||||
return invoke_locally(&binding, event);
|
||||
case BEHAVIOR_LOCALITY_EVENT_SOURCE:
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
if (event.source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) {
|
||||
return invoke_locally(&binding, event, pressed);
|
||||
} else {
|
||||
return zmk_split_central_invoke_behavior(event.source, &binding, event, pressed);
|
||||
if (event->source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) {
|
||||
return invoke_locally(&binding, event);
|
||||
}
|
||||
return zmk_split_central_invoke_behavior(event->source, &binding, event);
|
||||
#else
|
||||
return invoke_locally(&binding, event, pressed);
|
||||
return invoke_locally(&binding, event);
|
||||
#endif
|
||||
case BEHAVIOR_LOCALITY_GLOBAL:
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
for (int i = 0; i < ZMK_SPLIT_CENTRAL_PERIPHERAL_COUNT; i++) {
|
||||
zmk_split_central_invoke_behavior(i, &binding, event, pressed);
|
||||
zmk_split_central_invoke_behavior(i, &binding, event);
|
||||
}
|
||||
#endif
|
||||
return invoke_locally(&binding, event, pressed);
|
||||
return invoke_locally(&binding, event);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(behavior, behavior_listener);
|
||||
ZMK_SUBSCRIPTION(behavior, zmk_behavior_binding_event);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||
|
||||
int zmk_behavior_get_empty_param_metadata(const struct device *dev,
|
||||
|
|
|
|||
|
|
@ -30,24 +30,24 @@ static K_WORK_DELAYABLE_DEFINE(queue_work, behavior_queue_process_next);
|
|||
|
||||
static void behavior_queue_process_next(struct k_work *work) {
|
||||
struct q_item item = {.wait = 0};
|
||||
int ret;
|
||||
|
||||
while (k_msgq_get(&zmk_behavior_queue_msgq, &item, K_NO_WAIT) == 0) {
|
||||
LOG_DBG("Invoking %s: 0x%02x 0x%02x", item.binding.behavior_dev, item.binding.param1,
|
||||
item.binding.param2);
|
||||
|
||||
struct zmk_behavior_binding_event event = {.position = item.position,
|
||||
struct zmk_behavior_binding_event event = {.binding = &item.binding,
|
||||
.position = item.position,
|
||||
.timestamp = k_uptime_get(),
|
||||
.type = item.press ? PRESS : RELEASE,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = item.source
|
||||
#endif
|
||||
};
|
||||
|
||||
if (item.press) {
|
||||
zmk_behavior_invoke_binding(&item.binding, event, true);
|
||||
} else {
|
||||
zmk_behavior_invoke_binding(&item.binding, event, false);
|
||||
ret = raise_zmk_behavior_binding_event(event);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Error %d occurred while processing behavior in queue.", ret);
|
||||
}
|
||||
|
||||
LOG_DBG("Processing next queued behavior in %dms", item.wait);
|
||||
|
||||
if (item.wait > 0) {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ struct behavior_hold_tap_data {
|
|||
// this data is specific for each hold-tap
|
||||
struct active_hold_tap {
|
||||
int32_t position;
|
||||
uint8_t layer;
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
uint8_t source;
|
||||
#endif
|
||||
|
|
@ -260,6 +261,7 @@ static struct active_hold_tap *store_hold_tap(struct zmk_behavior_binding_event
|
|||
continue;
|
||||
}
|
||||
active_hold_taps[i].position = event->position;
|
||||
active_hold_taps[i].layer = event->layer;
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
active_hold_taps[i].source = event->source;
|
||||
#endif
|
||||
|
|
@ -402,60 +404,72 @@ static inline const char *decision_moment_str(enum decision_moment decision_mome
|
|||
}
|
||||
|
||||
static int press_hold_binding(struct active_hold_tap *hold_tap) {
|
||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
|
||||
.param1 = hold_tap->param_hold};
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &binding,
|
||||
.position = hold_tap->position,
|
||||
.timestamp = hold_tap->timestamp,
|
||||
.layer = hold_tap->layer,
|
||||
.type = PRESS,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = hold_tap->source,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
|
||||
.param1 = hold_tap->param_hold};
|
||||
return zmk_behavior_invoke_binding(&binding, event, true);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static int press_tap_binding(struct active_hold_tap *hold_tap) {
|
||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
|
||||
.param1 = hold_tap->param_tap};
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &binding,
|
||||
.position = hold_tap->position,
|
||||
.timestamp = hold_tap->timestamp,
|
||||
.layer = hold_tap->layer,
|
||||
.type = PRESS,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = hold_tap->source,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
|
||||
.param1 = hold_tap->param_tap};
|
||||
LOG_DBG("tapping on layer%d", hold_tap->layer);
|
||||
store_last_hold_tapped(hold_tap);
|
||||
return zmk_behavior_invoke_binding(&binding, event, true);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static int release_hold_binding(struct active_hold_tap *hold_tap) {
|
||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
|
||||
.param1 = hold_tap->param_hold};
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &binding,
|
||||
.position = hold_tap->position,
|
||||
.timestamp = hold_tap->timestamp,
|
||||
.layer = hold_tap->layer,
|
||||
.type = RELEASE,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = hold_tap->source,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
|
||||
.param1 = hold_tap->param_hold};
|
||||
return zmk_behavior_invoke_binding(&binding, event, false);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static int release_tap_binding(struct active_hold_tap *hold_tap) {
|
||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
|
||||
.param1 = hold_tap->param_tap};
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &binding,
|
||||
.position = hold_tap->position,
|
||||
.timestamp = hold_tap->timestamp,
|
||||
.layer = hold_tap->layer,
|
||||
.type = RELEASE,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = hold_tap->source,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
|
||||
.param1 = hold_tap->param_tap};
|
||||
return zmk_behavior_invoke_binding(&binding, event, false);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static int press_binding(struct active_hold_tap *hold_tap) {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ static int on_mod_morph_binding_pressed(struct zmk_behavior_binding *binding,
|
|||
} else {
|
||||
data->pressed_binding = (struct zmk_behavior_binding *)&cfg->normal_binding;
|
||||
}
|
||||
return zmk_behavior_invoke_binding(data->pressed_binding, event, true);
|
||||
event.binding = data->pressed_binding;
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
|
||||
|
|
@ -67,7 +68,8 @@ static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
|
|||
struct zmk_behavior_binding *pressed_binding = data->pressed_binding;
|
||||
data->pressed_binding = NULL;
|
||||
int err;
|
||||
err = zmk_behavior_invoke_binding(pressed_binding, event, false);
|
||||
event.binding = pressed_binding;
|
||||
err = raise_zmk_behavior_binding_event(event);
|
||||
zmk_hid_masked_modifiers_clear();
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include "behavior_sensor_rotate_common.h"
|
||||
|
||||
static const struct behavior_driver_api behavior_sensor_rotate_driver_api = {
|
||||
.sensor_binding_accept_data = zmk_behavior_sensor_rotate_common_accept_data,
|
||||
.sensor_binding_process = zmk_behavior_sensor_rotate_common_process};
|
||||
|
||||
#define _TRANSFORM_ENTRY(idx, node) \
|
||||
|
|
@ -32,9 +31,8 @@ static const struct behavior_driver_api behavior_sensor_rotate_driver_api = {
|
|||
.tap_ms = DT_INST_PROP_OR(n, tap_ms, 5), \
|
||||
.override_params = false, \
|
||||
}; \
|
||||
static struct behavior_sensor_rotate_data behavior_sensor_rotate_data_##n = {}; \
|
||||
BEHAVIOR_DT_INST_DEFINE( \
|
||||
n, NULL, NULL, &behavior_sensor_rotate_data_##n, &behavior_sensor_rotate_config_##n, \
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sensor_rotate_driver_api);
|
||||
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, NULL, &behavior_sensor_rotate_config_##n, POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&behavior_sensor_rotate_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_INST)
|
||||
|
|
|
|||
|
|
@ -4,73 +4,23 @@
|
|||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include <zmk/sensors.h>
|
||||
#include <zmk/behavior_queue.h>
|
||||
#include <zmk/virtual_key_position.h>
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
|
||||
#include "behavior_sensor_rotate_common.h"
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
int zmk_behavior_sensor_rotate_common_accept_data(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data *channel_data) {
|
||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
struct behavior_sensor_rotate_data *data = dev->data;
|
||||
|
||||
const struct sensor_value value = channel_data[0].value;
|
||||
int triggers;
|
||||
int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position);
|
||||
|
||||
// Some funky special casing for "old encoder behavior" where ticks where reported in val2 only,
|
||||
// instead of rotational degrees in val1.
|
||||
// REMOVE ME: Remove after a grace period of old ec11 sensor behavior
|
||||
if (value.val1 == 0) {
|
||||
triggers = value.val2;
|
||||
} else {
|
||||
struct sensor_value remainder = data->remainder[sensor_index][event.layer];
|
||||
|
||||
remainder.val1 += value.val1;
|
||||
remainder.val2 += value.val2;
|
||||
|
||||
if (abs(remainder.val2) >= 1000000) {
|
||||
remainder.val1 += remainder.val2 / 1000000;
|
||||
remainder.val2 %= 1000000;
|
||||
}
|
||||
|
||||
int trigger_degrees = 360 / sensor_config->triggers_per_rotation;
|
||||
triggers = remainder.val1 / trigger_degrees;
|
||||
remainder.val1 %= trigger_degrees;
|
||||
|
||||
data->remainder[sensor_index][event.layer] = remainder;
|
||||
}
|
||||
|
||||
LOG_DBG(
|
||||
"val1: %d, val2: %d, remainder: %d/%d triggers: %d inc keycode 0x%02X dec keycode 0x%02X",
|
||||
value.val1, value.val2, data->remainder[sensor_index][event.layer].val1,
|
||||
data->remainder[sensor_index][event.layer].val2, triggers, binding->param1,
|
||||
binding->param2);
|
||||
|
||||
data->triggers[sensor_index][event.layer] = triggers;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode) {
|
||||
struct zmk_behavior_binding_event event) {
|
||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
const struct behavior_sensor_rotate_config *cfg = dev->config;
|
||||
struct behavior_sensor_rotate_data *data = dev->data;
|
||||
|
||||
const int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position);
|
||||
|
||||
if (mode != BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER) {
|
||||
data->triggers[sensor_index][event.layer] = 0;
|
||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
||||
}
|
||||
|
||||
int triggers = data->triggers[sensor_index][event.layer];
|
||||
struct zmk_sensor_data *data = zmk_sensor_get_data(sensor_index);
|
||||
int triggers = data->num_triggers;
|
||||
|
||||
struct zmk_behavior_binding triggered_binding;
|
||||
if (triggers > 0) {
|
||||
|
|
@ -85,7 +35,7 @@ int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *bindi
|
|||
triggered_binding.param1 = binding->param2;
|
||||
}
|
||||
} else {
|
||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_DBG("Sensor binding: %s", binding->behavior_dev);
|
||||
|
|
@ -99,6 +49,5 @@ int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *bindi
|
|||
zmk_behavior_queue_add(&event, triggered_binding, true, cfg->tap_ms);
|
||||
zmk_behavior_queue_add(&event, triggered_binding, false, 0);
|
||||
}
|
||||
|
||||
return ZMK_BEHAVIOR_OPAQUE;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
#include <drivers/behavior.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/sensors.h>
|
||||
|
||||
struct behavior_sensor_rotate_config {
|
||||
struct zmk_behavior_binding cw_binding;
|
||||
|
|
@ -16,15 +14,5 @@ struct behavior_sensor_rotate_config {
|
|||
bool override_params;
|
||||
};
|
||||
|
||||
struct behavior_sensor_rotate_data {
|
||||
struct sensor_value remainder[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_LEN];
|
||||
int triggers[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_LEN];
|
||||
};
|
||||
|
||||
int zmk_behavior_sensor_rotate_common_accept_data(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data *channel_data);
|
||||
int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode);
|
||||
struct zmk_behavior_binding_event event);
|
||||
|
|
@ -13,7 +13,6 @@
|
|||
#include "behavior_sensor_rotate_common.h"
|
||||
|
||||
static const struct behavior_driver_api behavior_sensor_rotate_var_driver_api = {
|
||||
.sensor_binding_accept_data = zmk_behavior_sensor_rotate_common_accept_data,
|
||||
.sensor_binding_process = zmk_behavior_sensor_rotate_common_process};
|
||||
|
||||
#define SENSOR_ROTATE_VAR_INST(n) \
|
||||
|
|
@ -23,10 +22,8 @@ static const struct behavior_driver_api behavior_sensor_rotate_var_driver_api =
|
|||
.tap_ms = DT_INST_PROP(n, tap_ms), \
|
||||
.override_params = true, \
|
||||
}; \
|
||||
static struct behavior_sensor_rotate_data behavior_sensor_rotate_var_data_##n = {}; \
|
||||
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, &behavior_sensor_rotate_var_data_##n, \
|
||||
&behavior_sensor_rotate_var_config_##n, POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, NULL, &behavior_sensor_rotate_var_config_##n, \
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&behavior_sensor_rotate_var_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_VAR_INST)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ struct behavior_sticky_key_config {
|
|||
|
||||
struct active_sticky_key {
|
||||
uint32_t position;
|
||||
uint8_t layer;
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
uint8_t source;
|
||||
#endif
|
||||
|
|
@ -67,6 +68,7 @@ static struct active_sticky_key *store_sticky_key(struct zmk_behavior_binding_ev
|
|||
continue;
|
||||
}
|
||||
sticky_key->position = event->position;
|
||||
sticky_key->layer = event->layer;
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
sticky_key->source = event->source;
|
||||
#endif
|
||||
|
|
@ -108,13 +110,16 @@ static inline int press_sticky_key_behavior(struct active_sticky_key *sticky_key
|
|||
.param1 = sticky_key->param1,
|
||||
};
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &binding,
|
||||
.position = sticky_key->position,
|
||||
.layer = sticky_key->layer,
|
||||
.timestamp = timestamp,
|
||||
.type = PRESS,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = sticky_key->source,
|
||||
#endif
|
||||
};
|
||||
return zmk_behavior_invoke_binding(&binding, event, true);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static inline int release_sticky_key_behavior(struct active_sticky_key *sticky_key,
|
||||
|
|
@ -124,15 +129,18 @@ static inline int release_sticky_key_behavior(struct active_sticky_key *sticky_k
|
|||
.param1 = sticky_key->param1,
|
||||
};
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &binding,
|
||||
.position = sticky_key->position,
|
||||
.layer = sticky_key->layer,
|
||||
.timestamp = timestamp,
|
||||
.type = RELEASE,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = sticky_key->source,
|
||||
#endif
|
||||
};
|
||||
|
||||
clear_sticky_key(sticky_key);
|
||||
return zmk_behavior_invoke_binding(&binding, event, false);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static inline void on_sticky_key_timeout(struct active_sticky_key *sticky_key) {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ struct active_tap_dance {
|
|||
// Tap Dance Data
|
||||
int counter;
|
||||
uint32_t position;
|
||||
uint8_t layer;
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
uint8_t source;
|
||||
#endif
|
||||
|
|
@ -70,6 +71,7 @@ static int new_tap_dance(struct zmk_behavior_binding_event *event,
|
|||
if (ref_dance->position == ZMK_BHV_TAP_DANCE_POSITION_FREE) {
|
||||
ref_dance->counter = 0;
|
||||
ref_dance->position = event->position;
|
||||
ref_dance->layer = event->layer;
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
ref_dance->source = event->source;
|
||||
#endif
|
||||
|
|
@ -113,27 +115,34 @@ static inline int press_tap_dance_behavior(struct active_tap_dance *tap_dance, i
|
|||
tap_dance->tap_dance_decided = true;
|
||||
struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1];
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &binding,
|
||||
.position = tap_dance->position,
|
||||
.timestamp = timestamp,
|
||||
.layer = tap_dance->layer,
|
||||
.type = PRESS,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = tap_dance->source,
|
||||
#endif
|
||||
};
|
||||
return zmk_behavior_invoke_binding(&binding, event, true);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static inline int release_tap_dance_behavior(struct active_tap_dance *tap_dance,
|
||||
int64_t timestamp) {
|
||||
struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1];
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &binding,
|
||||
.position = tap_dance->position,
|
||||
.timestamp = timestamp,
|
||||
.layer = tap_dance->layer,
|
||||
.type = RELEASE,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = tap_dance->source,
|
||||
#endif
|
||||
};
|
||||
|
||||
clear_tap_dance(tap_dance);
|
||||
return zmk_behavior_invoke_binding(&binding, event, false);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static int on_tap_dance_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zmk/keymap.h>
|
||||
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
|
|
@ -16,19 +17,20 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
static int on_keymap_binding_trigger(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
||||
}
|
||||
|
||||
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
||||
// Avoid uint8_t overflow resulting in an infinite loop
|
||||
if (LAYER_ID_TO_INDEX(event.layer) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return zmk_keymap_raise_binding_event_at_layer_index(LAYER_ID_TO_INDEX(event.layer) - 1,
|
||||
event.source, event.position, event.type,
|
||||
event.timestamp);
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_transparent_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed,
|
||||
.binding_released = on_keymap_binding_released,
|
||||
.binding_pressed = on_keymap_binding_trigger,
|
||||
.binding_released = on_keymap_binding_trigger,
|
||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||
|
|
|
|||
|
|
@ -281,8 +281,11 @@ static int release_pressed_keys() {
|
|||
static inline int press_combo_behavior(int combo_idx, const struct combo_cfg *combo,
|
||||
int32_t timestamp) {
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &combo->behavior,
|
||||
.layer = 0, // Combos don't have layers, so their layer is set to be the base layer.
|
||||
.position = ZMK_VIRTUAL_KEY_POSITION_COMBO(combo_idx),
|
||||
.timestamp = timestamp,
|
||||
.type = PRESS,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
||||
#endif
|
||||
|
|
@ -290,20 +293,23 @@ static inline int press_combo_behavior(int combo_idx, const struct combo_cfg *co
|
|||
|
||||
last_combo_timestamp = timestamp;
|
||||
|
||||
return zmk_behavior_invoke_binding(&combo->behavior, event, true);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static inline int release_combo_behavior(int combo_idx, const struct combo_cfg *combo,
|
||||
int32_t timestamp) {
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.binding = &combo->behavior,
|
||||
.layer = 0, // Combos don't have layers, so their layer is set to be the base layer.
|
||||
.position = ZMK_VIRTUAL_KEY_POSITION_COMBO(combo_idx),
|
||||
.timestamp = timestamp,
|
||||
.type = RELEASE,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
||||
#endif
|
||||
};
|
||||
|
||||
return zmk_behavior_invoke_binding(&combo->behavior, event, false);
|
||||
return raise_zmk_behavior_binding_event(event);
|
||||
}
|
||||
|
||||
static void move_pressed_keys_to_active_combo(struct active_combo *active_combo) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2025 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/events/behavior_binding_event.h>
|
||||
|
||||
ZMK_EVENT_IMPL(zmk_behavior_binding_event);
|
||||
167
app/src/keymap.c
167
app/src/keymap.c
|
|
@ -22,6 +22,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#include <zmk/events/position_state_changed.h>
|
||||
#include <zmk/events/layer_state_changed.h>
|
||||
#include <zmk/events/sensor_event.h>
|
||||
#include <zmk/events/behavior_binding_event.h>
|
||||
|
||||
static zmk_keymap_layers_state_t _zmk_keymap_layer_locks = 0;
|
||||
static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0;
|
||||
|
|
@ -111,7 +112,7 @@ static struct zmk_behavior_binding
|
|||
|
||||
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||
|
||||
uint8_t map_layer_id_to_index(zmk_keymap_layer_id_t layer_id) {
|
||||
uint8_t zmk_keymap_map_layer_id_to_index(zmk_keymap_layer_id_t layer_id) {
|
||||
for (uint8_t i = 0; i < ZMK_KEYMAP_LAYERS_LEN; i++) {
|
||||
if (keymap_layer_orders[i] == layer_id) {
|
||||
return i;
|
||||
|
|
@ -122,12 +123,10 @@ uint8_t map_layer_id_to_index(zmk_keymap_layer_id_t layer_id) {
|
|||
}
|
||||
|
||||
#define LAYER_INDEX_TO_ID(_layer) keymap_layer_orders[_layer]
|
||||
#define LAYER_ID_TO_INDEX(_layer) map_layer_id_to_index(_layer)
|
||||
|
||||
#else
|
||||
|
||||
#define LAYER_INDEX_TO_ID(_layer) _layer
|
||||
#define LAYER_ID_TO_INDEX(_layer) _layer
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||
|
||||
|
|
@ -699,146 +698,82 @@ int zmk_keymap_reset_settings(void) { return -ENOTSUP; }
|
|||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||
|
||||
int zmk_keymap_apply_position_state(uint8_t source, zmk_keymap_layer_id_t layer_id,
|
||||
uint32_t position, bool pressed, int64_t timestamp) {
|
||||
const struct zmk_behavior_binding *binding =
|
||||
zmk_keymap_get_layer_binding_at_idx(layer_id, position);
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.layer = layer_id,
|
||||
.position = position,
|
||||
.timestamp = timestamp,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = source,
|
||||
#endif
|
||||
};
|
||||
|
||||
LOG_DBG("layer_id: %d position: %d, binding name: %s", layer_id, position,
|
||||
binding->behavior_dev);
|
||||
|
||||
return zmk_behavior_invoke_binding(binding, event, pressed);
|
||||
}
|
||||
|
||||
int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
|
||||
int64_t timestamp) {
|
||||
if (pressed) {
|
||||
zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state;
|
||||
}
|
||||
|
||||
int zmk_keymap_raise_binding_event_at_layer_index(zmk_keymap_layer_id_t layer_index, uint8_t source,
|
||||
uint32_t position, enum trigger_type type,
|
||||
int64_t timestamp) {
|
||||
// We use int here to be sure we don't loop layer_idx back to UINT8_MAX
|
||||
for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1;
|
||||
layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default); layer_idx--) {
|
||||
zmk_keymap_layer_id_t layer_id = LAYER_INDEX_TO_ID(layer_idx);
|
||||
for (int layer_idx = layer_index; layer_idx >= 0; layer_idx--) {
|
||||
zmk_keymap_layer_id_t candidate_layer = LAYER_INDEX_TO_ID(layer_idx);
|
||||
|
||||
if (layer_id == ZMK_KEYMAP_LAYER_ID_INVAL) {
|
||||
if (candidate_layer >= ZMK_KEYMAP_LAYERS_LEN) {
|
||||
continue;
|
||||
}
|
||||
if (zmk_keymap_layer_active_with_state(layer_id,
|
||||
zmk_keymap_active_behavior_layer[position])) {
|
||||
int ret =
|
||||
zmk_keymap_apply_position_state(source, layer_id, position, pressed, timestamp);
|
||||
if (ret > 0) {
|
||||
LOG_DBG("behavior processing to continue to next layer");
|
||||
continue;
|
||||
} else if (ret < 0) {
|
||||
LOG_DBG("Behavior returned error: %d", ret);
|
||||
return ret;
|
||||
if (zmk_keymap_layer_active_with_state(candidate_layer,
|
||||
zmk_keymap_active_behavior_layer[position]) ||
|
||||
(zmk_keymap_layer_active(candidate_layer) && (position >= ZMK_KEYMAP_LEN))) {
|
||||
const struct zmk_behavior_binding *binding;
|
||||
if (position >= ZMK_KEYMAP_LEN) {
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(position);
|
||||
binding = &zmk_sensor_keymap[candidate_layer][sensor_index];
|
||||
if (!zmk_behavior_get_binding(binding->behavior_dev)) {
|
||||
LOG_DBG("No behavior assigned to sensor index %d on layer %d", sensor_index,
|
||||
candidate_layer);
|
||||
continue;
|
||||
}
|
||||
LOG_DBG("layer_id: %d sensor_index: %d, binding name: %s", candidate_layer,
|
||||
sensor_index, binding->behavior_dev);
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
} else {
|
||||
return ret;
|
||||
binding = zmk_keymap_get_layer_binding_at_idx(candidate_layer, position);
|
||||
LOG_DBG("layer_id: %d position: %d, binding name: %s", candidate_layer, position,
|
||||
binding->behavior_dev);
|
||||
}
|
||||
|
||||
return raise_zmk_behavior_binding_event((struct zmk_behavior_binding_event){
|
||||
.binding = binding,
|
||||
.layer = candidate_layer,
|
||||
.position = position,
|
||||
.timestamp = timestamp,
|
||||
.type = type,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = source,
|
||||
#endif
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
int zmk_keymap_sensor_event(uint8_t sensor_index,
|
||||
const struct zmk_sensor_channel_data *channel_data,
|
||||
size_t channel_data_size, int64_t timestamp) {
|
||||
bool opaque_response = false;
|
||||
|
||||
for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1; layer_idx >= 0; layer_idx--) {
|
||||
uint8_t layer_id = LAYER_INDEX_TO_ID(layer_idx);
|
||||
|
||||
if (layer_id >= ZMK_KEYMAP_LAYERS_LEN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer_id][sensor_index];
|
||||
|
||||
LOG_DBG("layer idx: %d, layer id: %d sensor_index: %d, binding name: %s", layer_idx,
|
||||
layer_id, sensor_index, binding->behavior_dev);
|
||||
|
||||
const struct device *behavior = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
if (!behavior) {
|
||||
LOG_DBG("No behavior assigned to %d on layer %d", sensor_index, layer_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.layer = layer_id,
|
||||
.position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index),
|
||||
.timestamp = timestamp,
|
||||
};
|
||||
|
||||
int ret = behavior_sensor_keymap_binding_accept_data(
|
||||
binding, event, zmk_sensors_get_config_at_index(sensor_index), channel_data_size,
|
||||
channel_data);
|
||||
|
||||
if (ret < 0) {
|
||||
LOG_WRN("behavior data accept for behavior %s returned an error (%d). Processing to "
|
||||
"continue to next layer",
|
||||
binding->behavior_dev, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
enum behavior_sensor_binding_process_mode mode =
|
||||
(!opaque_response && layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default) &&
|
||||
zmk_keymap_layer_active(layer_id))
|
||||
? BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER
|
||||
: BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD;
|
||||
|
||||
ret = behavior_sensor_keymap_binding_process(binding, event, mode);
|
||||
|
||||
if (ret == ZMK_BEHAVIOR_OPAQUE) {
|
||||
LOG_DBG("sensor event processing complete, behavior response was opaque");
|
||||
opaque_response = true;
|
||||
} else if (ret < 0) {
|
||||
LOG_DBG("Behavior returned error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
static int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
|
||||
int64_t timestamp) {
|
||||
if (pressed) {
|
||||
zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state;
|
||||
}
|
||||
enum trigger_type type = pressed ? PRESS : RELEASE;
|
||||
|
||||
return 0;
|
||||
int ret = zmk_keymap_raise_binding_event_at_layer_index(ZMK_KEYMAP_LAYERS_LEN - 1, source,
|
||||
position, type, timestamp);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Behavior returned error: %d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
||||
int keymap_listener(const zmk_event_t *eh) {
|
||||
const struct zmk_position_state_changed *pos_ev;
|
||||
if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) {
|
||||
return zmk_keymap_position_state_changed(pos_ev->source, pos_ev->position, pos_ev->state,
|
||||
pos_ev->timestamp);
|
||||
}
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
const struct zmk_sensor_event *sensor_ev;
|
||||
if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) {
|
||||
return zmk_keymap_sensor_event(sensor_ev->sensor_index, sensor_ev->channel_data,
|
||||
sensor_ev->channel_data_size, sensor_ev->timestamp);
|
||||
}
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(keymap, keymap_listener);
|
||||
ZMK_SUBSCRIPTION(keymap, zmk_position_state_changed);
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
ZMK_SUBSCRIPTION(keymap, zmk_sensor_event);
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||
|
||||
static int keymap_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
|
||||
|
|
|
|||
|
|
@ -41,9 +41,11 @@ static int ip_behaviors_handle_event(const struct device *dev, struct input_even
|
|||
for (size_t i = 0; i < cfg->size; i++) {
|
||||
if (cfg->codes[i] == event->code) {
|
||||
struct zmk_behavior_binding_event behavior_event = {
|
||||
.binding = &cfg->bindings[i],
|
||||
.position = ZMK_VIRTUAL_KEY_POSITION_BEHAVIOR_INPUT_PROCESSOR(
|
||||
state->input_device_index, cfg->index),
|
||||
.timestamp = k_uptime_get(),
|
||||
.type = event->value ? PRESS : RELEASE,
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
||||
#endif
|
||||
|
|
@ -52,7 +54,7 @@ static int ip_behaviors_handle_event(const struct device *dev, struct input_even
|
|||
LOG_DBG("FOUND A MATCHING CODE, invoke %s for position %d with %d listeners",
|
||||
cfg->bindings[i].behavior_dev, behavior_event.position,
|
||||
ZMK_INPUT_LISTENERS_LEN);
|
||||
int ret = zmk_behavior_invoke_binding(&cfg->bindings[i], behavior_event, event->value);
|
||||
int ret = raise_zmk_behavior_binding_event(behavior_event);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#include <zmk/sensors.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/sensor_event.h>
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
#include <zmk/virtual_key_position.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/keymap.h>
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
|
||||
|
|
@ -52,6 +56,26 @@ static struct zmk_sensor_config configs[] = {
|
|||
};
|
||||
|
||||
static struct sensors_item_cfg sensors[] = {LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, (, ), 0)};
|
||||
struct zmk_sensor_data sensor_data[ZMK_KEYMAP_SENSORS_LEN] = {};
|
||||
|
||||
struct zmk_sensor_data *zmk_sensor_get_data(uint32_t sensor_idx) {
|
||||
if (sensor_idx >= ZMK_KEYMAP_SENSORS_LEN) {
|
||||
return NULL;
|
||||
}
|
||||
return &sensor_data[sensor_idx];
|
||||
};
|
||||
|
||||
void zmk_sensor_set_num_triggers(uint32_t sensor_idx, int num_triggers) {
|
||||
if (sensor_idx < ZMK_KEYMAP_SENSORS_LEN) {
|
||||
sensor_data[sensor_idx].num_triggers = num_triggers;
|
||||
}
|
||||
};
|
||||
|
||||
void zmk_sensor_set_remainder(uint32_t sensor_idx, struct sensor_value remainder) {
|
||||
if (sensor_idx < ZMK_KEYMAP_SENSORS_LEN) {
|
||||
sensor_data[sensor_idx].remainder = remainder;
|
||||
}
|
||||
};
|
||||
|
||||
static ATOMIC_DEFINE(pending_sensors, ZMK_KEYMAP_SENSORS_LEN);
|
||||
|
||||
|
|
@ -118,6 +142,49 @@ static void zmk_sensors_trigger_handler(const struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
#if (!IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL))
|
||||
|
||||
int sensor_listener(const zmk_event_t *eh) {
|
||||
const struct zmk_sensor_event *sensor_ev = as_zmk_sensor_event(eh);
|
||||
if (sensor_ev == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
uint32_t sensor_index = sensor_ev->sensor_index;
|
||||
const struct sensor_value value = sensor_ev->channel_data[0].value;
|
||||
struct zmk_sensor_data *data = zmk_sensor_get_data(sensor_index);
|
||||
const struct zmk_sensor_config *sensor_config = zmk_sensors_get_config_at_index(sensor_index);
|
||||
data->remainder.val1 += value.val1;
|
||||
data->remainder.val2 += value.val2;
|
||||
|
||||
if (data->remainder.val2 >= 1000000 || data->remainder.val2 <= 1000000) {
|
||||
data->remainder.val1 += data->remainder.val2 / 1000000;
|
||||
data->remainder.val2 %= 1000000;
|
||||
}
|
||||
|
||||
int trigger_degrees = 360 / sensor_config->triggers_per_rotation;
|
||||
int triggers = data->remainder.val1 / trigger_degrees;
|
||||
data->remainder.val1 %= trigger_degrees;
|
||||
zmk_sensor_set_remainder(sensor_index, data->remainder);
|
||||
zmk_sensor_set_num_triggers(sensor_index, triggers);
|
||||
|
||||
LOG_DBG("val1: %d, val2: %d, remainder: %d/%d triggers: %d", value.val1, value.val2,
|
||||
data->remainder.val1, data->remainder.val2, triggers);
|
||||
|
||||
int position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index);
|
||||
// Source is set to local for the time being, to be improved in the future
|
||||
int ret = zmk_keymap_raise_binding_event_at_layer_index(ZMK_KEYMAP_LAYERS_LEN - 1,
|
||||
ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
||||
position, SENSOR, sensor_ev->timestamp);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Behavior returned error: %d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(sensors, sensor_listener);
|
||||
ZMK_SUBSCRIPTION(sensors, zmk_sensor_event);
|
||||
#endif
|
||||
|
||||
static void zmk_sensors_init_item(uint8_t i) {
|
||||
LOG_DBG("Init sensor at index %d", i);
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ int zmk_split_transport_central_peripheral_event_handler(
|
|||
}
|
||||
|
||||
int zmk_split_central_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event, bool state) {
|
||||
struct zmk_behavior_binding_event *event) {
|
||||
if (!active_transport || !active_transport->api || !active_transport->api->send_command) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -93,12 +93,22 @@ int zmk_split_central_invoke_behavior(uint8_t source, struct zmk_behavior_bindin
|
|||
{
|
||||
.param1 = binding->param1,
|
||||
.param2 = binding->param2,
|
||||
.position = event.position,
|
||||
.event_source = event.source,
|
||||
.state = state ? 1 : 0,
|
||||
.position = event->position,
|
||||
.event_source = event->source,
|
||||
.state = (event->type == PRESS) ? 1 : 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
switch (event->type) {
|
||||
case PRESS:
|
||||
command.data.invoke_behavior.state = 1;
|
||||
break;
|
||||
case RELEASE:
|
||||
command.data.invoke_behavior.state = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const size_t payload_dev_size = sizeof(command.data.invoke_behavior.behavior_dev);
|
||||
if (strlcpy(command.data.invoke_behavior.behavior_dev, binding->behavior_dev,
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*keymap_apply_position_state/pos_state/p
|
||||
s/.*raise_binding_event_at_layer_index/binding_ev/p
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
pos_state: layer_id: 0 position: 0, binding name: abc_macro
|
||||
binding_ev: layer_id: 0 position: 0, binding name: abc_macro
|
||||
kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
pos_state: layer_id: 0 position: 0, binding name: abc_macro
|
||||
pos_state: layer_id: 0 position: 1, binding name: momentary_layer
|
||||
pos_state: layer_id: 0 position: 1, binding name: momentary_layer
|
||||
binding_ev: layer_id: 0 position: 0, binding name: abc_macro
|
||||
binding_ev: layer_id: 0 position: 1, binding name: momentary_layer
|
||||
binding_ev: layer_id: 0 position: 1, binding name: momentary_layer
|
||||
kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
|
|
|
|||
|
|
@ -3,19 +3,28 @@
|
|||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
ht_bal: behavior_hold_tap_balanced {
|
||||
compatible = "zmk,behavior-hold-tap";
|
||||
#binding-cells = <2>;
|
||||
flavor = "balanced";
|
||||
tapping-term-ms = <300>;
|
||||
bindings = <&kp>, <&trans>;
|
||||
};
|
||||
};
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&trans &mo 1
|
||||
&kp A &none>;
|
||||
&kp A &kp B>;
|
||||
};
|
||||
|
||||
lower_layer {
|
||||
bindings = <
|
||||
&trans &trans
|
||||
&trans &kp A>;
|
||||
&trans &ht_bal C 0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_PRESS(1,1,10)
|
||||
ZMK_MOCK_RELEASE(1,1,10)
|
||||
ZMK_MOCK_PRESS(1,1,400)
|
||||
ZMK_MOCK_RELEASE(1,1,400)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
||||
Loading…
Reference in New Issue