diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 123935402bd..c5e9b968b69 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -37,6 +37,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) diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h index 56c26a0155c..b26b4cae0f8 100644 --- a/app/include/drivers/behavior.h +++ b/app/include/drivers/behavior.h @@ -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); } - /** * @} */ diff --git a/app/include/zmk/behavior.h b/app/include/zmk/behavior.h index 5028d320257..145f8933d97 100644 --- a/app/include/zmk/behavior.h +++ b/app/include/zmk/behavior.h @@ -8,29 +8,10 @@ #include -#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 -}; +// TODO: Remove this +#define ZMK_BEHAVIOR_OPAQUE 0 +#include /** * @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); diff --git a/app/include/zmk/events/behavior_binding_event.h b/app/include/zmk/events/behavior_binding_event.h new file mode 100644 index 00000000000..f16380f035a --- /dev/null +++ b/app/include/zmk/events/behavior_binding_event.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +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); \ No newline at end of file diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index 9b7a00c61fd..463105bc938 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -7,6 +7,7 @@ #pragma once #include +#include #define ZMK_LAYER_CHILD_LEN_PLUS_ONE(node) 1 + #define ZMK_KEYMAP_LAYERS_LEN \ @@ -73,8 +74,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_idx(zmk_keymap_layer_id_t layer_id, uint8_t source, + uint32_t position, enum trigger_type type, + int64_t timestamp); #define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \ { \ diff --git a/app/include/zmk/sensors.h b/app/include/zmk/sensors.h index 1919d4ce647..4adbffa161d 100644 --- a/app/include/zmk/sensors.h +++ b/app/include/zmk/sensors.h @@ -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); \ No newline at end of file diff --git a/app/include/zmk/split/bluetooth/central.h b/app/include/zmk/split/bluetooth/central.h index 5e9e09ff6a1..0c6971d70a6 100644 --- a/app/include/zmk/split/bluetooth/central.h +++ b/app/include/zmk/split/bluetooth/central.h @@ -9,7 +9,7 @@ #endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) int zmk_split_bt_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) diff --git a/app/src/behavior.c b/app/src/behavior.c index 9b20c706265..0fb1b169260 100644 --- a/app/src/behavior.c +++ b/app/src/behavior.c @@ -24,10 +24,12 @@ #include #include +#include #include #include #include +#include #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -56,29 +58,58 @@ 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); +int behavior_listener(const zmk_event_t *eh) { + struct zmk_behavior_binding_event *event = as_zmk_behavior_binding_event(eh); + if (event == NULL) { + return -EINVAL; + } + 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 1; + LOG_WRN("No behavior assigned to %d on layer %d", event->position, event->layer); + return 0; } - int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, event); + /* + * 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; @@ -93,29 +124,32 @@ 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 ZMK_BLE_IS_CENTRAL // source is a member of event because CONFIG_ZMK_SPLIT is enabled - if (event.source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) { - return invoke_locally(&binding, event, pressed); + if (event->source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) { + return invoke_locally(&binding, event); } else { - return zmk_split_bt_invoke_behavior(event.source, &binding, event, pressed); + return zmk_split_bt_invoke_behavior(event->source, &binding, event); } #else - return invoke_locally(&binding, event, pressed); + return invoke_locally(&binding, event); #endif case BEHAVIOR_LOCALITY_GLOBAL: #if ZMK_BLE_IS_CENTRAL for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) { - zmk_split_bt_invoke_behavior(i, &binding, event, pressed); + zmk_split_bt_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, diff --git a/app/src/behavior_queue.c b/app/src/behavior_queue.c index 82c58ca8548..3c1bd71ed68 100644 --- a/app/src/behavior_queue.c +++ b/app/src/behavior_queue.c @@ -30,12 +30,14 @@ 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(), #if IS_ENABLED(CONFIG_ZMK_SPLIT) .source = item.source @@ -43,11 +45,14 @@ static void behavior_queue_process_next(struct k_work *work) { }; if (item.press) { - zmk_behavior_invoke_binding(&item.binding, event, true); + event.type = PRESS; } else { - zmk_behavior_invoke_binding(&item.binding, event, false); + event.type = RELEASE; + } + ret = raise_zmk_behavior_binding_event(event); + if (ret < 0) { + LOG_DBG("Error %d occurred while processing behavior in queue.", ret); } - LOG_DBG("Processing next queued behavior in %dms", item.wait); if (item.wait > 0) { diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c index 3df3bc86436..51b9d1f0ccd 100644 --- a/app/src/behaviors/behavior_hold_tap.c +++ b/app/src/behaviors/behavior_hold_tap.c @@ -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) { diff --git a/app/src/behaviors/behavior_mod_morph.c b/app/src/behaviors/behavior_mod_morph.c index f532f970578..69d32cb2f65 100644 --- a/app/src/behaviors/behavior_mod_morph.c +++ b/app/src/behaviors/behavior_mod_morph.c @@ -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; } diff --git a/app/src/behaviors/behavior_sensor_rotate.c b/app/src/behaviors/behavior_sensor_rotate.c index 4a59c5df976..c1160a36a47 100644 --- a/app/src/behaviors/behavior_sensor_rotate.c +++ b/app/src/behaviors/behavior_sensor_rotate.c @@ -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) diff --git a/app/src/behaviors/behavior_sensor_rotate_common.c b/app/src/behaviors/behavior_sensor_rotate_common.c index 278f1cb2be7..5a941169954 100644 --- a/app/src/behaviors/behavior_sensor_rotate_common.c +++ b/app/src/behaviors/behavior_sensor_rotate_common.c @@ -4,73 +4,23 @@ #include #include +#include #include #include #include - #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 (remainder.val2 >= 1000000 || 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; } diff --git a/app/src/behaviors/behavior_sensor_rotate_common.h b/app/src/behaviors/behavior_sensor_rotate_common.h index c92ac3d5e5f..08db14db022 100644 --- a/app/src/behaviors/behavior_sensor_rotate_common.h +++ b/app/src/behaviors/behavior_sensor_rotate_common.h @@ -6,8 +6,6 @@ #include #include -#include -#include 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); \ No newline at end of file + struct zmk_behavior_binding_event event); \ No newline at end of file diff --git a/app/src/behaviors/behavior_sensor_rotate_var.c b/app/src/behaviors/behavior_sensor_rotate_var.c index b096c46ac13..b4166b2aa3f 100644 --- a/app/src/behaviors/behavior_sensor_rotate_var.c +++ b/app/src/behaviors/behavior_sensor_rotate_var.c @@ -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) diff --git a/app/src/behaviors/behavior_sticky_key.c b/app/src/behaviors/behavior_sticky_key.c index babdeb7da24..c526ae4cdce 100644 --- a/app/src/behaviors/behavior_sticky_key.c +++ b/app/src/behaviors/behavior_sticky_key.c @@ -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) { diff --git a/app/src/behaviors/behavior_tap_dance.c b/app/src/behaviors/behavior_tap_dance.c index bbc301f1e1a..30be60b08ff 100644 --- a/app/src/behaviors/behavior_tap_dance.c +++ b/app/src/behaviors/behavior_tap_dance.c @@ -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, diff --git a/app/src/behaviors/behavior_transparent.c b/app/src/behaviors/behavior_transparent.c index 42a9d032a09..d42e19efcf5 100644 --- a/app/src/behaviors/behavior_transparent.c +++ b/app/src/behaviors/behavior_transparent.c @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -16,19 +17,15 @@ 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; + return zmk_keymap_raise_binding_event_at_layer_idx(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) diff --git a/app/src/combo.c b/app/src/combo.c index 2f547e0eea9..dd30177a497 100644 --- a/app/src/combo.c +++ b/app/src/combo.c @@ -290,8 +290,11 @@ static int release_pressed_keys() { static inline int press_combo_behavior(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 = combo->virtual_key_position, .timestamp = timestamp, + .type = PRESS, #if IS_ENABLED(CONFIG_ZMK_SPLIT) .source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL, #endif @@ -299,19 +302,22 @@ static inline int press_combo_behavior(const struct combo_cfg *combo, int32_t ti 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(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 = combo->virtual_key_position, .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) { @@ -502,6 +508,7 @@ static int position_state_changed_listener(const zmk_event_t *ev) { static int keycode_state_changed_listener(const zmk_event_t *eh) { struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); if (ev->state && !is_mod(ev->usage_page, ev->keycode)) { + LOG_DBG("help"); store_last_tapped(ev->timestamp); } return ZMK_EV_EVENT_BUBBLE; diff --git a/app/src/events/behavior_binding_event.c b/app/src/events/behavior_binding_event.c new file mode 100644 index 00000000000..e03e26b57ab --- /dev/null +++ b/app/src/events/behavior_binding_event.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_behavior_binding_event); diff --git a/app/src/keymap.c b/app/src/keymap.c index 762dd4f4112..d5c44451b06 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -22,6 +22,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0; static zmk_keymap_layer_id_t _zmk_keymap_layer_default = 0; @@ -685,146 +686,83 @@ 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_idx(zmk_keymap_layer_id_t layer_id, 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_id; layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default); + 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[layer_idx][sensor_index]; + if (!zmk_behavior_get_binding(binding->behavior_dev)) { + LOG_DBG("No behavior assigned to sensor index %d on layer %d", sensor_index, + layer_idx); + 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_idx(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) { diff --git a/app/src/pointing/input_processor_behaviors.c b/app/src/pointing/input_processor_behaviors.c index 0c8d75cdc3e..3751fea5a12 100644 --- a/app/src/pointing/input_processor_behaviors.c +++ b/app/src/pointing/input_processor_behaviors.c @@ -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; } diff --git a/app/src/sensors.c b/app/src/sensors.c index 90ea1903940..98855d38549 100644 --- a/app/src/sensors.c +++ b/app/src/sensors.c @@ -15,6 +15,31 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include +#include +#include +#include + +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; + } +}; #if ZMK_KEYMAP_HAS_SENSORS @@ -118,6 +143,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_idx(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); diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index dcebfb0cc5c..e6c888bce3a 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -1089,14 +1089,23 @@ split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payload_wrapper p }; int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event, bool state) { + struct zmk_behavior_binding_event *event) { struct zmk_split_run_behavior_payload payload = {.data = { .param1 = binding->param1, .param2 = binding->param2, - .position = event.position, - .source = event.source, - .state = state ? 1 : 0, + .position = event->position, + .source = event->source, }}; + switch (event->type) { + case PRESS: + payload.data.state = 1; + break; + case RELEASE: + payload.data.state = 0; + break; + default: + return -EINVAL; + } const size_t payload_dev_size = sizeof(payload.behavior_dev); if (strlcpy(payload.behavior_dev, binding->behavior_dev, payload_dev_size) >= payload_dev_size) { diff --git a/app/tests/encoders/behavior_keymap.dtsi b/app/tests/encoders/behavior_keymap.dtsi new file mode 100644 index 00000000000..6ac37f017d7 --- /dev/null +++ b/app/tests/encoders/behavior_keymap.dtsi @@ -0,0 +1,44 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &tog 2 &kp X + &tog 1 &none + >; + sensor-bindings = <&inc_dec_kp A B>; + }; + skip_layer { + bindings = < + &trans &kp Y + &none &none + >; + sensor-bindings = <&inc_dec_kp N M>; + }; + alt_layer { + bindings = < + &trans &kp Z + &none &none + >; + sensor-bindings = <&inc_dec_kp C D>; + }; + }; + + mock_encoder: mock_encoder { + compatible = "zmk,sensor-encoder-mock"; + status = "okay"; + event-startup-delay = <200>; + event-period = <200>; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&mock_encoder>; + triggers-per-rotation = <20>; + }; +}; \ No newline at end of file diff --git a/app/tests/encoders/layers-1/events.patterns b/app/tests/encoders/layers-1/events.patterns new file mode 100644 index 00000000000..517ae5a28b0 --- /dev/null +++ b/app/tests/encoders/layers-1/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*layer_changed/layer_changed/p \ No newline at end of file diff --git a/app/tests/encoders/layers-1/keycode_events.snapshot b/app/tests/encoders/layers-1/keycode_events.snapshot new file mode 100644 index 00000000000..95019009b52 --- /dev/null +++ b/app/tests/encoders/layers-1/keycode_events.snapshot @@ -0,0 +1,3 @@ +layer_changed: layer 2 state 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 diff --git a/app/tests/encoders/layers-1/native_posix_64.keymap b/app/tests/encoders/layers-1/native_posix_64.keymap new file mode 100644 index 00000000000..6996f5516ff --- /dev/null +++ b/app/tests/encoders/layers-1/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,1,8000) + >; +}; + +&mock_encoder { + events = <18>; +}; diff --git a/app/tests/encoders/layers-2/events.patterns b/app/tests/encoders/layers-2/events.patterns new file mode 100644 index 00000000000..517ae5a28b0 --- /dev/null +++ b/app/tests/encoders/layers-2/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*layer_changed/layer_changed/p \ No newline at end of file diff --git a/app/tests/encoders/layers-2/keycode_events.snapshot b/app/tests/encoders/layers-2/keycode_events.snapshot new file mode 100644 index 00000000000..153dea9ce0e --- /dev/null +++ b/app/tests/encoders/layers-2/keycode_events.snapshot @@ -0,0 +1,4 @@ +layer_changed: layer 1 state 1 +layer_changed: layer 2 state 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 \ No newline at end of file diff --git a/app/tests/encoders/layers-2/native_posix_64.keymap b/app/tests/encoders/layers-2/native_posix_64.keymap new file mode 100644 index 00000000000..7b7fbdb25fe --- /dev/null +++ b/app/tests/encoders/layers-2/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,1,8000) + >; +}; + +&mock_encoder { + events = <18>; +}; diff --git a/app/tests/encoders/rotate/events.patterns b/app/tests/encoders/rotate/events.patterns new file mode 100644 index 00000000000..833100f6ac4 --- /dev/null +++ b/app/tests/encoders/rotate/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/encoders/rotate/keycode_events.snapshot b/app/tests/encoders/rotate/keycode_events.snapshot new file mode 100644 index 00000000000..b809163ddca --- /dev/null +++ b/app/tests/encoders/rotate/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/encoders/rotate/native_posix_64.keymap b/app/tests/encoders/rotate/native_posix_64.keymap new file mode 100644 index 00000000000..883352e710f --- /dev/null +++ b/app/tests/encoders/rotate/native_posix_64.keymap @@ -0,0 +1,10 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < ZMK_MOCK_PRESS(1,1,1000) + >; +}; + +&mock_encoder { + events = <18 (-18)>; +}; diff --git a/app/tests/macros/press-mid-macro/events.patterns b/app/tests/macros/press-mid-macro/events.patterns index cedbda8bc6d..dcc61e55026 100644 --- a/app/tests/macros/press-mid-macro/events.patterns +++ b/app/tests/macros/press-mid-macro/events.patterns @@ -1,2 +1,2 @@ s/.*hid_listener_keycode/kp/p -s/.*keymap_apply_position_state/pos_state/p \ No newline at end of file +s/.*raise_binding_event_at_layer_idx/binding_ev/p \ No newline at end of file diff --git a/app/tests/macros/press-mid-macro/keycode_events.snapshot b/app/tests/macros/press-mid-macro/keycode_events.snapshot index 28551b1ccd5..1ac138d54ae 100644 --- a/app/tests/macros/press-mid-macro/keycode_events.snapshot +++ b/app/tests/macros/press-mid-macro/keycode_events.snapshot @@ -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 diff --git a/app/tests/transparent/behavior_keymap.dtsi b/app/tests/transparent/behavior_keymap.dtsi index b70c84218c2..980aa52ca2b 100644 --- a/app/tests/transparent/behavior_keymap.dtsi +++ b/app/tests/transparent/behavior_keymap.dtsi @@ -3,19 +3,28 @@ #include / { + 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>; }; }; }; diff --git a/app/tests/transparent/nested/events.patterns b/app/tests/transparent/nested/events.patterns new file mode 100644 index 00000000000..3c9d3f838c6 --- /dev/null +++ b/app/tests/transparent/nested/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/transparent/nested/keycode_events.snapshot b/app/tests/transparent/nested/keycode_events.snapshot new file mode 100644 index 00000000000..d4f757e58f8 --- /dev/null +++ b/app/tests/transparent/nested/keycode_events.snapshot @@ -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 \ No newline at end of file diff --git a/app/tests/transparent/nested/native_posix_64.keymap b/app/tests/transparent/nested/native_posix_64.keymap new file mode 100644 index 00000000000..9f3f2ca3b12 --- /dev/null +++ b/app/tests/transparent/nested/native_posix_64.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#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) + >; +}; \ No newline at end of file