This commit is contained in:
Okke Formsma 2021-01-03 19:38:55 +00:00 committed by GitHub
commit 668cb25bdf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 271 additions and 219 deletions

View file

@ -31,6 +31,7 @@ target_sources(app PRIVATE src/sensors.c)
target_sources(app PRIVATE src/event_manager.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_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/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/position_state_changed.c)
target_sources(app PRIVATE src/events/layer_state_changed.c) target_sources(app PRIVATE src/events/layer_state_changed.c)
target_sources(app PRIVATE src/events/keycode_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_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c)
target_sources(app PRIVATE src/endpoints.c) target_sources(app PRIVATE src/endpoints.c)
target_sources(app PRIVATE src/hid_listener.c) target_sources(app PRIVATE src/hid_listener.c)
target_sources(app PRIVATE src/behavior.c)
target_sources(app PRIVATE src/main.c) target_sources(app PRIVATE src/main.c)
add_subdirectory(src/display/) add_subdirectory(src/display/)

View file

@ -11,6 +11,7 @@
#include <device.h> #include <device.h>
#include <zmk/keys.h> #include <zmk/keys.h>
#include <zmk/behavior.h> #include <zmk/behavior.h>
#include <zmk/events/behavior_state_changed.h>
/** /**
* @cond INTERNAL_HIDDEN * @cond INTERNAL_HIDDEN
@ -20,8 +21,7 @@
* (Internal use only.) * (Internal use only.)
*/ */
typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, typedef int (*behavior_keymap_binding_callback_t)(const struct behavior_state_changed *ev);
struct zmk_behavior_binding_event event);
typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding,
const struct device *sensor, const struct device *sensor,
int64_t timestamp); int64_t timestamp);
@ -44,19 +44,18 @@ __subsystem struct behavior_driver_api {
* @retval 0 If successful. * @retval 0 If successful.
* @retval Negative errno code if failure. * @retval Negative errno code if failure.
*/ */
__syscall int behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, __syscall int behavior_keymap_binding_pressed(const struct behavior_state_changed *ev);
struct zmk_behavior_binding_event event);
static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, static inline int
struct zmk_behavior_binding_event event) { z_impl_behavior_keymap_binding_pressed(const struct behavior_state_changed *event) {
const struct device *dev = device_get_binding(binding->behavior_dev); const struct device *dev = device_get_binding(event->behavior_dev);
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
if (api->binding_pressed == NULL) { if (api->binding_pressed == NULL) {
return -ENOTSUP; 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 0 If successful.
* @retval Negative errno code if failure. * @retval Negative errno code if failure.
*/ */
__syscall int behavior_keymap_binding_released(struct zmk_behavior_binding *binding, __syscall int behavior_keymap_binding_released(const struct behavior_state_changed *ev);
struct zmk_behavior_binding_event event);
static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_binding *binding, static inline int
struct zmk_behavior_binding_event event) { z_impl_behavior_keymap_binding_released(const struct behavior_state_changed *event) {
const struct device *dev = device_get_binding(binding->behavior_dev); const struct device *dev = device_get_binding(event->behavior_dev);
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
if (api->binding_released == NULL) { if (api->binding_released == NULL) {
return -ENOTSUP; return -ENOTSUP;
} }
return api->binding_released(binding, event); return api->binding_released(event);
} }
/** /**

View file

@ -8,6 +8,7 @@
#define ZMK_BEHAVIOR_OPAQUE 0 #define ZMK_BEHAVIOR_OPAQUE 0
#define ZMK_BEHAVIOR_TRANSPARENT 1 #define ZMK_BEHAVIOR_TRANSPARENT 1
#define ZMK_BEHAVIOR_CAPTURED 2
struct zmk_behavior_binding { struct zmk_behavior_binding {
char *behavior_dev; char *behavior_dev;

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <zephyr.h>
#include <zmk/event_manager.h>
#include <zmk/behavior.h>
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;
}

53
app/src/behavior.c Normal file
View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <sys/util.h>
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/matrix.h>
#include <zmk/sensors.h>
#include <zmk/keymap.h>
#include <drivers/behavior.h>
#include <zmk/behavior.h>
#include <zmk/event_manager.h>
#include <zmk/events/position_state_changed.h>
#include <zmk/events/behavior_state_changed.h>
#include <zmk/events/sensor_event.h>
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);

View file

@ -12,14 +12,14 @@
#include <bluetooth/conn.h> #include <bluetooth/conn.h>
#include <logging/log.h> #include <logging/log.h>
#include <zmk/behavior.h> #include <zmk/behavior.h>
#include <zmk/events/behavior_state_changed.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/ble.h> #include <zmk/ble.h>
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int on_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { switch (event->param1) {
switch (binding->param1) {
case BT_CLR_CMD: case BT_CLR_CMD:
return zmk_ble_clear_bonds(); return zmk_ble_clear_bonds();
case BT_NXT_CMD: case BT_NXT_CMD:
@ -27,9 +27,9 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
case BT_PRV_CMD: case BT_PRV_CMD:
return zmk_ble_prof_prev(); return zmk_ble_prof_prev();
case BT_SEL_CMD: case BT_SEL_CMD:
return zmk_ble_prof_select(binding->param2); return zmk_ble_prof_select(event->param2);
default: default:
LOG_ERR("Unknown BT command: %d", binding->param1); LOG_ERR("Unknown BT command: %d", event->param1);
} }
return -ENOTSUP; 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 behavior_bt_init(const struct device *dev) { return 0; };
static int on_keymap_binding_released(struct zmk_behavior_binding *binding, static int on_keymap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) {
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }

View file

@ -16,15 +16,14 @@
#include <logging/log.h> #include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int on_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) {
const struct device *ext_power = device_get_binding("EXT_POWER"); const struct device *ext_power = device_get_binding("EXT_POWER");
if (ext_power == NULL) { 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; return -EIO;
} }
switch (binding->param1) { switch (event->param1) {
case EXT_POWER_OFF_CMD: case EXT_POWER_OFF_CMD:
return ext_power_disable(ext_power); return ext_power_disable(ext_power);
case EXT_POWER_ON_CMD: case EXT_POWER_ON_CMD:
@ -35,14 +34,13 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
else else
return ext_power_enable(ext_power); return ext_power_enable(ext_power);
default: default:
LOG_ERR("Unknown ext_power command: %d", binding->param1); LOG_ERR("Unknown ext_power command: %d", event->param1);
} }
return -ENOTSUP; return -ENOTSUP;
} }
static int on_keymap_binding_released(struct zmk_behavior_binding *binding, static int on_keymap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) {
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }

View file

@ -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_HELD 10
#define ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS 40 #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 { enum flavor {
ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED = 0, ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED = 0,
ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED = 1, ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED = 1,
@ -49,14 +46,10 @@ struct behavior_hold_tap_config {
// this data is specific for each hold-tap // this data is specific for each hold-tap
struct active_hold_tap { struct active_hold_tap {
int32_t position; const struct behavior_state_changed *event;
// todo: move these params into the config->behaviors->tap and const struct behavior_hold_tap_config *config;
uint32_t param_hold;
uint32_t param_tap;
int64_t timestamp;
bool is_decided; bool is_decided;
bool is_hold; bool is_hold;
const struct behavior_hold_tap_config *config;
struct k_delayed_work work; struct k_delayed_work work;
bool work_is_cancelled; bool work_is_cancelled;
}; };
@ -157,34 +150,31 @@ static void release_captured_events() {
static struct active_hold_tap *find_hold_tap(uint32_t position) { static struct active_hold_tap *find_hold_tap(uint32_t position) {
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { 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 &active_hold_taps[i];
} }
} }
return NULL; return NULL;
} }
static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_hold, static struct active_hold_tap *store_hold_tap(const struct behavior_state_changed *event,
uint32_t param_tap, int64_t timestamp,
const struct behavior_hold_tap_config *config) { const struct behavior_hold_tap_config *config) {
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { 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; 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_decided = false;
active_hold_taps[i].is_hold = false; active_hold_taps[i].is_hold = false;
active_hold_taps[i].config = config; 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 &active_hold_taps[i];
} }
return NULL; return NULL;
} }
static void clear_hold_tap(struct active_hold_tap *hold_tap) { 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_decided = false;
hold_tap->is_hold = false; hold_tap->is_hold = false;
hold_tap->work_is_cancelled = 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; return;
} }
LOG_DBG("%d decided %s (%s event %d)", hold_tap->position, hold_tap->is_hold ? "hold" : "tap", LOG_DBG("%d decided %s (%s event %d)", hold_tap->event->position,
flavor_str(hold_tap->config->flavor), event_type); hold_tap->is_hold ? "hold" : "tap", flavor_str(hold_tap->config->flavor), event_type);
undecided_hold_tap = NULL; 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) { if (hold_tap->is_hold) {
binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev; ZMK_EVENT_RAISE(create_behavior_state_changed(
binding.param1 = hold_tap->param_hold; hold_tap->config->behaviors->hold.behavior_dev, hold_tap->event->param1, 0, true,
binding.param2 = 0; hold_tap->event->layer, hold_tap->event->position, hold_tap->event->timestamp));
} else { } else {
binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev; ZMK_EVENT_RAISE(create_behavior_state_changed(
binding.param1 = hold_tap->param_tap; hold_tap->config->behaviors->tap.behavior_dev, hold_tap->event->param2, 0, true,
binding.param2 = 0; hold_tap->event->layer, hold_tap->event->position, hold_tap->event->timestamp));
} }
behavior_keymap_binding_pressed(&binding, event);
release_captured_events(); release_captured_events();
} }
static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding, static int on_hold_tap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { const struct device *dev = device_get_binding(event->behavior_dev);
const struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_hold_tap_config *cfg = dev->config; const struct behavior_hold_tap_config *cfg = dev->config;
if (undecided_hold_tap != NULL) { 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; return ZMK_BEHAVIOR_OPAQUE;
} }
struct active_hold_tap *hold_tap = struct active_hold_tap *hold_tap = store_hold_tap(event, cfg);
store_hold_tap(event.position, binding->param1, binding->param2, event.timestamp, cfg);
if (hold_tap == NULL) { if (hold_tap == NULL) {
LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?", LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?",
ZMK_BHV_HOLD_TAP_MAX_HELD); ZMK_BHV_HOLD_TAP_MAX_HELD);
return ZMK_BEHAVIOR_OPAQUE; 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; undecided_hold_tap = hold_tap;
// if this behavior was queued we have to adjust the timer to only // if this behavior was queued we have to adjust the timer to only
// wait for the remaining time. // 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) { if (tapping_term_ms_left > 0) {
k_delayed_work_submit(&hold_tap->work, K_MSEC(tapping_term_ms_left)); 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, static int on_hold_tap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { struct active_hold_tap *hold_tap = find_hold_tap(event->position);
struct active_hold_tap *hold_tap = find_hold_tap(event.position);
if (hold_tap == NULL) { 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; return ZMK_BEHAVIOR_OPAQUE;
} }
// If these events were queued, the timer event may be queued too late or not at all. // 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. // We insert a timer event before the TH_KEY_UP event to verify.
int work_cancel_result = k_delayed_work_cancel(&hold_tap->work); 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_TIMER_EVENT);
} }
decide_hold_tap(hold_tap, HT_KEY_UP); decide_hold_tap(hold_tap, HT_KEY_UP);
// todo: set up the binding and data items inside of the active_hold_tap struct int ret;
struct zmk_behavior_binding_event sub_behavior_data = {
.position = hold_tap->position,
.timestamp = hold_tap->timestamp,
};
struct zmk_behavior_binding sub_behavior_binding;
if (hold_tap->is_hold) { if (hold_tap->is_hold) {
sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev; ret = ZMK_EVENT_RAISE(create_behavior_state_changed(
sub_behavior_binding.param1 = hold_tap->param_hold; hold_tap->config->behaviors->hold.behavior_dev, hold_tap->event->param1, 0, false,
sub_behavior_binding.param2 = 0; hold_tap->event->layer, hold_tap->event->position, hold_tap->event->timestamp));
} else { } else {
sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev; ret = ZMK_EVENT_RAISE(create_behavior_state_changed(
sub_behavior_binding.param1 = hold_tap->param_tap; hold_tap->config->behaviors->tap.behavior_dev, hold_tap->event->param2, 0, false,
sub_behavior_binding.param2 = 0; 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) { if (work_cancel_result == -EINPROGRESS) {
// let the timer handler clean up // let the timer handler clean up
// if we'd clear now, the timer may call back for an uninitialized active_hold_tap. // 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; hold_tap->work_is_cancelled = true;
} else { } else {
LOG_DBG("%d cleaning up hold-tap", event.position); LOG_DBG("%d cleaning up hold-tap", event->position);
clear_hold_tap(hold_tap); clear_hold_tap(hold_tap);
} }
if (ret < 0) {
return ret;
}
return ZMK_BEHAVIOR_OPAQUE; 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; return ZMK_EV_EVENT_BUBBLE;
} }
if (undecided_hold_tap->position == ev->position) { if (undecided_hold_tap->event->position == ev->position) {
if (ev->state) { // keydown if (ev->state) { // keydown
LOG_ERR("hold-tap listener should be called before before most other listeners!"); LOG_ERR("hold-tap listener should be called before before most other listeners!");
return ZMK_EV_EVENT_BUBBLE; return ZMK_EV_EVENT_BUBBLE;
} else { // keyup } 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; 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 // We make a timer decision before the other key events are handled if the timer would
// have run out. // have run out.
if (ev->timestamp > 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); decide_hold_tap(undecided_hold_tap, HT_TIMER_EVENT);
} }
if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { if (!ev->state && find_captured_keydown_event(ev->position) == NULL) {
// no keydown event has been captured, let it bubble. // no keydown event has been captured, let it bubble.
// we'll catch modifiers later in modifier_state_changed_listener // 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"); ev->state ? "down" : "up");
return ZMK_EV_EVENT_BUBBLE; 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"); ev->state ? "down" : "up");
capture_event(eh); capture_event(eh);
decide_hold_tap(undecided_hold_tap, ev->state ? HT_OTHER_KEY_DOWN : HT_OTHER_KEY_UP); 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 // only key-up events will bubble through position_state_changed_listener
// if a undecided_hold_tap is active. // 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"); ev->state ? "down" : "up");
capture_event(eh); capture_event(eh);
return ZMK_EV_EVENT_CAPTURED; return ZMK_EV_EVENT_CAPTURED;
@ -485,7 +464,6 @@ static int behavior_hold_tap_init(const struct device *dev) {
if (init_first_run) { if (init_first_run) {
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { 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); 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; init_first_run = false;

View file

@ -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 behavior_key_press_init(const struct device *dev) { return 0; };
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int on_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event->position, event->param1);
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
return ZMK_EVENT_RAISE( 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, static int on_keymap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event->position, event->param1);
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
return ZMK_EVENT_RAISE( 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 = { static const struct behavior_driver_api behavior_key_press_driver_api = {

View file

@ -20,16 +20,14 @@ struct behavior_mo_data {};
static int behavior_mo_init(const struct device *dev) { return 0; }; static int behavior_mo_init(const struct device *dev) { return 0; };
static int mo_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int mo_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { LOG_DBG("position %d layer %d", event->position, event->param1);
LOG_DBG("position %d layer %d", event.position, binding->param1); return zmk_keymap_layer_activate(event->param1);
return zmk_keymap_layer_activate(binding->param1);
} }
static int mo_keymap_binding_released(struct zmk_behavior_binding *binding, static int mo_keymap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { LOG_DBG("position %d layer %d", event->position, event->param1);
LOG_DBG("position %d layer %d", event.position, binding->param1); return zmk_keymap_layer_deactivate(event->param1);
return zmk_keymap_layer_deactivate(binding->param1);
} }
static const struct behavior_driver_api behavior_mo_driver_api = { static const struct behavior_driver_api behavior_mo_driver_api = {

View file

@ -20,13 +20,11 @@ struct behavior_none_data {};
static int behavior_none_init(const struct device *dev) { return 0; }; static int behavior_none_init(const struct device *dev) { return 0; };
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int on_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) {
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }
static int on_keymap_binding_released(struct zmk_behavior_binding *binding, static int on_keymap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) {
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }

View file

@ -18,9 +18,8 @@
#include <logging/log.h> #include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int on_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { switch (event->param1) {
switch (binding->param1) {
case OUT_TOG: case OUT_TOG:
return zmk_endpoints_toggle(); return zmk_endpoints_toggle();
case OUT_USB: case OUT_USB:
@ -28,7 +27,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
case OUT_BLE: case OUT_BLE:
return zmk_endpoints_select(ZMK_ENDPOINT_BLE); return zmk_endpoints_select(ZMK_ENDPOINT_BLE);
default: default:
LOG_ERR("Unknown output command: %d", binding->param1); LOG_ERR("Unknown output command: %d", event->param1);
} }
return -ENOTSUP; return -ENOTSUP;

View file

@ -21,9 +21,8 @@ struct behavior_reset_config {
static int behavior_reset_init(const struct device *dev) { return 0; }; static int behavior_reset_init(const struct device *dev) { return 0; };
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int on_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { const struct device *dev = device_get_binding(event->behavior_dev);
const struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_reset_config *cfg = dev->config; const struct behavior_reset_config *cfg = dev->config;
// TODO: Correct magic code for going into DFU? // TODO: Correct magic code for going into DFU?

View file

@ -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 behavior_rgb_underglow_init(const struct device *dev) { return 0; }
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int on_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { switch (event->param1) {
switch (binding->param1) {
case RGB_TOG: case RGB_TOG:
return zmk_rgb_underglow_toggle(); return zmk_rgb_underglow_toggle();
case RGB_HUI: case RGB_HUI:
@ -48,8 +47,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
return -ENOTSUP; return -ENOTSUP;
} }
static int on_keymap_binding_released(struct zmk_behavior_binding *binding, static int on_keymap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) {
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }

View file

@ -18,6 +18,7 @@
#include <zmk/events/keycode_state_changed.h> #include <zmk/events/keycode_state_changed.h>
#include <zmk/events/modifiers_state_changed.h> #include <zmk/events/modifiers_state_changed.h>
#include <zmk/hid.h> #include <zmk/hid.h>
#include <zmk/event_manager.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@ -33,9 +34,7 @@ struct behavior_sticky_key_config {
}; };
struct active_sticky_key { struct active_sticky_key {
uint32_t position; const struct behavior_state_changed *event;
uint32_t param1;
uint32_t param2;
const struct behavior_sticky_key_config *config; const struct behavior_sticky_key_config *config;
// timer data. // timer data.
bool timer_started; bool timer_started;
@ -49,22 +48,18 @@ struct active_sticky_key {
struct active_sticky_key active_sticky_keys[ZMK_BHV_STICKY_KEY_MAX_HELD] = {}; 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, static struct active_sticky_key *store_sticky_key(const struct behavior_state_changed *event,
uint32_t param2,
const struct behavior_sticky_key_config *config) { const struct behavior_sticky_key_config *config) {
for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) {
struct active_sticky_key *const sticky_key = &active_sticky_keys[i]; struct active_sticky_key *const sticky_key = &active_sticky_keys[i];
if (sticky_key->position != ZMK_BHV_STICKY_KEY_POSITION_FREE || if (sticky_key->event != NULL || sticky_key->timer_cancelled) {
sticky_key->timer_cancelled) {
continue; continue;
} }
sticky_key->position = position; sticky_key->event = event;
sticky_key->param1 = param1;
sticky_key->param2 = param2;
sticky_key->config = config; sticky_key->config = config;
sticky_key->release_at = 0;
sticky_key->timer_cancelled = false; sticky_key->timer_cancelled = false;
sticky_key->timer_started = false; sticky_key->timer_started = false;
sticky_key->release_at = 0;
sticky_key->modified_key_usage_page = 0; sticky_key->modified_key_usage_page = 0;
sticky_key->modified_key_keycode = 0; sticky_key->modified_key_keycode = 0;
return sticky_key; return sticky_key;
@ -72,13 +67,11 @@ static struct active_sticky_key *store_sticky_key(uint32_t position, uint32_t pa
return NULL; 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) { static struct active_sticky_key *find_sticky_key(uint32_t position) {
for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { 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]; 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, static inline int press_sticky_key_behavior(struct active_sticky_key *sticky_key,
int64_t timestamp) { int64_t timestamp) {
struct zmk_behavior_binding binding = { return ZMK_EVENT_RAISE(create_behavior_state_changed(
.behavior_dev = sticky_key->config->behavior.behavior_dev, sticky_key->config->behavior.behavior_dev, sticky_key->event->param1,
.param1 = sticky_key->param1, sticky_key->event->param2, true, sticky_key->event->layer, sticky_key->event->position,
.param2 = sticky_key->param2, timestamp));
};
struct zmk_behavior_binding_event event = {
.position = sticky_key->position,
.timestamp = timestamp,
};
return behavior_keymap_binding_pressed(&binding, event);
} }
static inline int release_sticky_key_behavior(struct active_sticky_key *sticky_key, static inline int release_sticky_key_behavior(struct active_sticky_key *sticky_key,
int64_t timestamp) { int64_t timestamp) {
struct zmk_behavior_binding binding = { const struct behavior_state_changed *event = sticky_key->event;
.behavior_dev = sticky_key->config->behavior.behavior_dev, sticky_key->event = NULL;
.param1 = sticky_key->param1, return ZMK_EVENT_RAISE(create_behavior_state_changed(sticky_key->config->behavior.behavior_dev,
.param2 = sticky_key->param2, event->param1, event->param2, false,
}; event->layer, event->position, timestamp));
struct zmk_behavior_binding_event event = { k_free((void *)event);
.position = sticky_key->position,
.timestamp = timestamp,
};
clear_sticky_key(sticky_key);
return behavior_keymap_binding_released(&binding, event);
} }
static int stop_timer(struct active_sticky_key *sticky_key) { 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; return timer_cancel_result;
} }
static int on_sticky_key_binding_pressed(struct zmk_behavior_binding *binding, static int on_sticky_key_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { const struct device *dev = device_get_binding(event->behavior_dev);
const struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_sticky_key_config *cfg = dev->config; const struct behavior_sticky_key_config *cfg = dev->config;
struct active_sticky_key *sticky_key; struct active_sticky_key *sticky_key;
sticky_key = find_sticky_key(event.position); sticky_key = find_sticky_key(event->position);
if (sticky_key != NULL) { if (sticky_key != NULL) {
stop_timer(sticky_key); 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) { if (sticky_key == NULL) {
LOG_ERR("unable to store sticky key, did you press more than %d sticky_key?", LOG_ERR("unable to store sticky key, did you press more than %d sticky_key?",
ZMK_BHV_STICKY_KEY_MAX_HELD); ZMK_BHV_STICKY_KEY_MAX_HELD);
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }
press_sticky_key_behavior(sticky_key, event.timestamp); press_sticky_key_behavior(sticky_key, event->timestamp);
LOG_DBG("%d new sticky_key", event.position); LOG_DBG("%d new sticky_key", event->position);
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_CAPTURED;
} }
static int on_sticky_key_binding_released(struct zmk_behavior_binding *binding, static int on_sticky_key_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { struct active_sticky_key *sticky_key = find_sticky_key(event->position);
struct active_sticky_key *sticky_key = find_sticky_key(event.position);
if (sticky_key == NULL) { if (sticky_key == NULL) {
LOG_ERR("ACTIVE STICKY KEY CLEARED TOO EARLY"); LOG_ERR("ACTIVE STICKY KEY CLEARED TOO EARLY");
return ZMK_BEHAVIOR_OPAQUE; 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) { 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."); 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. // No other key was pressed. Start the timer.
sticky_key->timer_started = true; 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 // adjust timer in case this behavior was queued by a hold-tap
int32_t ms_left = sticky_key->release_at - k_uptime_get(); int32_t ms_left = sticky_key->release_at - k_uptime_get();
if (ms_left > 0) { 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); struct keycode_state_changed *ev = cast_keycode_state_changed(eh);
for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) {
struct active_sticky_key *sticky_key = &active_sticky_keys[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; continue;
} }
if (strcmp(sticky_key->config->behavior.behavior_dev, "KEY_PRESS") == 0 && if (strcmp(sticky_key->config->behavior.behavior_dev, "KEY_PRESS") == 0 &&
HID_USAGE_ID(sticky_key->param1) == ev->keycode && HID_USAGE_ID(sticky_key->event->param1) == ev->keycode &&
(HID_USAGE_PAGE(sticky_key->param1) & 0xFF) == ev->usage_page && (HID_USAGE_PAGE(sticky_key->event->param1) & 0xFF) == ev->usage_page &&
SELECT_MODS(sticky_key->param1) == ev->implicit_modifiers) { SELECT_MODS(sticky_key->event->param1) == ev->implicit_modifiers) {
// don't catch key down events generated by the sticky key behavior itself // don't catch key down events generated by the sticky key behavior itself
continue; continue;
} }
@ -231,7 +210,7 @@ ZMK_SUBSCRIPTION(behavior_sticky_key, keycode_state_changed);
void behavior_sticky_key_timer_handler(struct k_work *item) { void behavior_sticky_key_timer_handler(struct k_work *item) {
struct active_sticky_key *sticky_key = struct active_sticky_key *sticky_key =
CONTAINER_OF(item, struct active_sticky_key, release_timer); 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; return;
} }
if (sticky_key->timer_cancelled) { 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++) { for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) {
k_delayed_work_init(&active_sticky_keys[i].release_timer, k_delayed_work_init(&active_sticky_keys[i].release_timer,
behavior_sticky_key_timer_handler); 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; init_first_run = false;

View file

@ -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 behavior_to_init(const struct device *dev) { return 0; };
static int to_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int to_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { LOG_DBG("position %d layer %d", event->position, event->param1);
LOG_DBG("position %d layer %d", event.position, binding->param1); zmk_keymap_layer_to(event->param1);
zmk_keymap_layer_to(binding->param1);
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }
static int to_keymap_binding_released(struct zmk_behavior_binding *binding, static int to_keymap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { LOG_DBG("position %d layer %d", event->position, event->param1);
LOG_DBG("position %d layer %d", event.position, binding->param1);
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }

View file

@ -20,15 +20,13 @@ struct behavior_tog_data {};
static int behavior_tog_init(const struct device *dev) { return 0; }; static int behavior_tog_init(const struct device *dev) { return 0; };
static int tog_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int tog_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { LOG_DBG("position %d layer %d", event->position, event->param1);
LOG_DBG("position %d layer %d", event.position, binding->param1); return zmk_keymap_layer_toggle(event->param1);
return zmk_keymap_layer_toggle(binding->param1);
} }
static int tog_keymap_binding_released(struct zmk_behavior_binding *binding, static int tog_keymap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) { LOG_DBG("position %d layer %d", event->position, event->param1);
LOG_DBG("position %d layer %d", event.position, binding->param1);
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }

View file

@ -20,13 +20,11 @@ struct behavior_transparent_data {};
static int behavior_transparent_init(const struct device *dev) { return 0; }; static int behavior_transparent_init(const struct device *dev) { return 0; };
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static int on_keymap_binding_pressed(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) {
return ZMK_BEHAVIOR_TRANSPARENT; return ZMK_BEHAVIOR_TRANSPARENT;
} }
static int on_keymap_binding_released(struct zmk_behavior_binding *binding, static int on_keymap_binding_released(const struct behavior_state_changed *event) {
struct zmk_behavior_binding_event event) {
return ZMK_BEHAVIOR_TRANSPARENT; return ZMK_BEHAVIOR_TRANSPARENT;
} }

View file

@ -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_start[];
extern struct zmk_event_subscription __event_subscriptions_end[]; 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 zmk_event_manager_handle_from(struct zmk_event_header *event, uint8_t start_index) {
int ret = 0; int ret = 0;
uint8_t len = __event_subscriptions_end - __event_subscriptions_start; 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) { switch (ret) {
case ZMK_EV_EVENT_HANDLED: case ZMK_EV_EVENT_HANDLED:
LOG_DBG("Listener handled the event"); LOG_DBG("Listener handled the event");
ret = 0;
goto release; goto release;
case ZMK_EV_EVENT_CAPTURED: case ZMK_EV_EVENT_CAPTURED:
LOG_DBG("Listener captured the event"); LOG_DBG("Listener captured the event");
event->last_listener_index = i; event->last_listener_index = i;
// Listeners are expected to free events they capture // Listeners are expected to free events they capture
return 0; return ret;
} }
} }
} }

View file

@ -0,0 +1,10 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <kernel.h>
#include <zmk/events/behavior_state_changed.h>
ZMK_EVENT_IMPL(behavior_state_changed);

View file

@ -16,6 +16,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/event_manager.h> #include <zmk/event_manager.h>
#include <zmk/events/position_state_changed.h> #include <zmk/events/position_state_changed.h>
#include <zmk/events/behavior_state_changed.h>
#include <zmk/events/layer_state_changed.h> #include <zmk/events/layer_state_changed.h>
#include <zmk/events/sensor_event.h> #include <zmk/events/sensor_event.h>
@ -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) { 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]; struct zmk_behavior_binding *binding = &zmk_keymap[layer][position];
const struct device *behavior; 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_DBG("layer: %d position: %d, binding name: %s", layer, position,
log_strdup(binding->behavior_dev)); log_strdup(binding->behavior_dev));
@ -159,14 +155,11 @@ int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed,
if (!behavior) { if (!behavior) {
LOG_DBG("No behavior assigned to %d on layer %d", position, layer); LOG_DBG("No behavior assigned to %d on layer %d", position, layer);
return 1; return ZMK_EV_EVENT_HANDLED;
} }
if (pressed) { return ZMK_EVENT_RAISE(
return behavior_keymap_binding_pressed(binding, event); create_behavior_state_changed_from_binding(binding, pressed, layer, position, timestamp));
} else {
return behavior_keymap_binding_released(binding, event);
}
} }
int zmk_keymap_position_state_changed(uint32_t position, bool pressed, int64_t 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--) { 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])) { 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); 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"); LOG_DBG("behavior processing to continue to next layer");
continue; continue;
} else if (ret < 0) { } else if (ret < 0) {