diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 5fb3827c..a4c884ee 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -31,6 +31,7 @@ target_sources(app PRIVATE src/sensors.c) target_sources(app PRIVATE src/event_manager.c) target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c) target_sources(app PRIVATE src/events/activity_state_changed.c) +target_sources(app PRIVATE src/events/behavior_state_changed.c) target_sources(app PRIVATE src/events/position_state_changed.c) target_sources(app PRIVATE src/events/layer_state_changed.c) target_sources(app PRIVATE src/events/keycode_state_changed.c) @@ -70,6 +71,7 @@ target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/hog.c) target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c) target_sources(app PRIVATE src/endpoints.c) target_sources(app PRIVATE src/hid_listener.c) +target_sources(app PRIVATE src/behavior.c) target_sources(app PRIVATE src/main.c) add_subdirectory(src/display/) diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h index bc135fd3..a9982465 100644 --- a/app/include/drivers/behavior.h +++ b/app/include/drivers/behavior.h @@ -11,6 +11,7 @@ #include #include #include +#include /** * @cond INTERNAL_HIDDEN @@ -20,8 +21,7 @@ * (Internal use only.) */ -typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event); +typedef int (*behavior_keymap_binding_callback_t)(const struct behavior_state_changed *ev); typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, const struct device *sensor, int64_t timestamp); @@ -44,19 +44,18 @@ __subsystem struct behavior_driver_api { * @retval 0 If successful. * @retval Negative errno code if failure. */ -__syscall int behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event); +__syscall int behavior_keymap_binding_pressed(const struct behavior_state_changed *ev); -static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - const struct device *dev = device_get_binding(binding->behavior_dev); +static inline int +z_impl_behavior_keymap_binding_pressed(const struct behavior_state_changed *event) { + const struct device *dev = device_get_binding(event->behavior_dev); const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->binding_pressed == NULL) { return -ENOTSUP; } - return api->binding_pressed(binding, event); + return api->binding_pressed(event); } /** @@ -67,19 +66,18 @@ static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_bin * @retval 0 If successful. * @retval Negative errno code if failure. */ -__syscall int behavior_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event); +__syscall int behavior_keymap_binding_released(const struct behavior_state_changed *ev); -static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - const struct device *dev = device_get_binding(binding->behavior_dev); +static inline int +z_impl_behavior_keymap_binding_released(const struct behavior_state_changed *event) { + const struct device *dev = device_get_binding(event->behavior_dev); const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->binding_released == NULL) { return -ENOTSUP; } - return api->binding_released(binding, event); + return api->binding_released(event); } /** diff --git a/app/include/zmk/behavior.h b/app/include/zmk/behavior.h index 31fb43ed..9e4fe789 100644 --- a/app/include/zmk/behavior.h +++ b/app/include/zmk/behavior.h @@ -8,6 +8,7 @@ #define ZMK_BEHAVIOR_OPAQUE 0 #define ZMK_BEHAVIOR_TRANSPARENT 1 +#define ZMK_BEHAVIOR_CAPTURED 2 struct zmk_behavior_binding { char *behavior_dev; diff --git a/app/include/zmk/events/behavior_state_changed.h b/app/include/zmk/events/behavior_state_changed.h new file mode 100644 index 00000000..99bdd99d --- /dev/null +++ b/app/include/zmk/events/behavior_state_changed.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct behavior_state_changed { + struct zmk_event_header header; + char *behavior_dev; + uint32_t param1; + uint32_t param2; + bool pressed; + int layer; + uint32_t position; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(behavior_state_changed); + +static inline struct behavior_state_changed * +create_behavior_state_changed_from_binding(struct zmk_behavior_binding *binding, bool pressed, + int layer, uint32_t position, int64_t timestamp) { + struct behavior_state_changed *ev = new_behavior_state_changed(); + ev->behavior_dev = binding->behavior_dev; + ev->param1 = binding->param1; + ev->param2 = binding->param2; + ev->pressed = pressed; + ev->layer = layer; + ev->position = position; + ev->timestamp = timestamp; + return ev; +} + +static inline struct behavior_state_changed * +create_behavior_state_changed(char *behavior_dev, uint32_t param1, uint32_t param2, bool pressed, + int layer, uint32_t position, int64_t timestamp) { + struct behavior_state_changed *ev = new_behavior_state_changed(); + ev->behavior_dev = behavior_dev; + ev->param1 = param1; + ev->param2 = param2; + ev->pressed = pressed; + ev->layer = layer; + ev->position = position; + ev->timestamp = timestamp; + return ev; +} diff --git a/app/src/behavior.c b/app/src/behavior.c new file mode 100644 index 00000000..bfe03e75 --- /dev/null +++ b/app/src/behavior.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int zmk_behavior_state_changed(const struct behavior_state_changed *ev) { + int ret; + if (ev->pressed) { + ret = behavior_keymap_binding_pressed(ev); + } else { + ret = behavior_keymap_binding_released(ev); + } + if (ret < 0) { + return ret; + } + switch (ret) { + case ZMK_BEHAVIOR_TRANSPARENT: + return ZMK_EV_EVENT_BUBBLE; + case ZMK_BEHAVIOR_OPAQUE: + return ZMK_EV_EVENT_HANDLED; + case ZMK_BEHAVIOR_CAPTURED: + return ZMK_EV_EVENT_CAPTURED; + default: + return -ENOTSUP; + } +} + +int behavior_listener(const struct zmk_event_header *eh) { + if (is_behavior_state_changed(eh)) { + const struct behavior_state_changed *ev = cast_behavior_state_changed(eh); + return zmk_behavior_state_changed(ev); + } + return 0; +} + +ZMK_LISTENER(behavior, behavior_listener); +ZMK_SUBSCRIPTION(behavior, behavior_state_changed); \ No newline at end of file diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index 3149c8ce..e8e6b813 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -12,14 +12,14 @@ #include #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - switch (binding->param1) { +static int on_keymap_binding_pressed(const struct behavior_state_changed *event) { + switch (event->param1) { case BT_CLR_CMD: return zmk_ble_clear_bonds(); case BT_NXT_CMD: @@ -27,9 +27,9 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, case BT_PRV_CMD: return zmk_ble_prof_prev(); case BT_SEL_CMD: - return zmk_ble_prof_select(binding->param2); + return zmk_ble_prof_select(event->param2); default: - LOG_ERR("Unknown BT command: %d", binding->param1); + LOG_ERR("Unknown BT command: %d", event->param1); } return -ENOTSUP; @@ -37,8 +37,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int behavior_bt_init(const struct device *dev) { return 0; }; -static int on_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { +static int on_keymap_binding_released(const struct behavior_state_changed *event) { return ZMK_BEHAVIOR_OPAQUE; } diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c index 18520f7d..b04517b0 100644 --- a/app/src/behaviors/behavior_ext_power.c +++ b/app/src/behaviors/behavior_ext_power.c @@ -16,15 +16,14 @@ #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { +static int on_keymap_binding_pressed(const struct behavior_state_changed *event) { const struct device *ext_power = device_get_binding("EXT_POWER"); if (ext_power == NULL) { - LOG_ERR("Unable to retrieve ext_power device: %d", binding->param1); + LOG_ERR("Unable to retrieve ext_power device: %d", event->param1); return -EIO; } - switch (binding->param1) { + switch (event->param1) { case EXT_POWER_OFF_CMD: return ext_power_disable(ext_power); case EXT_POWER_ON_CMD: @@ -35,14 +34,13 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, else return ext_power_enable(ext_power); default: - LOG_ERR("Unknown ext_power command: %d", binding->param1); + LOG_ERR("Unknown ext_power command: %d", event->param1); } return -ENOTSUP; } -static int on_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { +static int on_keymap_binding_released(const struct behavior_state_changed *event) { return ZMK_BEHAVIOR_OPAQUE; } diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c index 9b62eb15..7713b99d 100644 --- a/app/src/behaviors/behavior_hold_tap.c +++ b/app/src/behaviors/behavior_hold_tap.c @@ -27,9 +27,6 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #define ZMK_BHV_HOLD_TAP_MAX_HELD 10 #define ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS 40 -// increase if you have keyboard with more keys. -#define ZMK_BHV_HOLD_TAP_POSITION_NOT_USED 9999 - enum flavor { ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED = 0, ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED = 1, @@ -49,14 +46,10 @@ struct behavior_hold_tap_config { // this data is specific for each hold-tap struct active_hold_tap { - int32_t position; - // todo: move these params into the config->behaviors->tap and - uint32_t param_hold; - uint32_t param_tap; - int64_t timestamp; + const struct behavior_state_changed *event; + const struct behavior_hold_tap_config *config; bool is_decided; bool is_hold; - const struct behavior_hold_tap_config *config; struct k_delayed_work work; bool work_is_cancelled; }; @@ -157,34 +150,31 @@ static void release_captured_events() { static struct active_hold_tap *find_hold_tap(uint32_t position) { for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { - if (active_hold_taps[i].position == position) { + if (active_hold_taps[i].event != NULL && active_hold_taps[i].event->position == position) { return &active_hold_taps[i]; } } return NULL; } -static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_hold, - uint32_t param_tap, int64_t timestamp, +static struct active_hold_tap *store_hold_tap(const struct behavior_state_changed *event, const struct behavior_hold_tap_config *config) { for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { - if (active_hold_taps[i].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) { + if (active_hold_taps[i].event != NULL) { continue; } - active_hold_taps[i].position = position; + active_hold_taps[i].event = event; active_hold_taps[i].is_decided = false; active_hold_taps[i].is_hold = false; active_hold_taps[i].config = config; - active_hold_taps[i].param_hold = param_hold; - active_hold_taps[i].param_tap = param_tap; - active_hold_taps[i].timestamp = timestamp; return &active_hold_taps[i]; } return NULL; } static void clear_hold_tap(struct active_hold_tap *hold_tap) { - hold_tap->position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; + k_free((void *)hold_tap->event); + hold_tap->event = NULL; hold_tap->is_decided = false; hold_tap->is_hold = false; hold_tap->work_is_cancelled = false; @@ -279,32 +269,25 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome return; } - LOG_DBG("%d decided %s (%s event %d)", hold_tap->position, hold_tap->is_hold ? "hold" : "tap", - flavor_str(hold_tap->config->flavor), event_type); + LOG_DBG("%d decided %s (%s event %d)", hold_tap->event->position, + hold_tap->is_hold ? "hold" : "tap", flavor_str(hold_tap->config->flavor), event_type); undecided_hold_tap = NULL; - struct zmk_behavior_binding_event event = { - .position = hold_tap->position, - .timestamp = hold_tap->timestamp, - }; - - struct zmk_behavior_binding binding; if (hold_tap->is_hold) { - binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev; - binding.param1 = hold_tap->param_hold; - binding.param2 = 0; + ZMK_EVENT_RAISE(create_behavior_state_changed( + hold_tap->config->behaviors->hold.behavior_dev, hold_tap->event->param1, 0, true, + hold_tap->event->layer, hold_tap->event->position, hold_tap->event->timestamp)); } else { - binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev; - binding.param1 = hold_tap->param_tap; - binding.param2 = 0; + ZMK_EVENT_RAISE(create_behavior_state_changed( + hold_tap->config->behaviors->tap.behavior_dev, hold_tap->event->param2, 0, true, + hold_tap->event->layer, hold_tap->event->position, hold_tap->event->timestamp)); } - behavior_keymap_binding_pressed(&binding, event); + release_captured_events(); } -static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - const struct device *dev = device_get_binding(binding->behavior_dev); +static int on_hold_tap_binding_pressed(const struct behavior_state_changed *event) { + const struct device *dev = device_get_binding(event->behavior_dev); const struct behavior_hold_tap_config *cfg = dev->config; if (undecided_hold_tap != NULL) { @@ -313,72 +296,67 @@ static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding, return ZMK_BEHAVIOR_OPAQUE; } - struct active_hold_tap *hold_tap = - store_hold_tap(event.position, binding->param1, binding->param2, event.timestamp, cfg); + struct active_hold_tap *hold_tap = store_hold_tap(event, cfg); if (hold_tap == NULL) { LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?", ZMK_BHV_HOLD_TAP_MAX_HELD); return ZMK_BEHAVIOR_OPAQUE; } - LOG_DBG("%d new undecided hold_tap", event.position); + LOG_DBG("%d new undecided hold_tap", event->position); undecided_hold_tap = hold_tap; // if this behavior was queued we have to adjust the timer to only // wait for the remaining time. - int32_t tapping_term_ms_left = (hold_tap->timestamp + cfg->tapping_term_ms) - k_uptime_get(); + int32_t tapping_term_ms_left = + (hold_tap->event->timestamp + cfg->tapping_term_ms) - k_uptime_get(); if (tapping_term_ms_left > 0) { k_delayed_work_submit(&hold_tap->work, K_MSEC(tapping_term_ms_left)); } - return ZMK_BEHAVIOR_OPAQUE; + return ZMK_BEHAVIOR_CAPTURED; } -static int on_hold_tap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - struct active_hold_tap *hold_tap = find_hold_tap(event.position); +static int on_hold_tap_binding_released(const struct behavior_state_changed *event) { + struct active_hold_tap *hold_tap = find_hold_tap(event->position); if (hold_tap == NULL) { - LOG_ERR("ACTIVE_HOLD_TAP_CLEANED_UP_TOO_EARLY"); + LOG_ERR("ACTIVE HOLD TAP CLEANED UP TOO EARLY"); return ZMK_BEHAVIOR_OPAQUE; } // If these events were queued, the timer event may be queued too late or not at all. // We insert a timer event before the TH_KEY_UP event to verify. int work_cancel_result = k_delayed_work_cancel(&hold_tap->work); - if (event.timestamp > (hold_tap->timestamp + hold_tap->config->tapping_term_ms)) { + if (event->timestamp > (hold_tap->event->timestamp + hold_tap->config->tapping_term_ms)) { decide_hold_tap(hold_tap, HT_TIMER_EVENT); } decide_hold_tap(hold_tap, HT_KEY_UP); - // todo: set up the binding and data items inside of the active_hold_tap struct - struct zmk_behavior_binding_event sub_behavior_data = { - .position = hold_tap->position, - .timestamp = hold_tap->timestamp, - }; - - struct zmk_behavior_binding sub_behavior_binding; + int ret; if (hold_tap->is_hold) { - sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev; - sub_behavior_binding.param1 = hold_tap->param_hold; - sub_behavior_binding.param2 = 0; + ret = ZMK_EVENT_RAISE(create_behavior_state_changed( + hold_tap->config->behaviors->hold.behavior_dev, hold_tap->event->param1, 0, false, + hold_tap->event->layer, hold_tap->event->position, hold_tap->event->timestamp)); } else { - sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev; - sub_behavior_binding.param1 = hold_tap->param_tap; - sub_behavior_binding.param2 = 0; + ret = ZMK_EVENT_RAISE(create_behavior_state_changed( + hold_tap->config->behaviors->tap.behavior_dev, hold_tap->event->param2, 0, false, + hold_tap->event->layer, hold_tap->event->position, hold_tap->event->timestamp)); } - behavior_keymap_binding_released(&sub_behavior_binding, sub_behavior_data); if (work_cancel_result == -EINPROGRESS) { // let the timer handler clean up // if we'd clear now, the timer may call back for an uninitialized active_hold_tap. - LOG_DBG("%d hold-tap timer work in event queue", event.position); + LOG_DBG("%d hold-tap timer work in event queue", event->position); hold_tap->work_is_cancelled = true; } else { - LOG_DBG("%d cleaning up hold-tap", event.position); + LOG_DBG("%d cleaning up hold-tap", event->position); clear_hold_tap(hold_tap); } + if (ret < 0) { + return ret; + } return ZMK_BEHAVIOR_OPAQUE; } @@ -395,12 +373,13 @@ static int position_state_changed_listener(const struct zmk_event_header *eh) { return ZMK_EV_EVENT_BUBBLE; } - if (undecided_hold_tap->position == ev->position) { + if (undecided_hold_tap->event->position == ev->position) { if (ev->state) { // keydown LOG_ERR("hold-tap listener should be called before before most other listeners!"); return ZMK_EV_EVENT_BUBBLE; } else { // keyup - LOG_DBG("%d bubble undecided hold-tap keyrelease event", undecided_hold_tap->position); + LOG_DBG("%d bubble undecided hold-tap keyrelease event", + undecided_hold_tap->event->position); return ZMK_EV_EVENT_BUBBLE; } } @@ -409,19 +388,19 @@ static int position_state_changed_listener(const struct zmk_event_header *eh) { // We make a timer decision before the other key events are handled if the timer would // have run out. if (ev->timestamp > - (undecided_hold_tap->timestamp + undecided_hold_tap->config->tapping_term_ms)) { + (undecided_hold_tap->event->timestamp + undecided_hold_tap->config->tapping_term_ms)) { decide_hold_tap(undecided_hold_tap, HT_TIMER_EVENT); } if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { // no keydown event has been captured, let it bubble. // we'll catch modifiers later in modifier_state_changed_listener - LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->position, ev->position, + LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->event->position, ev->position, ev->state ? "down" : "up"); return ZMK_EV_EVENT_BUBBLE; } - LOG_DBG("%d capturing %d %s event", undecided_hold_tap->position, ev->position, + LOG_DBG("%d capturing %d %s event", undecided_hold_tap->event->position, ev->position, ev->state ? "down" : "up"); capture_event(eh); decide_hold_tap(undecided_hold_tap, ev->state ? HT_OTHER_KEY_DOWN : HT_OTHER_KEY_UP); @@ -449,7 +428,7 @@ static int keycode_state_changed_listener(const struct zmk_event_header *eh) { // only key-up events will bubble through position_state_changed_listener // if a undecided_hold_tap is active. - LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->position, ev->keycode, + LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->event->position, ev->keycode, ev->state ? "down" : "up"); capture_event(eh); return ZMK_EV_EVENT_CAPTURED; @@ -485,7 +464,6 @@ static int behavior_hold_tap_init(const struct device *dev) { if (init_first_run) { for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { k_delayed_work_init(&active_hold_taps[i].work, behavior_hold_tap_timer_work_handler); - active_hold_taps[i].position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; } } init_first_run = false; diff --git a/app/src/behaviors/behavior_key_press.c b/app/src/behaviors/behavior_key_press.c index df0828ac..29707da0 100644 --- a/app/src/behaviors/behavior_key_press.c +++ b/app/src/behaviors/behavior_key_press.c @@ -18,18 +18,16 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int behavior_key_press_init(const struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); +static int on_keymap_binding_pressed(const struct behavior_state_changed *event) { + LOG_DBG("position %d keycode 0x%02X", event->position, event->param1); return ZMK_EVENT_RAISE( - keycode_state_changed_from_encoded(binding->param1, true, event.timestamp)); + keycode_state_changed_from_encoded(event->param1, true, event->timestamp)); } -static int on_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); +static int on_keymap_binding_released(const struct behavior_state_changed *event) { + LOG_DBG("position %d keycode 0x%02X", event->position, event->param1); return ZMK_EVENT_RAISE( - keycode_state_changed_from_encoded(binding->param1, false, event.timestamp)); + keycode_state_changed_from_encoded(event->param1, false, event->timestamp)); } static const struct behavior_driver_api behavior_key_press_driver_api = { diff --git a/app/src/behaviors/behavior_momentary_layer.c b/app/src/behaviors/behavior_momentary_layer.c index 2b0206d0..fc5d8290 100644 --- a/app/src/behaviors/behavior_momentary_layer.c +++ b/app/src/behaviors/behavior_momentary_layer.c @@ -20,16 +20,14 @@ struct behavior_mo_data {}; static int behavior_mo_init(const struct device *dev) { return 0; }; -static int mo_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d layer %d", event.position, binding->param1); - return zmk_keymap_layer_activate(binding->param1); +static int mo_keymap_binding_pressed(const struct behavior_state_changed *event) { + LOG_DBG("position %d layer %d", event->position, event->param1); + return zmk_keymap_layer_activate(event->param1); } -static int mo_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d layer %d", event.position, binding->param1); - return zmk_keymap_layer_deactivate(binding->param1); +static int mo_keymap_binding_released(const struct behavior_state_changed *event) { + LOG_DBG("position %d layer %d", event->position, event->param1); + return zmk_keymap_layer_deactivate(event->param1); } static const struct behavior_driver_api behavior_mo_driver_api = { diff --git a/app/src/behaviors/behavior_none.c b/app/src/behaviors/behavior_none.c index e0eaa159..0da227b6 100644 --- a/app/src/behaviors/behavior_none.c +++ b/app/src/behaviors/behavior_none.c @@ -20,13 +20,11 @@ struct behavior_none_data {}; static int behavior_none_init(const struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { +static int on_keymap_binding_pressed(const struct behavior_state_changed *event) { return ZMK_BEHAVIOR_OPAQUE; } -static int on_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { +static int on_keymap_binding_released(const struct behavior_state_changed *event) { return ZMK_BEHAVIOR_OPAQUE; } diff --git a/app/src/behaviors/behavior_outputs.c b/app/src/behaviors/behavior_outputs.c index 3a45b7fd..1c5cdf97 100644 --- a/app/src/behaviors/behavior_outputs.c +++ b/app/src/behaviors/behavior_outputs.c @@ -18,9 +18,8 @@ #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - switch (binding->param1) { +static int on_keymap_binding_pressed(const struct behavior_state_changed *event) { + switch (event->param1) { case OUT_TOG: return zmk_endpoints_toggle(); case OUT_USB: @@ -28,7 +27,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, case OUT_BLE: return zmk_endpoints_select(ZMK_ENDPOINT_BLE); default: - LOG_ERR("Unknown output command: %d", binding->param1); + LOG_ERR("Unknown output command: %d", event->param1); } return -ENOTSUP; diff --git a/app/src/behaviors/behavior_reset.c b/app/src/behaviors/behavior_reset.c index e4b720f7..f8d5bd21 100644 --- a/app/src/behaviors/behavior_reset.c +++ b/app/src/behaviors/behavior_reset.c @@ -21,9 +21,8 @@ struct behavior_reset_config { static int behavior_reset_init(const struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - const struct device *dev = device_get_binding(binding->behavior_dev); +static int on_keymap_binding_pressed(const struct behavior_state_changed *event) { + const struct device *dev = device_get_binding(event->behavior_dev); const struct behavior_reset_config *cfg = dev->config; // TODO: Correct magic code for going into DFU? diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c index 399123a3..74b549b5 100644 --- a/app/src/behaviors/behavior_rgb_underglow.c +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -18,9 +18,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int behavior_rgb_underglow_init(const struct device *dev) { return 0; } -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - switch (binding->param1) { +static int on_keymap_binding_pressed(const struct behavior_state_changed *event) { + switch (event->param1) { case RGB_TOG: return zmk_rgb_underglow_toggle(); case RGB_HUI: @@ -48,8 +47,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, return -ENOTSUP; } -static int on_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { +static int on_keymap_binding_released(const struct behavior_state_changed *event) { return ZMK_BEHAVIOR_OPAQUE; } diff --git a/app/src/behaviors/behavior_sticky_key.c b/app/src/behaviors/behavior_sticky_key.c index 15c9e21c..67c03179 100644 --- a/app/src/behaviors/behavior_sticky_key.c +++ b/app/src/behaviors/behavior_sticky_key.c @@ -18,6 +18,7 @@ #include #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -33,9 +34,7 @@ struct behavior_sticky_key_config { }; struct active_sticky_key { - uint32_t position; - uint32_t param1; - uint32_t param2; + const struct behavior_state_changed *event; const struct behavior_sticky_key_config *config; // timer data. bool timer_started; @@ -49,22 +48,18 @@ struct active_sticky_key { struct active_sticky_key active_sticky_keys[ZMK_BHV_STICKY_KEY_MAX_HELD] = {}; -static struct active_sticky_key *store_sticky_key(uint32_t position, uint32_t param1, - uint32_t param2, +static struct active_sticky_key *store_sticky_key(const struct behavior_state_changed *event, const struct behavior_sticky_key_config *config) { for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { struct active_sticky_key *const sticky_key = &active_sticky_keys[i]; - if (sticky_key->position != ZMK_BHV_STICKY_KEY_POSITION_FREE || - sticky_key->timer_cancelled) { + if (sticky_key->event != NULL || sticky_key->timer_cancelled) { continue; } - sticky_key->position = position; - sticky_key->param1 = param1; - sticky_key->param2 = param2; + sticky_key->event = event; sticky_key->config = config; - sticky_key->release_at = 0; sticky_key->timer_cancelled = false; sticky_key->timer_started = false; + sticky_key->release_at = 0; sticky_key->modified_key_usage_page = 0; sticky_key->modified_key_keycode = 0; return sticky_key; @@ -72,13 +67,11 @@ static struct active_sticky_key *store_sticky_key(uint32_t position, uint32_t pa return NULL; } -static void clear_sticky_key(struct active_sticky_key *sticky_key) { - sticky_key->position = ZMK_BHV_STICKY_KEY_POSITION_FREE; -} - static struct active_sticky_key *find_sticky_key(uint32_t position) { for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { - if (active_sticky_keys[i].position == position && !active_sticky_keys[i].timer_cancelled) { + if (active_sticky_keys[i].event != NULL && + active_sticky_keys[i].event->position == position && + !active_sticky_keys[i].timer_cancelled) { return &active_sticky_keys[i]; } } @@ -87,32 +80,20 @@ static struct active_sticky_key *find_sticky_key(uint32_t position) { static inline int press_sticky_key_behavior(struct active_sticky_key *sticky_key, int64_t timestamp) { - struct zmk_behavior_binding binding = { - .behavior_dev = sticky_key->config->behavior.behavior_dev, - .param1 = sticky_key->param1, - .param2 = sticky_key->param2, - }; - struct zmk_behavior_binding_event event = { - .position = sticky_key->position, - .timestamp = timestamp, - }; - return behavior_keymap_binding_pressed(&binding, event); + return ZMK_EVENT_RAISE(create_behavior_state_changed( + sticky_key->config->behavior.behavior_dev, sticky_key->event->param1, + sticky_key->event->param2, true, sticky_key->event->layer, sticky_key->event->position, + timestamp)); } static inline int release_sticky_key_behavior(struct active_sticky_key *sticky_key, int64_t timestamp) { - struct zmk_behavior_binding binding = { - .behavior_dev = sticky_key->config->behavior.behavior_dev, - .param1 = sticky_key->param1, - .param2 = sticky_key->param2, - }; - struct zmk_behavior_binding_event event = { - .position = sticky_key->position, - .timestamp = timestamp, - }; - - clear_sticky_key(sticky_key); - return behavior_keymap_binding_released(&binding, event); + const struct behavior_state_changed *event = sticky_key->event; + sticky_key->event = NULL; + return ZMK_EVENT_RAISE(create_behavior_state_changed(sticky_key->config->behavior.behavior_dev, + event->param1, event->param2, false, + event->layer, event->position, timestamp)); + k_free((void *)event); } static int stop_timer(struct active_sticky_key *sticky_key) { @@ -124,31 +105,29 @@ static int stop_timer(struct active_sticky_key *sticky_key) { return timer_cancel_result; } -static int on_sticky_key_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - const struct device *dev = device_get_binding(binding->behavior_dev); +static int on_sticky_key_binding_pressed(const struct behavior_state_changed *event) { + const struct device *dev = device_get_binding(event->behavior_dev); const struct behavior_sticky_key_config *cfg = dev->config; struct active_sticky_key *sticky_key; - sticky_key = find_sticky_key(event.position); + sticky_key = find_sticky_key(event->position); if (sticky_key != NULL) { stop_timer(sticky_key); - release_sticky_key_behavior(sticky_key, event.timestamp); + release_sticky_key_behavior(sticky_key, event->timestamp); } - sticky_key = store_sticky_key(event.position, binding->param1, binding->param2, cfg); + sticky_key = store_sticky_key(event, cfg); if (sticky_key == NULL) { LOG_ERR("unable to store sticky key, did you press more than %d sticky_key?", ZMK_BHV_STICKY_KEY_MAX_HELD); return ZMK_BEHAVIOR_OPAQUE; } - press_sticky_key_behavior(sticky_key, event.timestamp); - LOG_DBG("%d new sticky_key", event.position); - return ZMK_BEHAVIOR_OPAQUE; + press_sticky_key_behavior(sticky_key, event->timestamp); + LOG_DBG("%d new sticky_key", event->position); + return ZMK_BEHAVIOR_CAPTURED; } -static int on_sticky_key_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - struct active_sticky_key *sticky_key = find_sticky_key(event.position); +static int on_sticky_key_binding_released(const struct behavior_state_changed *event) { + struct active_sticky_key *sticky_key = find_sticky_key(event->position); if (sticky_key == NULL) { LOG_ERR("ACTIVE STICKY KEY CLEARED TOO EARLY"); return ZMK_BEHAVIOR_OPAQUE; @@ -156,12 +135,12 @@ static int on_sticky_key_binding_released(struct zmk_behavior_binding *binding, if (sticky_key->modified_key_usage_page != 0 && sticky_key->modified_key_keycode != 0) { LOG_DBG("Another key was pressed while the sticky key was pressed. Act like a normal key."); - return release_sticky_key_behavior(sticky_key, event.timestamp); + return release_sticky_key_behavior(sticky_key, event->timestamp); } // No other key was pressed. Start the timer. sticky_key->timer_started = true; - sticky_key->release_at = event.timestamp + sticky_key->config->release_after_ms; + sticky_key->release_at = event->timestamp + sticky_key->config->release_after_ms; // adjust timer in case this behavior was queued by a hold-tap int32_t ms_left = sticky_key->release_at - k_uptime_get(); if (ms_left > 0) { @@ -182,14 +161,14 @@ static int sticky_key_keycode_state_changed_listener(const struct zmk_event_head struct keycode_state_changed *ev = cast_keycode_state_changed(eh); for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { struct active_sticky_key *sticky_key = &active_sticky_keys[i]; - if (sticky_key->position == ZMK_BHV_STICKY_KEY_POSITION_FREE) { + if (sticky_key->event == NULL) { continue; } if (strcmp(sticky_key->config->behavior.behavior_dev, "KEY_PRESS") == 0 && - HID_USAGE_ID(sticky_key->param1) == ev->keycode && - (HID_USAGE_PAGE(sticky_key->param1) & 0xFF) == ev->usage_page && - SELECT_MODS(sticky_key->param1) == ev->implicit_modifiers) { + HID_USAGE_ID(sticky_key->event->param1) == ev->keycode && + (HID_USAGE_PAGE(sticky_key->event->param1) & 0xFF) == ev->usage_page && + SELECT_MODS(sticky_key->event->param1) == ev->implicit_modifiers) { // don't catch key down events generated by the sticky key behavior itself continue; } @@ -231,7 +210,7 @@ ZMK_SUBSCRIPTION(behavior_sticky_key, keycode_state_changed); void behavior_sticky_key_timer_handler(struct k_work *item) { struct active_sticky_key *sticky_key = CONTAINER_OF(item, struct active_sticky_key, release_timer); - if (sticky_key->position == ZMK_BHV_STICKY_KEY_POSITION_FREE) { + if (sticky_key->event == NULL) { return; } if (sticky_key->timer_cancelled) { @@ -247,7 +226,7 @@ static int behavior_sticky_key_init(const struct device *dev) { for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { k_delayed_work_init(&active_sticky_keys[i].release_timer, behavior_sticky_key_timer_handler); - active_sticky_keys[i].position = ZMK_BHV_STICKY_KEY_POSITION_FREE; + active_sticky_keys[i].event = NULL; } } init_first_run = false; diff --git a/app/src/behaviors/behavior_to_layer.c b/app/src/behaviors/behavior_to_layer.c index bb64026d..1913df97 100644 --- a/app/src/behaviors/behavior_to_layer.c +++ b/app/src/behaviors/behavior_to_layer.c @@ -17,16 +17,14 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int behavior_to_init(const struct device *dev) { return 0; }; -static int to_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d layer %d", event.position, binding->param1); - zmk_keymap_layer_to(binding->param1); +static int to_keymap_binding_pressed(const struct behavior_state_changed *event) { + LOG_DBG("position %d layer %d", event->position, event->param1); + zmk_keymap_layer_to(event->param1); return ZMK_BEHAVIOR_OPAQUE; } -static int to_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d layer %d", event.position, binding->param1); +static int to_keymap_binding_released(const struct behavior_state_changed *event) { + LOG_DBG("position %d layer %d", event->position, event->param1); return ZMK_BEHAVIOR_OPAQUE; } diff --git a/app/src/behaviors/behavior_toggle_layer.c b/app/src/behaviors/behavior_toggle_layer.c index 21daa004..bc480eb7 100644 --- a/app/src/behaviors/behavior_toggle_layer.c +++ b/app/src/behaviors/behavior_toggle_layer.c @@ -20,15 +20,13 @@ struct behavior_tog_data {}; static int behavior_tog_init(const struct device *dev) { return 0; }; -static int tog_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d layer %d", event.position, binding->param1); - return zmk_keymap_layer_toggle(binding->param1); +static int tog_keymap_binding_pressed(const struct behavior_state_changed *event) { + LOG_DBG("position %d layer %d", event->position, event->param1); + return zmk_keymap_layer_toggle(event->param1); } -static int tog_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d layer %d", event.position, binding->param1); +static int tog_keymap_binding_released(const struct behavior_state_changed *event) { + LOG_DBG("position %d layer %d", event->position, event->param1); return ZMK_BEHAVIOR_OPAQUE; } diff --git a/app/src/behaviors/behavior_transparent.c b/app/src/behaviors/behavior_transparent.c index ca3d279f..acc9b9e1 100644 --- a/app/src/behaviors/behavior_transparent.c +++ b/app/src/behaviors/behavior_transparent.c @@ -20,13 +20,11 @@ struct behavior_transparent_data {}; static int behavior_transparent_init(const struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { +static int on_keymap_binding_pressed(const struct behavior_state_changed *event) { return ZMK_BEHAVIOR_TRANSPARENT; } -static int on_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { +static int on_keymap_binding_released(const struct behavior_state_changed *event) { return ZMK_BEHAVIOR_TRANSPARENT; } diff --git a/app/src/event_manager.c b/app/src/event_manager.c index 872f5c86..dfaa2cd8 100644 --- a/app/src/event_manager.c +++ b/app/src/event_manager.c @@ -17,6 +17,12 @@ extern struct zmk_event_type *__event_type_end[]; extern struct zmk_event_subscription __event_subscriptions_start[]; extern struct zmk_event_subscription __event_subscriptions_end[]; +/* + * Returns negative values for errors. + * Returns ZMK_EV_EVENT_HANDLED if the event was handled + * Returns ZMK_EV_EVENT_CAPTURED if the event was captured + * Returns ZMK_EV_EVENT_BUBBLE if no handler handled the event + */ int zmk_event_manager_handle_from(struct zmk_event_header *event, uint8_t start_index) { int ret = 0; uint8_t len = __event_subscriptions_end - __event_subscriptions_start; @@ -31,13 +37,12 @@ int zmk_event_manager_handle_from(struct zmk_event_header *event, uint8_t start_ switch (ret) { case ZMK_EV_EVENT_HANDLED: LOG_DBG("Listener handled the event"); - ret = 0; goto release; case ZMK_EV_EVENT_CAPTURED: LOG_DBG("Listener captured the event"); event->last_listener_index = i; // Listeners are expected to free events they capture - return 0; + return ret; } } } diff --git a/app/src/events/behavior_state_changed.c b/app/src/events/behavior_state_changed.c new file mode 100644 index 00000000..c0802ecb --- /dev/null +++ b/app/src/events/behavior_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(behavior_state_changed); \ No newline at end of file diff --git a/app/src/keymap.c b/app/src/keymap.c index 786a1773..714f1079 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -16,6 +16,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +#include #include #include @@ -146,11 +147,6 @@ int zmk_keymap_layer_to(uint8_t layer) { int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, int64_t timestamp) { struct zmk_behavior_binding *binding = &zmk_keymap[layer][position]; const struct device *behavior; - struct zmk_behavior_binding_event event = { - .layer = layer, - .position = position, - .timestamp = timestamp, - }; LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, log_strdup(binding->behavior_dev)); @@ -159,14 +155,11 @@ int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, if (!behavior) { LOG_DBG("No behavior assigned to %d on layer %d", position, layer); - return 1; + return ZMK_EV_EVENT_HANDLED; } - if (pressed) { - return behavior_keymap_binding_pressed(binding, event); - } else { - return behavior_keymap_binding_released(binding, event); - } + return ZMK_EVENT_RAISE( + create_behavior_state_changed_from_binding(binding, pressed, layer, position, timestamp)); } int zmk_keymap_position_state_changed(uint32_t position, bool pressed, int64_t timestamp) { @@ -176,7 +169,7 @@ int zmk_keymap_position_state_changed(uint32_t position, bool pressed, int64_t t for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { if (zmk_keymap_layer_active_with_state(layer, zmk_keymap_active_behavior_layer[position])) { int ret = zmk_keymap_apply_position_state(layer, position, pressed, timestamp); - if (ret > 0) { + if (ret == ZMK_EV_EVENT_BUBBLE) { LOG_DBG("behavior processing to continue to next layer"); continue; } else if (ret < 0) {