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_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/)

View file

@ -11,6 +11,7 @@
#include <device.h>
#include <zmk/keys.h>
#include <zmk/behavior.h>
#include <zmk/events/behavior_state_changed.h>
/**
* @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);
}
/**

View file

@ -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;

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 <logging/log.h>
#include <zmk/behavior.h>
#include <zmk/events/behavior_state_changed.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/ble.h>
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;
}

View file

@ -16,15 +16,14 @@
#include <logging/log.h>
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;
}

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_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;

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 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 = {

View file

@ -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 = {

View file

@ -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;
}

View file

@ -18,9 +18,8 @@
#include <logging/log.h>
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;

View file

@ -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?

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 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;
}

View file

@ -18,6 +18,7 @@
#include <zmk/events/keycode_state_changed.h>
#include <zmk/events/modifiers_state_changed.h>
#include <zmk/hid.h>
#include <zmk/event_manager.h>
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;

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 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;
}

View file

@ -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;
}

View file

@ -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;
}

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_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;
}
}
}

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/events/position_state_changed.h>
#include <zmk/events/behavior_state_changed.h>
#include <zmk/events/layer_state_changed.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) {
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) {