Browse Source

Add timestamps to position and behavior events (#147)

* Add timestamps to position events and behaviors.

- Take original event timestamps into consideration so nested tap-holds have proper timing.
- Add position and timestamp to keycode state changed event so the one-shot behavior can properly identify other keypresses and timings.
- Add timestamp to position events received from peripheral

* reduce number of arguments to behaviors
xmkb
Okke Formsma 4 years ago committed by GitHub
parent
commit
d38740cebf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 44
      app/include/drivers/behavior.h
  2. 6
      app/include/zmk/behavior.h
  3. 1
      app/include/zmk/events/keycode-state-changed.h
  4. 1
      app/include/zmk/events/position-state-changed.h
  5. 2
      app/include/zmk/keymap.h
  6. 18
      app/src/behaviors/behavior_bt.c
  7. 114
      app/src/behaviors/behavior_hold_tap.c
  8. 19
      app/src/behaviors/behavior_key_press.c
  9. 17
      app/src/behaviors/behavior_momentary_layer.c
  10. 10
      app/src/behaviors/behavior_none.c
  11. 7
      app/src/behaviors/behavior_reset.c
  12. 6
      app/src/behaviors/behavior_rgb_underglow.c
  13. 11
      app/src/behaviors/behavior_sensor_rotate_key_press.c
  14. 15
      app/src/behaviors/behavior_toggle_layer.c
  15. 10
      app/src/behaviors/behavior_transparent.c
  16. 22
      app/src/keymap.c
  17. 1
      app/src/kscan.c
  18. 1
      app/src/split/bluetooth/central.c
  19. 4
      app/tests/hold-tap/balanced/many-nested/events.patterns
  20. 20
      app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot
  21. 41
      app/tests/hold-tap/balanced/many-nested/native_posix.keymap

44
app/include/drivers/behavior.h

@ -10,6 +10,7 @@
#include <stddef.h> #include <stddef.h>
#include <device.h> #include <device.h>
#include <zmk/keys.h> #include <zmk/keys.h>
#include <zmk/behavior.h>
/** /**
* @cond INTERNAL_HIDDEN * @cond INTERNAL_HIDDEN
@ -19,10 +20,10 @@
* (Internal use only.) * (Internal use only.)
*/ */
typedef int (*behavior_keymap_binding_callback_t)(struct device *dev, u32_t position, u32_t param1, typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding,
u32_t param2); struct zmk_behavior_binding_event event);
typedef int (*behavior_sensor_keymap_binding_callback_t)(struct device *dev, struct device *sensor, typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding,
u32_t param1, u32_t param2); struct device *sensor);
__subsystem struct behavior_driver_api { __subsystem struct behavior_driver_api {
behavior_keymap_binding_callback_t binding_pressed; behavior_keymap_binding_callback_t binding_pressed;
@ -42,18 +43,19 @@ __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 device *dev, u32_t position, u32_t param1, __syscall int behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding,
u32_t param2); struct zmk_behavior_binding_event event);
static inline int z_impl_behavior_keymap_binding_pressed(struct device *dev, u32_t position, static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding,
u32_t param1, u32_t param2) { struct zmk_behavior_binding_event event) {
struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api; const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api;
if (api->binding_pressed == NULL) { if (api->binding_pressed == NULL) {
return -ENOTSUP; return -ENOTSUP;
} }
return api->binding_pressed(dev, position, param1, param2); return api->binding_pressed(binding, event);
} }
/** /**
@ -64,18 +66,19 @@ static inline int z_impl_behavior_keymap_binding_pressed(struct device *dev, u32
* @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 device *dev, u32_t position, u32_t param1, __syscall int behavior_keymap_binding_released(struct zmk_behavior_binding *binding,
u32_t param2); struct zmk_behavior_binding_event event);
static inline int z_impl_behavior_keymap_binding_released(struct device *dev, u32_t position, static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_binding *binding,
u32_t param1, u32_t param2) { struct zmk_behavior_binding_event event) {
struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api; const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api;
if (api->binding_released == NULL) { if (api->binding_released == NULL) {
return -ENOTSUP; return -ENOTSUP;
} }
return api->binding_released(dev, position, param1, param2); return api->binding_released(binding, event);
} }
/** /**
@ -88,19 +91,20 @@ static inline int z_impl_behavior_keymap_binding_released(struct device *dev, u3
* @retval 0 If successful. * @retval 0 If successful.
* @retval Negative errno code if failure. * @retval Negative errno code if failure.
*/ */
__syscall int behavior_sensor_keymap_binding_triggered(struct device *dev, struct device *sensor, __syscall int behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding,
u32_t param1, u32_t param2); struct device *sensor);
static inline int z_impl_behavior_sensor_keymap_binding_triggered(struct device *dev, static inline int
struct device *sensor, z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding,
u32_t param1, u32_t param2) { struct device *sensor) {
struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api; const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api;
if (api->sensor_binding_triggered == NULL) { if (api->sensor_binding_triggered == NULL) {
return -ENOTSUP; return -ENOTSUP;
} }
return api->sensor_binding_triggered(dev, sensor, param1, param2); return api->sensor_binding_triggered(binding, sensor);
} }
/** /**

6
app/include/zmk/behavior.h

@ -10,4 +10,10 @@ struct zmk_behavior_binding {
char *behavior_dev; char *behavior_dev;
u32_t param1; u32_t param1;
u32_t param2; u32_t param2;
};
struct zmk_behavior_binding_event {
int layer;
u32_t position;
s64_t timestamp;
}; };

1
app/include/zmk/events/keycode-state-changed.h

@ -24,6 +24,5 @@ inline struct keycode_state_changed *create_keycode_state_changed(u8_t usage_pag
ev->usage_page = usage_page; ev->usage_page = usage_page;
ev->keycode = keycode; ev->keycode = keycode;
ev->state = state; ev->state = state;
return ev; return ev;
} }

1
app/include/zmk/events/position-state-changed.h

@ -13,6 +13,7 @@ struct position_state_changed {
struct zmk_event_header header; struct zmk_event_header header;
u32_t position; u32_t position;
bool state; bool state;
s64_t timestamp;
}; };
ZMK_EVENT_DECLARE(position_state_changed); ZMK_EVENT_DECLARE(position_state_changed);

2
app/include/zmk/keymap.h

@ -11,4 +11,4 @@ int zmk_keymap_layer_activate(u8_t layer);
int zmk_keymap_layer_deactivate(u8_t layer); int zmk_keymap_layer_deactivate(u8_t layer);
int zmk_keymap_layer_toggle(u8_t layer); int zmk_keymap_layer_toggle(u8_t layer);
int zmk_keymap_position_state_changed(u32_t position, bool pressed); int zmk_keymap_position_state_changed(u32_t position, bool pressed, s64_t timestamp);

18
app/src/behaviors/behavior_bt.c

@ -8,18 +8,18 @@
#include <device.h> #include <device.h>
#include <drivers/behavior.h> #include <drivers/behavior.h>
#include <dt-bindings/zmk/bt.h> #include <dt-bindings/zmk/bt.h>
#include <bluetooth/conn.h> #include <bluetooth/conn.h>
#include <logging/log.h> #include <logging/log.h>
#include <zmk/behavior.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 device *dev, u32_t position, u32_t command, u32_t arg) { static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
switch (command) { struct zmk_behavior_binding_event event) {
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 device *dev, u32_t position, u32_t c
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(arg); return zmk_ble_prof_select(binding->param2);
default: default:
LOG_ERR("Unknown BT command: %d", command); LOG_ERR("Unknown BT command: %d", binding->param1);
} }
return -ENOTSUP; return -ENOTSUP;
@ -37,8 +37,8 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c
static int behavior_bt_init(struct device *dev) { return 0; }; static int behavior_bt_init(struct device *dev) { return 0; };
static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t command, static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
u32_t arg) { struct zmk_behavior_binding_event event) {
return 0; return 0;
} }

114
app/src/behaviors/behavior_hold_tap.c

@ -10,7 +10,6 @@
#include <drivers/behavior.h> #include <drivers/behavior.h>
#include <logging/log.h> #include <logging/log.h>
#include <zmk/behavior.h> #include <zmk/behavior.h>
#include <zmk/matrix.h> #include <zmk/matrix.h>
#include <zmk/endpoints.h> #include <zmk/endpoints.h>
#include <zmk/event-manager.h> #include <zmk/event-manager.h>
@ -18,6 +17,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/behavior.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@ -40,10 +40,8 @@ struct behavior_hold_tap_behaviors {
struct zmk_behavior_binding hold; struct zmk_behavior_binding hold;
}; };
typedef k_timeout_t (*timer_func)();
struct behavior_hold_tap_config { struct behavior_hold_tap_config {
timer_func tapping_term_ms; int tapping_term_ms;
struct behavior_hold_tap_behaviors *behaviors; struct behavior_hold_tap_behaviors *behaviors;
enum flavor flavor; enum flavor flavor;
}; };
@ -51,8 +49,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 {
s32_t position; s32_t position;
// todo: move these params into the config->behaviors->tap and
u32_t param_hold; u32_t param_hold;
u32_t param_tap; u32_t param_tap;
s64_t timestamp;
bool is_decided; bool is_decided;
bool is_hold; bool is_hold;
const struct behavior_hold_tap_config *config; const struct behavior_hold_tap_config *config;
@ -164,6 +164,7 @@ static struct active_hold_tap *find_hold_tap(u32_t position) {
} }
static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold, u32_t param_tap, static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold, u32_t param_tap,
s64_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].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) {
@ -175,6 +176,7 @@ static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold,
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_hold = param_hold;
active_hold_taps[i].param_tap = param_tap; 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;
@ -253,7 +255,7 @@ static inline char *flavor_str(enum flavor flavor) {
return "UNKNOWN FLAVOR"; return "UNKNOWN FLAVOR";
} }
static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_moment event) { static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_moment event_type) {
if (hold_tap->is_decided) { if (hold_tap->is_decided) {
return; return;
} }
@ -265,11 +267,11 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome
switch (hold_tap->config->flavor) { switch (hold_tap->config->flavor) {
case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED: case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED:
decide_hold_preferred(hold_tap, event); decide_hold_preferred(hold_tap, event_type);
case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED: case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED:
decide_balanced(hold_tap, event); decide_balanced(hold_tap, event_type);
case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED: case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED:
decide_tap_preferred(hold_tap, event); decide_tap_preferred(hold_tap, event_type);
} }
if (!hold_tap->is_decided) { if (!hold_tap->is_decided) {
@ -277,26 +279,31 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome
} }
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->position, hold_tap->is_hold ? "hold" : "tap",
flavor_str(hold_tap->config->flavor), event); flavor_str(hold_tap->config->flavor), event_type);
undecided_hold_tap = NULL; undecided_hold_tap = NULL;
struct zmk_behavior_binding *behavior; 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) {
behavior = &hold_tap->config->behaviors->hold; binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev;
struct device *behavior_device = device_get_binding(behavior->behavior_dev); binding.param1 = hold_tap->param_hold;
behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_hold, binding.param2 = 0;
0);
} else { } else {
behavior = &hold_tap->config->behaviors->tap; binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev;
struct device *behavior_device = device_get_binding(behavior->behavior_dev); binding.param1 = hold_tap->param_tap;
behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_tap, binding.param2 = 0;
0);
} }
behavior_keymap_binding_pressed(&binding, event);
release_captured_events(); release_captured_events();
} }
static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t param_hold, static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
u32_t param_tap) { struct zmk_behavior_binding_event event) {
struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_hold_tap_config *cfg = dev->config_info; const struct behavior_hold_tap_config *cfg = dev->config_info;
if (undecided_hold_tap != NULL) { if (undecided_hold_tap != NULL) {
@ -305,54 +312,69 @@ static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t
return 0; return 0;
} }
struct active_hold_tap *hold_tap = store_hold_tap(position, param_hold, param_tap, cfg); struct active_hold_tap *hold_tap =
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 0; return 0;
} }
LOG_DBG("%d new undecided hold_tap", position); LOG_DBG("%d new undecided hold_tap", event.position);
undecided_hold_tap = hold_tap; undecided_hold_tap = hold_tap;
k_delayed_work_submit(&hold_tap->work, cfg->tapping_term_ms());
// todo: once we get timing info for keypresses, start the timer relative to the original // if this behavior was queued we have to adjust the timer to only
// keypress don't forget to simulate a timer-event before the event after that time was handled. // wait for the remaining time.
s32_t tapping_term_ms_left = (hold_tap->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 0; return 0;
} }
static int on_hold_tap_binding_released(struct device *dev, u32_t position, u32_t _, u32_t __) { static int on_hold_tap_binding_released(struct zmk_behavior_binding *binding,
struct active_hold_tap *hold_tap = find_hold_tap(position); struct zmk_behavior_binding_event event) {
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 0; return 0;
} }
// 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); int work_cancel_result = k_delayed_work_cancel(&hold_tap->work);
if (event.timestamp > (hold_tap->timestamp + hold_tap->config->tapping_term_ms)) {
decide_hold_tap(hold_tap, HT_TIMER_EVENT);
}
decide_hold_tap(hold_tap, HT_KEY_UP); decide_hold_tap(hold_tap, HT_KEY_UP);
struct zmk_behavior_binding *behavior; // 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;
if (hold_tap->is_hold) { if (hold_tap->is_hold) {
behavior = &hold_tap->config->behaviors->hold; sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev;
struct device *behavior_device = device_get_binding(behavior->behavior_dev); sub_behavior_binding.param1 = hold_tap->param_hold;
behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_hold, sub_behavior_binding.param2 = 0;
0);
} else { } else {
behavior = &hold_tap->config->behaviors->tap; sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev;
struct device *behavior_device = device_get_binding(behavior->behavior_dev); sub_behavior_binding.param1 = hold_tap->param_tap;
behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_tap, sub_behavior_binding.param2 = 0;
0);
} }
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", 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", position); LOG_DBG("%d cleaning up hold-tap", event.position);
clear_hold_tap(hold_tap); clear_hold_tap(hold_tap);
} }
@ -382,6 +404,14 @@ static int position_state_changed_listener(const struct zmk_event_header *eh) {
} }
} }
// If these events were queued, the timer event may be queued too late or not at all.
// 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)) {
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
@ -463,6 +493,7 @@ static int behavior_hold_tap_init(struct device *dev) {
struct behavior_hold_tap_data {}; struct behavior_hold_tap_data {};
static struct behavior_hold_tap_data behavior_hold_tap_data; static struct behavior_hold_tap_data behavior_hold_tap_data;
/* todo: get rid of unused param1 and param2. */
#define _TRANSFORM_ENTRY(idx, node) \ #define _TRANSFORM_ENTRY(idx, node) \
{ \ { \
.behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \ .behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \
@ -473,14 +504,11 @@ static struct behavior_hold_tap_data behavior_hold_tap_data;
}, },
#define KP_INST(n) \ #define KP_INST(n) \
static k_timeout_t behavior_hold_tap_config_##n##_gettime() { \
return K_MSEC(DT_INST_PROP(n, tapping_term_ms)); \
} \
static struct behavior_hold_tap_behaviors behavior_hold_tap_behaviors_##n = { \ static struct behavior_hold_tap_behaviors behavior_hold_tap_behaviors_##n = { \
.hold = _TRANSFORM_ENTRY(0, n).tap = _TRANSFORM_ENTRY(1, n)}; \ .hold = _TRANSFORM_ENTRY(0, n).tap = _TRANSFORM_ENTRY(1, n)}; \
static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \ static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \
.behaviors = &behavior_hold_tap_behaviors_##n, \ .behaviors = &behavior_hold_tap_behaviors_##n, \
.tapping_term_ms = &behavior_hold_tap_config_##n##_gettime, \ .tapping_term_ms = DT_INST_PROP(n, tapping_term_ms), \
.flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \
}; \ }; \
DEVICE_AND_API_INIT(behavior_hold_tap_##n, DT_INST_LABEL(n), behavior_hold_tap_init, \ DEVICE_AND_API_INIT(behavior_hold_tap_##n, DT_INST_LABEL(n), behavior_hold_tap_init, \

19
app/src/behaviors/behavior_key_press.c

@ -12,6 +12,7 @@
#include <zmk/event-manager.h> #include <zmk/event-manager.h>
#include <zmk/events/keycode-state-changed.h> #include <zmk/events/keycode-state-changed.h>
#include <zmk/behavior.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@ -22,18 +23,24 @@ struct behavior_key_press_data {};
static int behavior_key_press_init(struct device *dev) { return 0; }; static int behavior_key_press_init(struct device *dev) { return 0; };
static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t keycode, u32_t _) { static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_key_press_config *cfg = dev->config_info; const struct behavior_key_press_config *cfg = dev->config_info;
LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode); LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", event.position, cfg->usage_page,
binding->param1);
return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, true)); return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, binding->param1, true));
} }
static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t keycode, u32_t _) { static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_key_press_config *cfg = dev->config_info; const struct behavior_key_press_config *cfg = dev->config_info;
LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode); LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", event.position, cfg->usage_page,
binding->param1);
return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, false)); return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, binding->param1, false));
} }
static const struct behavior_driver_api behavior_key_press_driver_api = { static const struct behavior_driver_api behavior_key_press_driver_api = {

17
app/src/behaviors/behavior_momentary_layer.c

@ -11,6 +11,7 @@
#include <logging/log.h> #include <logging/log.h>
#include <zmk/keymap.h> #include <zmk/keymap.h>
#include <zmk/behavior.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@ -19,16 +20,16 @@ struct behavior_mo_data {};
static int behavior_mo_init(struct device *dev) { return 0; }; static int behavior_mo_init(struct device *dev) { return 0; };
static int mo_keymap_binding_pressed(struct device *dev, u32_t position, u32_t layer, u32_t _) { static int mo_keymap_binding_pressed(struct zmk_behavior_binding *binding,
LOG_DBG("position %d layer %d", position, layer); struct zmk_behavior_binding_event event) {
LOG_DBG("position %d layer %d", event.position, binding->param1);
return zmk_keymap_layer_activate(layer); return zmk_keymap_layer_activate(binding->param1);
} }
static int mo_keymap_binding_released(struct device *dev, u32_t position, u32_t layer, u32_t _) { static int mo_keymap_binding_released(struct zmk_behavior_binding *binding,
LOG_DBG("position %d layer %d", position, layer); struct zmk_behavior_binding_event event) {
LOG_DBG("position %d layer %d", event.position, binding->param1);
return zmk_keymap_layer_deactivate(layer); 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 = {

10
app/src/behaviors/behavior_none.c

@ -11,6 +11,8 @@
#include <drivers/behavior.h> #include <drivers/behavior.h>
#include <logging/log.h> #include <logging/log.h>
#include <zmk/behavior.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
struct behavior_none_config {}; struct behavior_none_config {};
@ -18,13 +20,13 @@ struct behavior_none_data {};
static int behavior_none_init(struct device *dev) { return 0; }; static int behavior_none_init(struct device *dev) { return 0; };
static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
u32_t _param2) { struct zmk_behavior_binding_event event) {
return 0; return 0;
} }
static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t _param1, static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
u32_t _param2) { struct zmk_behavior_binding_event event) {
return 0; return 0;
} }

7
app/src/behaviors/behavior_reset.c

@ -11,6 +11,8 @@
#include <drivers/behavior.h> #include <drivers/behavior.h>
#include <logging/log.h> #include <logging/log.h>
#include <zmk/behavior.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
struct behavior_reset_config { struct behavior_reset_config {
@ -19,8 +21,9 @@ struct behavior_reset_config {
static int behavior_reset_init(struct device *dev) { return 0; }; static int behavior_reset_init(struct device *dev) { return 0; };
static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
u32_t _param2) { struct zmk_behavior_binding_event event) {
struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_reset_config *cfg = dev->config_info; const struct behavior_reset_config *cfg = dev->config_info;
// TODO: Correct magic code for going into DFU? // TODO: Correct magic code for going into DFU?

6
app/src/behaviors/behavior_rgb_underglow.c

@ -12,13 +12,15 @@
#include <dt-bindings/zmk/rgb.h> #include <dt-bindings/zmk/rgb.h>
#include <zmk/rgb_underglow.h> #include <zmk/rgb_underglow.h>
#include <zmk/keymap.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
static int behavior_rgb_underglow_init(struct device *dev) { return 0; } static int behavior_rgb_underglow_init(struct device *dev) { return 0; }
static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t action, u32_t _) { static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
switch (action) { struct zmk_behavior_binding_event event) {
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:

11
app/src/behaviors/behavior_sensor_rotate_key_press.c

@ -23,15 +23,16 @@ struct behavior_sensor_rotate_key_press_data {};
static int behavior_sensor_rotate_key_press_init(struct device *dev) { return 0; }; static int behavior_sensor_rotate_key_press_init(struct device *dev) { return 0; };
static int on_sensor_binding_triggered(struct device *dev, struct device *sensor, static int on_sensor_binding_triggered(struct zmk_behavior_binding *binding,
u32_t increment_keycode, u32_t decrement_keycode) { struct device *sensor) {
struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_sensor_rotate_key_press_config *cfg = dev->config_info; const struct behavior_sensor_rotate_key_press_config *cfg = dev->config_info;
struct sensor_value value; struct sensor_value value;
int err; int err;
u32_t keycode; u32_t keycode;
struct keycode_state_changed *ev; struct keycode_state_changed *ev;
LOG_DBG("usage_page 0x%02X inc keycode 0x%02X dec keycode 0x%02X", cfg->usage_page, LOG_DBG("usage_page 0x%02X inc keycode 0x%02X dec keycode 0x%02X", cfg->usage_page,
increment_keycode, decrement_keycode); binding->param1, binding->param2);
err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value); err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value);
@ -42,10 +43,10 @@ static int on_sensor_binding_triggered(struct device *dev, struct device *sensor
switch (value.val1) { switch (value.val1) {
case 1: case 1:
keycode = increment_keycode; keycode = binding->param1;
break; break;
case -1: case -1:
keycode = decrement_keycode; keycode = binding->param2;
break; break;
default: default:
return -ENOTSUP; return -ENOTSUP;

15
app/src/behaviors/behavior_toggle_layer.c

@ -11,6 +11,7 @@
#include <logging/log.h> #include <logging/log.h>
#include <zmk/keymap.h> #include <zmk/keymap.h>
#include <zmk/behavior.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@ -19,15 +20,15 @@ struct behavior_tog_data {};
static int behavior_tog_init(struct device *dev) { return 0; }; static int behavior_tog_init(struct device *dev) { return 0; };
static int tog_keymap_binding_pressed(struct device *dev, u32_t position, u32_t layer, u32_t _) { static int tog_keymap_binding_pressed(struct zmk_behavior_binding *binding,
LOG_DBG("position %d layer %d", position, layer); struct zmk_behavior_binding_event event) {
LOG_DBG("position %d layer %d", event.position, binding->param1);
return zmk_keymap_layer_toggle(layer); return zmk_keymap_layer_toggle(binding->param1);
} }
static int tog_keymap_binding_released(struct device *dev, u32_t position, u32_t layer, u32_t _) { static int tog_keymap_binding_released(struct zmk_behavior_binding *binding,
LOG_DBG("position %d layer %d", position, layer); struct zmk_behavior_binding_event event) {
LOG_DBG("position %d layer %d", event.position, binding->param1);
return 0; return 0;
} }

10
app/src/behaviors/behavior_transparent.c

@ -11,6 +11,8 @@
#include <drivers/behavior.h> #include <drivers/behavior.h>
#include <logging/log.h> #include <logging/log.h>
#include <zmk/behavior.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
struct behavior_transparent_config {}; struct behavior_transparent_config {};
@ -18,13 +20,13 @@ struct behavior_transparent_data {};
static int behavior_transparent_init(struct device *dev) { return 0; }; static int behavior_transparent_init(struct device *dev) { return 0; };
static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
u32_t _param2) { struct zmk_behavior_binding_event event) {
return 1; return 1;
} }
static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t _param1, static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
u32_t _param2) { struct zmk_behavior_binding_event event) {
return 1; return 1;
} }

22
app/src/keymap.c

@ -104,9 +104,14 @@ bool is_active_layer(u8_t layer, u32_t layer_state) {
return (layer_state & BIT(layer)) == BIT(layer) || layer == zmk_keymap_layer_default; return (layer_state & BIT(layer)) == BIT(layer) || layer == zmk_keymap_layer_default;
} }
int zmk_keymap_apply_position_state(int layer, u32_t position, bool pressed) { int zmk_keymap_apply_position_state(int layer, u32_t position, bool pressed, s64_t timestamp) {
struct zmk_behavior_binding *binding = &zmk_keymap[layer][position]; struct zmk_behavior_binding *binding = &zmk_keymap[layer][position];
struct device *behavior; 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));
@ -119,20 +124,18 @@ int zmk_keymap_apply_position_state(int layer, u32_t position, bool pressed) {
} }
if (pressed) { if (pressed) {
return behavior_keymap_binding_pressed(behavior, position, binding->param1, return behavior_keymap_binding_pressed(binding, event);
binding->param2);
} else { } else {
return behavior_keymap_binding_released(behavior, position, binding->param1, return behavior_keymap_binding_released(binding, event);
binding->param2);
} }
} }
int zmk_keymap_position_state_changed(u32_t position, bool pressed) { int zmk_keymap_position_state_changed(u32_t position, bool pressed, s64_t timestamp) {
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--) {
u32_t layer_state = u32_t layer_state =
pressed ? zmk_keymap_layer_state : zmk_keymap_active_behavior_layer[position]; pressed ? zmk_keymap_layer_state : zmk_keymap_active_behavior_layer[position];
if (is_active_layer(layer, layer_state)) { if (is_active_layer(layer, layer_state)) {
int ret = zmk_keymap_apply_position_state(layer, position, pressed); int ret = zmk_keymap_apply_position_state(layer, position, pressed, timestamp);
zmk_keymap_active_behavior_layer[position] = zmk_keymap_layer_state; zmk_keymap_active_behavior_layer[position] = zmk_keymap_layer_state;
@ -171,8 +174,7 @@ int zmk_keymap_sensor_triggered(u8_t sensor_number, struct device *sensor) {
continue; continue;
} }
ret = behavior_sensor_keymap_binding_triggered(behavior, sensor, binding->param1, ret = behavior_sensor_keymap_binding_triggered(binding, sensor);
binding->param2);
if (ret > 0) { if (ret > 0) {
LOG_DBG("behavior processing to continue to next layer"); LOG_DBG("behavior processing to continue to next layer");
@ -194,7 +196,7 @@ int zmk_keymap_sensor_triggered(u8_t sensor_number, struct device *sensor) {
int keymap_listener(const struct zmk_event_header *eh) { int keymap_listener(const struct zmk_event_header *eh) {
if (is_position_state_changed(eh)) { if (is_position_state_changed(eh)) {
const struct position_state_changed *ev = cast_position_state_changed(eh); const struct position_state_changed *ev = cast_position_state_changed(eh);
return zmk_keymap_position_state_changed(ev->position, ev->state); return zmk_keymap_position_state_changed(ev->position, ev->state, ev->timestamp);
#if ZMK_KEYMAP_HAS_SENSORS #if ZMK_KEYMAP_HAS_SENSORS
} else if (is_sensor_event(eh)) { } else if (is_sensor_event(eh)) {
const struct sensor_event *ev = cast_sensor_event(eh); const struct sensor_event *ev = cast_sensor_event(eh);

1
app/src/kscan.c

@ -52,6 +52,7 @@ void zmk_kscan_process_msgq(struct k_work *item) {
pos_ev = new_position_state_changed(); pos_ev = new_position_state_changed();
pos_ev->state = pressed; pos_ev->state = pressed;
pos_ev->position = position; pos_ev->position = position;
pos_ev->timestamp = k_uptime_get();
ZMK_EVENT_RAISE(pos_ev); ZMK_EVENT_RAISE(pos_ev);
} }
} }

1
app/src/split/bluetooth/central.c

@ -60,6 +60,7 @@ static u8_t split_central_notify_func(struct bt_conn *conn, struct bt_gatt_subsc
struct position_state_changed *pos_ev = new_position_state_changed(); struct position_state_changed *pos_ev = new_position_state_changed();
pos_ev->position = position; pos_ev->position = position;
pos_ev->state = pressed; pos_ev->state = pressed;
pos_ev->timestamp = k_uptime_get();
LOG_DBG("Trigger key position state change for %d", position); LOG_DBG("Trigger key position state change for %d", position);
ZMK_EVENT_RAISE(pos_ev); ZMK_EVENT_RAISE(pos_ev);

4
app/tests/hold-tap/balanced/many-nested/events.patterns

@ -0,0 +1,4 @@
s/.*hid_listener_keycode/kp/p
s/.*mo_keymap_binding/mo/p
s/.*on_hold_tap_binding/ht_binding/p
s/.*decide_hold_tap/ht_decide/p

20
app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot

@ -0,0 +1,20 @@
ht_binding_pressed: 0 new undecided hold_tap
ht_decide: 0 decided hold (balanced event 3)
kp_pressed: usage_page 0x07 keycode 0xe1
ht_binding_pressed: 1 new undecided hold_tap
ht_decide: 1 decided hold (balanced event 3)
kp_pressed: usage_page 0x07 keycode 0xe0
ht_binding_pressed: 2 new undecided hold_tap
ht_binding_released: 0 cleaning up hold-tap
ht_decide: 2 decided hold (balanced event 3)
kp_pressed: usage_page 0x07 keycode 0xe3
ht_binding_pressed: 3 new undecided hold_tap
ht_binding_released: 1 cleaning up hold-tap
ht_decide: 3 decided hold (balanced event 3)
kp_pressed: usage_page 0x07 keycode 0xe2
kp_released: usage_page 0x07 keycode 0xe1
kp_released: usage_page 0x07 keycode 0xe0
kp_released: usage_page 0x07 keycode 0xe3
ht_binding_released: 2 cleaning up hold-tap
kp_released: usage_page 0x07 keycode 0xe2
ht_binding_released: 3 cleaning up hold-tap

41
app/tests/hold-tap/balanced/many-nested/native_posix.keymap

@ -0,0 +1,41 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan-mock.h>
/ {
behaviors {
ht_bal: behavior_hold_tap_balanced {
compatible = "zmk,behavior-hold-tap";
label = "HOLD_TAP_BALANCED";
#binding-cells = <2>;
flavor = "balanced";
tapping_term_ms = <300>;
bindings = <&kp>, <&kp>;
};
};
keymap {
compatible = "zmk,keymap";
label ="Default keymap";
default_layer {
bindings = <
&ht_bal LSFT F &ht_bal LCTL J
&ht_bal LGUI H &ht_bal LALT L
>;
};
};
};
&kscan {
events = <
ZMK_MOCK_PRESS(0,0,100)
ZMK_MOCK_PRESS(0,1,100)
ZMK_MOCK_PRESS(1,0,100)
ZMK_MOCK_PRESS(1,1,100)
ZMK_MOCK_RELEASE(0,0,100)
ZMK_MOCK_RELEASE(0,1,100)
ZMK_MOCK_RELEASE(1,0,100)
ZMK_MOCK_RELEASE(1,1,100)
>;
};
Loading…
Cancel
Save