Merge pull request #146 from okke-formsma/hold-tap
Hold-Tap implementation
This commit is contained in:
commit
48a3729ffe
120 changed files with 1528 additions and 272 deletions
|
@ -25,7 +25,6 @@ zephyr_linker_sources(RODATA include/linker/zmk-events.ld)
|
|||
target_include_directories(app PRIVATE include)
|
||||
target_sources(app PRIVATE src/kscan.c)
|
||||
target_sources(app PRIVATE src/matrix_transform.c)
|
||||
target_sources(app PRIVATE src/keymap.c)
|
||||
target_sources(app PRIVATE src/hid.c)
|
||||
target_sources(app PRIVATE src/sensors.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE src/display.c)
|
||||
|
@ -36,12 +35,13 @@ target_sources(app PRIVATE src/events/modifiers_state_changed.c)
|
|||
target_sources(app PRIVATE src/events/sensor_event.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_reset.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_mod_tap.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_none.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
|
||||
target_sources(app PRIVATE src/keymap.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <behaviors/transparent.dtsi>
|
||||
#include <behaviors/none.dtsi>
|
||||
#include <behaviors/mod_tap.dtsi>
|
||||
#include <behaviors/layer_tap.dtsi>
|
||||
#include <behaviors/momentary_layer.dtsi>
|
||||
#include <behaviors/toggle_layer.dtsi>
|
||||
#include <behaviors/reset.dtsi>
|
||||
|
|
12
app/dts/behaviors/layer_tap.dtsi
Normal file
12
app/dts/behaviors/layer_tap.dtsi
Normal file
|
@ -0,0 +1,12 @@
|
|||
/ {
|
||||
behaviors {
|
||||
lt: behavior_layer_tap {
|
||||
compatible = "zmk,behavior-hold-tap";
|
||||
label = "LAYER_TAP";
|
||||
#binding-cells = <2>;
|
||||
flavor = "tap-preferred";
|
||||
tapping_term_ms = <200>;
|
||||
bindings = <&mo>, <&kp>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,9 +1,12 @@
|
|||
/ {
|
||||
behaviors {
|
||||
mt: behavior_mod_tap {
|
||||
compatible = "zmk,behavior-mod-tap";
|
||||
compatible = "zmk,behavior-hold-tap";
|
||||
label = "MOD_TAP";
|
||||
#binding-cells = <2>;
|
||||
flavor = "hold-preferred";
|
||||
tapping_term_ms = <200>;
|
||||
bindings = <&kp>, <&kp>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
23
app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml
Normal file
23
app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Copyright (c) 2020, Cody McGinnis; Okke Formsma
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Hold or Tap behavior
|
||||
|
||||
compatible: "zmk,behavior-hold-tap"
|
||||
|
||||
include: two_param.yaml
|
||||
|
||||
properties:
|
||||
bindings:
|
||||
type: phandles
|
||||
required: true
|
||||
tapping_term_ms:
|
||||
type: int
|
||||
flavor:
|
||||
type: string
|
||||
required: false
|
||||
default: "hold-preferred"
|
||||
enum:
|
||||
- "hold-preferred"
|
||||
- "balanced"
|
||||
- "tap-preferred"
|
|
@ -1,8 +0,0 @@
|
|||
# Copyright (c) 2020, Pete Johanson
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Mod-Tap Beavhior
|
||||
|
||||
compatible: "zmk,behavior-mod-tap"
|
||||
|
||||
include: two_param.yaml
|
|
@ -75,9 +75,14 @@ struct zmk_event_subscription {
|
|||
#define ZMK_EVENT_RAISE_AFTER(ev, mod) \
|
||||
zmk_event_manager_raise_after((struct zmk_event_header *)ev, &zmk_listener_##mod);
|
||||
|
||||
|
||||
#define ZMK_EVENT_RAISE_AT(ev, mod) \
|
||||
zmk_event_manager_raise_at((struct zmk_event_header *)ev, &zmk_listener_##mod);
|
||||
|
||||
#define ZMK_EVENT_RELEASE(ev) \
|
||||
zmk_event_manager_release((struct zmk_event_header *)ev);
|
||||
|
||||
int zmk_event_manager_raise(struct zmk_event_header *event);
|
||||
int zmk_event_manager_raise_after(struct zmk_event_header *event, const struct zmk_listener *listener);
|
||||
int zmk_event_manager_raise_at(struct zmk_event_header *event, const struct zmk_listener *listener);
|
||||
int zmk_event_manager_release(struct zmk_event_header *event);
|
||||
|
|
502
app/src/behaviors/behavior_hold_tap.c
Normal file
502
app/src/behaviors/behavior_hold_tap.c
Normal file
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Cody McGinnis, Okke Formsma
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_hold_tap
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <logging/log.h>
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
#include <zmk/matrix.h>
|
||||
#include <zmk/endpoints.h>
|
||||
#include <zmk/event-manager.h>
|
||||
#include <zmk/events/position-state-changed.h>
|
||||
#include <zmk/events/keycode-state-changed.h>
|
||||
#include <zmk/events/modifiers-state-changed.h>
|
||||
#include <zmk/hid.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_NODE_EXISTS(DT_DRV_INST(0))
|
||||
|
||||
#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,
|
||||
ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED = 2,
|
||||
};
|
||||
|
||||
struct behavior_hold_tap_behaviors {
|
||||
struct zmk_behavior_binding tap;
|
||||
struct zmk_behavior_binding hold;
|
||||
};
|
||||
|
||||
typedef k_timeout_t (*timer_func)();
|
||||
|
||||
struct behavior_hold_tap_config {
|
||||
timer_func tapping_term_ms;
|
||||
struct behavior_hold_tap_behaviors *behaviors;
|
||||
enum flavor flavor;
|
||||
};
|
||||
|
||||
// this data is specific for each hold-tap
|
||||
struct active_hold_tap {
|
||||
s32_t position;
|
||||
u32_t param_hold;
|
||||
u32_t param_tap;
|
||||
bool is_decided;
|
||||
bool is_hold;
|
||||
const struct behavior_hold_tap_config *config;
|
||||
struct k_delayed_work work;
|
||||
bool work_is_cancelled;
|
||||
};
|
||||
|
||||
// The undecided hold tap is the hold tap that needs to be decided before
|
||||
// other keypress events can be released. While the undecided_hold_tap is
|
||||
// not NULL, most events are captured in captured_events.
|
||||
// After the hold_tap is decided, it will stay in the active_hold_taps until
|
||||
// its key-up has been processed and the delayed work is cleaned up.
|
||||
struct active_hold_tap *undecided_hold_tap = NULL;
|
||||
struct active_hold_tap active_hold_taps[ZMK_BHV_HOLD_TAP_MAX_HELD] = {};
|
||||
// We capture most position_state_changed events and some modifiers_state_changed events.
|
||||
const struct zmk_event_header *captured_events[ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS] = {};
|
||||
|
||||
static int capture_event(const struct zmk_event_header *event)
|
||||
{
|
||||
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) {
|
||||
if (captured_events[i] == NULL) {
|
||||
captured_events[i] = event;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct position_state_changed *find_captured_keydown_event(u32_t position)
|
||||
{
|
||||
struct position_state_changed *last_match = NULL;
|
||||
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) {
|
||||
const struct zmk_event_header *eh = captured_events[i];
|
||||
if (eh == NULL) {
|
||||
return last_match;
|
||||
}
|
||||
if (!is_position_state_changed(eh)) {
|
||||
continue;
|
||||
}
|
||||
struct position_state_changed *position_event = cast_position_state_changed(eh);
|
||||
if (position_event->position == position && position_event->state) {
|
||||
last_match = position_event;
|
||||
}
|
||||
}
|
||||
return last_match;
|
||||
}
|
||||
|
||||
const struct zmk_listener zmk_listener_behavior_hold_tap;
|
||||
|
||||
static void release_captured_events()
|
||||
{
|
||||
if (undecided_hold_tap != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We use a trick to prevent copying the captured_events array.
|
||||
//
|
||||
// Events for different mod-tap instances are separated by a NULL pointer.
|
||||
//
|
||||
// The first event popped will never be catched by the next active hold-tap
|
||||
// because to start capturing a mod-tap-key-down event must first completely
|
||||
// go through the events queue.
|
||||
//
|
||||
// Example of this release process;
|
||||
// [mt2_down, k1_down, k1_up, mt2_up, null, ...]
|
||||
// ^
|
||||
// mt2_down position event isn't captured because no hold-tap is active.
|
||||
// mt2_down behavior event is handled, now we have an undecided hold-tap
|
||||
// [null, k1_down, k1_up, mt2_up, null, ...]
|
||||
// ^
|
||||
// k1_down is captured by the mt2 mod-tap
|
||||
// !note that searches for find_captured_keydown_event by the mt2 behavior will stop at the first null encountered
|
||||
// [mt1_down, null, k1_up, mt2_up, null, ...]
|
||||
// ^
|
||||
// k1_up event is captured by the new hold-tap:
|
||||
// [k1_down, k1_up, null, mt2_up, null, ...]
|
||||
// ^
|
||||
// mt2_up event is not captured but causes release of mt2 behavior
|
||||
// [k1_down, k1_up, null, null, null, ...]
|
||||
// now mt2 will start releasing it's own captured positions.
|
||||
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) {
|
||||
const struct zmk_event_header *captured_event = captured_events[i];
|
||||
if (captured_event == NULL) {
|
||||
return;
|
||||
}
|
||||
captured_events[i] = NULL;
|
||||
if (undecided_hold_tap != NULL) {
|
||||
k_msleep(10);
|
||||
}
|
||||
if (is_position_state_changed(captured_event)) {
|
||||
struct position_state_changed *position_event = cast_position_state_changed(captured_event);
|
||||
LOG_DBG("Releasing key position event for position %d %s", position_event->position, (position_event->state ? "pressed" : "released"));
|
||||
} else {
|
||||
struct keycode_state_changed *modifier_event = cast_keycode_state_changed(captured_event);
|
||||
LOG_DBG("Releasing mods changed event 0x%02X %s", modifier_event->keycode, (modifier_event->state ? "pressed" : "released"));
|
||||
}
|
||||
ZMK_EVENT_RAISE_AT(captured_event, behavior_hold_tap);
|
||||
}
|
||||
}
|
||||
|
||||
static struct active_hold_tap *find_hold_tap(u32_t position)
|
||||
{
|
||||
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) {
|
||||
if (active_hold_taps[i].position == position) {
|
||||
return &active_hold_taps[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold, u32_t param_tap, 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) {
|
||||
continue;
|
||||
}
|
||||
active_hold_taps[i].position = position;
|
||||
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;
|
||||
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;
|
||||
hold_tap->is_decided = false;
|
||||
hold_tap->is_hold = false;
|
||||
hold_tap->work_is_cancelled = false;
|
||||
}
|
||||
|
||||
enum decision_moment {
|
||||
HT_KEY_UP = 0,
|
||||
HT_OTHER_KEY_DOWN = 1,
|
||||
HT_OTHER_KEY_UP = 2,
|
||||
HT_TIMER_EVENT = 3,
|
||||
};
|
||||
|
||||
static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_moment event)
|
||||
{
|
||||
switch (event) {
|
||||
case HT_KEY_UP:
|
||||
hold_tap->is_hold = 0;
|
||||
hold_tap->is_decided = true;
|
||||
break;
|
||||
case HT_OTHER_KEY_UP:
|
||||
case HT_TIMER_EVENT:
|
||||
hold_tap->is_hold = 1;
|
||||
hold_tap->is_decided = true;
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision_moment event)
|
||||
{
|
||||
switch (event) {
|
||||
case HT_KEY_UP:
|
||||
hold_tap->is_hold = 0;
|
||||
hold_tap->is_decided = true;
|
||||
break;
|
||||
case HT_TIMER_EVENT:
|
||||
hold_tap->is_hold = 1;
|
||||
hold_tap->is_decided = true;
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decision_moment event)
|
||||
{
|
||||
switch (event) {
|
||||
case HT_KEY_UP:
|
||||
hold_tap->is_hold = 0;
|
||||
hold_tap->is_decided = true;
|
||||
break;
|
||||
case HT_OTHER_KEY_DOWN:
|
||||
case HT_TIMER_EVENT:
|
||||
hold_tap->is_hold = 1;
|
||||
hold_tap->is_decided = true;
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
static inline char* flavor_str(enum flavor flavor) {
|
||||
switch(flavor) {
|
||||
case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED:
|
||||
return "hold-preferred";
|
||||
case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED:
|
||||
return "balanced";
|
||||
case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED:
|
||||
return "tap-preferred";
|
||||
}
|
||||
return "UNKNOWN FLAVOR";
|
||||
}
|
||||
|
||||
static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_moment event)
|
||||
{
|
||||
if (hold_tap->is_decided) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hold_tap != undecided_hold_tap) {
|
||||
LOG_DBG("ERROR found undecided tap hold that is not the active tap hold");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(hold_tap->config->flavor) {
|
||||
case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED:
|
||||
decide_hold_preferred(hold_tap, event);
|
||||
case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED:
|
||||
decide_balanced(hold_tap, event);
|
||||
case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED:
|
||||
decide_tap_preferred(hold_tap, event);
|
||||
}
|
||||
|
||||
if (!hold_tap->is_decided) {
|
||||
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);
|
||||
undecided_hold_tap = NULL;
|
||||
|
||||
struct zmk_behavior_binding *behavior;
|
||||
if (hold_tap->is_hold) {
|
||||
behavior = &hold_tap->config->behaviors->hold;
|
||||
struct device *behavior_device = device_get_binding(behavior->behavior_dev);
|
||||
behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_hold, 0);
|
||||
} else {
|
||||
behavior = &hold_tap->config->behaviors->tap;
|
||||
struct device *behavior_device = device_get_binding(behavior->behavior_dev);
|
||||
behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_tap, 0);
|
||||
}
|
||||
release_captured_events();
|
||||
}
|
||||
|
||||
static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t param_hold, u32_t param_tap)
|
||||
{
|
||||
const struct behavior_hold_tap_config *cfg = dev->config_info;
|
||||
|
||||
if (undecided_hold_tap != NULL) {
|
||||
LOG_DBG("ERROR another hold-tap behavior is undecided.");
|
||||
// if this happens, make sure the behavior events occur AFTER other position events.
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct active_hold_tap *hold_tap = store_hold_tap(position, param_hold, param_tap, 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 0;
|
||||
}
|
||||
|
||||
LOG_DBG("%d new undecided hold_tap", position);
|
||||
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 keypress
|
||||
// don't forget to simulate a timer-event before the event after that time was handled.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_hold_tap_binding_released(struct device *dev, u32_t position, u32_t _, u32_t __)
|
||||
{
|
||||
struct active_hold_tap *hold_tap = find_hold_tap(position);
|
||||
|
||||
if (hold_tap == NULL) {
|
||||
LOG_ERR("ACTIVE_HOLD_TAP_CLEANED_UP_TOO_EARLY");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int work_cancel_result = k_delayed_work_cancel(&hold_tap->work);
|
||||
decide_hold_tap(hold_tap, HT_KEY_UP);
|
||||
|
||||
struct zmk_behavior_binding *behavior;
|
||||
if (hold_tap->is_hold) {
|
||||
behavior = &hold_tap->config->behaviors->hold;
|
||||
struct device *behavior_device = device_get_binding(behavior->behavior_dev);
|
||||
behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_hold, 0);
|
||||
} else {
|
||||
behavior = &hold_tap->config->behaviors->tap;
|
||||
struct device *behavior_device = device_get_binding(behavior->behavior_dev);
|
||||
behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_tap, 0);
|
||||
}
|
||||
|
||||
|
||||
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", position);
|
||||
hold_tap->work_is_cancelled = true;
|
||||
} else {
|
||||
LOG_DBG("%d cleaning up hold-tap", position);
|
||||
clear_hold_tap(hold_tap);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_hold_tap_driver_api = {
|
||||
.binding_pressed = on_hold_tap_binding_pressed,
|
||||
.binding_released = on_hold_tap_binding_released,
|
||||
};
|
||||
|
||||
|
||||
static int position_state_changed_listener(const struct zmk_event_header *eh)
|
||||
{
|
||||
struct position_state_changed *ev = cast_position_state_changed(eh);
|
||||
|
||||
if (undecided_hold_tap == NULL) {
|
||||
LOG_DBG("%d bubble (no undecided hold_tap active)", ev->position);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (undecided_hold_tap->position == ev->position) {
|
||||
if (ev->state) { // keydown
|
||||
LOG_ERR("hold-tap listener should be called before before most other listeners!");
|
||||
return 0;
|
||||
} else { // keyup
|
||||
LOG_DBG("%d bubble undecided hold-tap keyrelease event", undecided_hold_tap->position);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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, ev->state ? "down" : "up");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_DBG("%d capturing %d %s event", undecided_hold_tap->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);
|
||||
return ZMK_EV_EVENT_CAPTURED;
|
||||
}
|
||||
|
||||
static bool is_mod(struct keycode_state_changed *ev)
|
||||
{
|
||||
return ev->usage_page == USAGE_KEYPAD && ev->keycode >= LCTL && ev->keycode <= RGUI;
|
||||
}
|
||||
|
||||
static int keycode_state_changed_listener(const struct zmk_event_header *eh)
|
||||
{
|
||||
// we want to catch layer-up events too... how?
|
||||
struct keycode_state_changed *ev = cast_keycode_state_changed(eh);
|
||||
|
||||
if (undecided_hold_tap == NULL) {
|
||||
// LOG_DBG("0x%02X bubble (no undecided hold_tap active)", ev->keycode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!is_mod(ev)) {
|
||||
// LOG_DBG("0x%02X bubble (not a mod)", ev->keycode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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, ev->state ? "down" : "up");
|
||||
capture_event(eh);
|
||||
return ZMK_EV_EVENT_CAPTURED;
|
||||
}
|
||||
|
||||
|
||||
int behavior_hold_tap_listener(const struct zmk_event_header *eh)
|
||||
{
|
||||
if (is_position_state_changed(eh)) {
|
||||
return position_state_changed_listener(eh);
|
||||
} else if (is_keycode_state_changed(eh)) {
|
||||
return keycode_state_changed_listener(eh);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(behavior_hold_tap, behavior_hold_tap_listener);
|
||||
ZMK_SUBSCRIPTION(behavior_hold_tap, position_state_changed);
|
||||
// this should be modifiers_state_changed, but unfrotunately that's not implemented yet.
|
||||
ZMK_SUBSCRIPTION(behavior_hold_tap, keycode_state_changed);
|
||||
|
||||
void behavior_hold_tap_timer_work_handler(struct k_work *item)
|
||||
{
|
||||
struct active_hold_tap *hold_tap = CONTAINER_OF(item, struct active_hold_tap, work);
|
||||
|
||||
if (hold_tap->work_is_cancelled) {
|
||||
clear_hold_tap(hold_tap);
|
||||
} else {
|
||||
decide_hold_tap(hold_tap, HT_TIMER_EVENT);
|
||||
}
|
||||
}
|
||||
|
||||
static int behavior_hold_tap_init(struct device *dev)
|
||||
{
|
||||
static bool init_first_run = true;
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct behavior_hold_tap_data {};
|
||||
static struct behavior_hold_tap_data behavior_hold_tap_data;
|
||||
|
||||
#define _TRANSFORM_ENTRY(idx, node) \
|
||||
{ \
|
||||
.behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \
|
||||
.param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), (DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \
|
||||
.param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), (DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \
|
||||
},
|
||||
|
||||
#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 = { \
|
||||
.hold = _TRANSFORM_ENTRY(0, n) \
|
||||
.tap = _TRANSFORM_ENTRY(1, n) \
|
||||
}; \
|
||||
static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \
|
||||
.behaviors = &behavior_hold_tap_behaviors_##n, \
|
||||
.tapping_term_ms = &behavior_hold_tap_config_##n##_gettime, \
|
||||
.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, \
|
||||
&behavior_hold_tap_data, \
|
||||
&behavior_hold_tap_config_##n, \
|
||||
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&behavior_hold_tap_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
||||
|
||||
|
||||
#endif
|
|
@ -1,252 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_mod_tap
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
#include <zmk/matrix.h>
|
||||
#include <zmk/endpoints.h>
|
||||
#include <zmk/event-manager.h>
|
||||
#include <zmk/events/keycode-state-changed.h>
|
||||
#include <zmk/events/modifiers-state-changed.h>
|
||||
#include <zmk/hid.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#define ZMK_BHV_MOD_TAP_MAX_HELD 4
|
||||
#define ZMK_BHV_MOD_TAP_MAX_PENDING_KC 4
|
||||
|
||||
struct active_mod_tap_item {
|
||||
u32_t keycode;
|
||||
u8_t mods;
|
||||
bool pending;
|
||||
zmk_mod_flags active_mods;
|
||||
};
|
||||
|
||||
struct captured_keycode_state_change_item {
|
||||
struct keycode_state_changed* event;
|
||||
zmk_mod_flags active_mods;
|
||||
};
|
||||
|
||||
struct behavior_mod_tap_config { };
|
||||
struct behavior_mod_tap_data {
|
||||
struct active_mod_tap_item active_mod_taps[ZMK_BHV_MOD_TAP_MAX_HELD];
|
||||
struct captured_keycode_state_change_item captured_keycode_events[ZMK_BHV_MOD_TAP_MAX_PENDING_KC];
|
||||
};
|
||||
|
||||
bool have_pending_mods(char *label) {
|
||||
struct device *dev = device_get_binding(label);
|
||||
struct behavior_mod_tap_data *data = dev->driver_data;
|
||||
|
||||
for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
|
||||
if (data->active_mod_taps[i].mods) {
|
||||
LOG_DBG("Found pending mods for %d and keycode 0x%02X", data->active_mod_taps[i].mods, data->active_mod_taps[i].keycode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct captured_keycode_state_change_item* find_pending_keycode(struct behavior_mod_tap_data *data, u32_t keycode)
|
||||
{
|
||||
for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; i++) {
|
||||
if (data->captured_keycode_events[i].event == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data->captured_keycode_events[i].event->keycode == keycode) {
|
||||
return &data->captured_keycode_events[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
zmk_mod_flags behavior_mod_tap_active_mods(struct behavior_mod_tap_data *data)
|
||||
{
|
||||
zmk_mod_flags mods = 0;
|
||||
|
||||
for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
|
||||
mods |= data->active_mod_taps[i].mods;
|
||||
}
|
||||
|
||||
return mods;
|
||||
}
|
||||
|
||||
int behavior_mod_tap_capture_keycode_event(struct behavior_mod_tap_data *data, struct keycode_state_changed *ev)
|
||||
{
|
||||
for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; i++) {
|
||||
if (data->captured_keycode_events[i].event != NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data->captured_keycode_events[i].event = ev;
|
||||
data->captured_keycode_events[i].active_mods = behavior_mod_tap_active_mods(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void behavior_mod_tap_update_active_mods_state(struct behavior_mod_tap_data *data, zmk_mod_flags used_flags)
|
||||
{
|
||||
for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
|
||||
if ((data->active_mod_taps[i].mods & used_flags) == data->active_mod_taps[i].mods) {
|
||||
data->active_mod_taps[i].pending = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// How to pass context to subscription?!
|
||||
int behavior_mod_tap_listener(const struct zmk_event_header *eh)
|
||||
{
|
||||
if (is_keycode_state_changed(eh) && have_pending_mods(DT_INST_LABEL(0))) {
|
||||
struct device *dev = device_get_binding(DT_INST_LABEL(0));
|
||||
struct keycode_state_changed *ev = cast_keycode_state_changed(eh);
|
||||
struct behavior_mod_tap_data *data = dev->driver_data;
|
||||
struct captured_keycode_state_change_item* pending_keycode;
|
||||
if (ev->state) {
|
||||
LOG_DBG("Have pending mods, capturing keycode 0x%02X event to ressend later", ev->keycode);
|
||||
behavior_mod_tap_capture_keycode_event(data, ev);
|
||||
return ZMK_EV_EVENT_CAPTURED;
|
||||
} else if ((pending_keycode = find_pending_keycode(data, ev->keycode)) != NULL) {
|
||||
LOG_DBG("Key released, going to activate mods 0x%02X then send pending key press for keycode 0x%02X",
|
||||
pending_keycode->active_mods, pending_keycode->event->keycode);
|
||||
|
||||
zmk_hid_register_mods(pending_keycode->active_mods);
|
||||
behavior_mod_tap_update_active_mods_state(data, pending_keycode->active_mods);
|
||||
|
||||
ZMK_EVENT_RELEASE(pending_keycode->event);
|
||||
k_msleep(10);
|
||||
|
||||
pending_keycode->event = NULL;
|
||||
pending_keycode->active_mods = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(behavior_mod_tap, behavior_mod_tap_listener);
|
||||
ZMK_SUBSCRIPTION(behavior_mod_tap, keycode_state_changed);
|
||||
|
||||
static int behavior_mod_tap_init(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t mods, u32_t keycode)
|
||||
{
|
||||
struct behavior_mod_tap_data *data = dev->driver_data;
|
||||
LOG_DBG("mods: %d, keycode: 0x%02X", mods, keycode);
|
||||
for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
|
||||
if (data->active_mod_taps[i].mods != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
zmk_mod_flags active_mods = behavior_mod_tap_active_mods(data);
|
||||
|
||||
data->active_mod_taps[i].active_mods = active_mods;
|
||||
data->active_mod_taps[i].mods = mods;
|
||||
data->active_mod_taps[i].keycode = keycode;
|
||||
data->active_mod_taps[i].pending = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_WRN("Failed to record mod-tap activation, at maximum concurrent mod-tap activations");
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t mods, u32_t keycode)
|
||||
{
|
||||
struct behavior_mod_tap_data *data = dev->driver_data;
|
||||
LOG_DBG("mods: %d, keycode: %d", mods, keycode);
|
||||
|
||||
for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
|
||||
struct active_mod_tap_item *item = &data->active_mod_taps[i];
|
||||
if (item->mods == mods && item->keycode == keycode) {
|
||||
if (item->pending) {
|
||||
LOG_DBG("Sending un-triggered mod-tap for keycode: 0x%02X", keycode);
|
||||
|
||||
if (item->active_mods) {
|
||||
LOG_DBG("Registering recorded active mods captured when mod-tap initially activated: 0x%02X", item->active_mods);
|
||||
behavior_mod_tap_update_active_mods_state(data, item->active_mods);
|
||||
zmk_hid_register_mods(item->active_mods);
|
||||
}
|
||||
|
||||
struct keycode_state_changed *key_press = create_keycode_state_changed(USAGE_KEYPAD, item->keycode, true);
|
||||
ZMK_EVENT_RAISE_AFTER(key_press, behavior_mod_tap);
|
||||
k_msleep(10);
|
||||
|
||||
for (int j = 0; j < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; j++) {
|
||||
if (data->captured_keycode_events[j].event == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct keycode_state_changed *ev = data->captured_keycode_events[j].event;
|
||||
data->captured_keycode_events[j].event = NULL;
|
||||
data->captured_keycode_events[j].active_mods = 0;
|
||||
LOG_DBG("Re-sending latched key press for usage page 0x%02X keycode 0x%02X state %s", ev->usage_page, ev->keycode, (ev->state ? "pressed" : "released"));
|
||||
ZMK_EVENT_RELEASE(ev);
|
||||
k_msleep(10);
|
||||
}
|
||||
|
||||
struct keycode_state_changed *key_release = create_keycode_state_changed(USAGE_KEYPAD, keycode, false);
|
||||
LOG_DBG("Sending un-triggered mod-tap release for keycode: 0x%02X", keycode);
|
||||
ZMK_EVENT_RAISE_AFTER(key_release, behavior_mod_tap);
|
||||
k_msleep(10);
|
||||
|
||||
if (item->active_mods) {
|
||||
LOG_DBG("Unregistering recorded active mods captured when mod-tap initially activated: 0x%02X", item->active_mods);
|
||||
zmk_hid_unregister_mods(item->active_mods);
|
||||
zmk_endpoints_send_report(USAGE_KEYPAD);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
LOG_DBG("Releasing triggered mods: %d", mods);
|
||||
zmk_hid_unregister_mods(mods);
|
||||
zmk_endpoints_send_report(USAGE_KEYPAD);
|
||||
}
|
||||
|
||||
item->mods = 0;
|
||||
item->keycode = 0;
|
||||
item->active_mods = 0;
|
||||
|
||||
LOG_DBG("Removing mods %d from active_mods for other held mod-taps", mods);
|
||||
for (int j = 0; j < ZMK_BHV_MOD_TAP_MAX_HELD; j++) {
|
||||
if (data->active_mod_taps[j].active_mods & mods) {
|
||||
LOG_DBG("Removing 0x%02X from active mod tap mods 0x%02X keycode 0x%02X", mods, data->active_mod_taps[j].mods, data->active_mod_taps[j].keycode);
|
||||
data->active_mod_taps[j].active_mods &= ~mods;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_mod_tap_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed,
|
||||
.binding_released = on_keymap_binding_released,
|
||||
};
|
||||
|
||||
static const struct behavior_mod_tap_config behavior_mod_tap_config = {};
|
||||
|
||||
static struct behavior_mod_tap_data behavior_mod_tap_data;
|
||||
|
||||
DEVICE_AND_API_INIT(behavior_mod_tap, DT_INST_LABEL(0), behavior_mod_tap_init,
|
||||
&behavior_mod_tap_data,
|
||||
&behavior_mod_tap_config,
|
||||
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||||
&behavior_mod_tap_driver_api);
|
|
@ -71,6 +71,22 @@ int zmk_event_manager_raise_after(struct zmk_event_header *event, const struct z
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
int zmk_event_manager_raise_at(struct zmk_event_header *event, const struct zmk_listener *listener)
|
||||
{
|
||||
u8_t len = __event_subscriptions_end - __event_subscriptions_start;
|
||||
for (int i = 0; i < len; i++) {
|
||||
struct zmk_event_subscription *ev_sub = __event_subscriptions_start + i;
|
||||
|
||||
if (ev_sub->event_type == event->event && ev_sub->listener == listener) {
|
||||
return zmk_event_manager_handle_from(event, i);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_WRN("Unable to find where to raise this event");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int zmk_event_manager_release(struct zmk_event_header *event)
|
||||
{
|
||||
return zmk_event_manager_handle_from(event, event->last_listener_index + 1);
|
||||
|
|
1
app/tests/hold-tap/README.md
Normal file
1
app/tests/hold-tap/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
Refer to the pdf/open document "zmk-modtap-proposal.{pdf,odt}" in this directory for a visual representation of the numbered tests for hold-tap.
|
4
app/tests/hold-tap/balanced/1-dn-up/events.patterns
Normal file
4
app/tests/hold-tap/balanced/1-dn-up/events.patterns
Normal file
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (balanced event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
11
app/tests/hold-tap/balanced/1-dn-up/native_posix.keymap
Normal file
11
app/tests/hold-tap/balanced/1-dn-up/native_posix.keymap
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (balanced event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,11 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,500)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0xe4
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (balanced event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_released: usage_page 0x07 keycode 0xe4
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,13 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,1,10) /*ctrl*/
|
||||
ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,1,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0xe4
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (balanced event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_released: usage_page 0x07 keycode 0xe4
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,1,10) /*ctrl*/
|
||||
ZMK_MOCK_PRESS(0,0,50) /*mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,1,300)
|
||||
/*timer*/
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
ht_decide: 0 decided tap (balanced event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,13 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,0,10) /*d*/
|
||||
ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
ht_decide: 0 decided hold (balanced event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,13 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,0,10) /* d */
|
||||
ZMK_MOCK_PRESS(0,0,100) /* mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,0,400)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
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 tap (balanced event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x0d
|
||||
kp_released: usage_page 0x07 keycode 0x0d
|
||||
ht_binding_released: 1 cleaning up hold-tap
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,200)
|
||||
ZMK_MOCK_PRESS(0,1,200)
|
||||
/* timer fires */
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (balanced event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,200)
|
||||
ZMK_MOCK_PRESS(1,0,200)
|
||||
/* timer fires */
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (balanced event 2)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,100)
|
||||
ZMK_MOCK_PRESS(1,0,100)
|
||||
ZMK_MOCK_RELEASE(1,0,200)
|
||||
/* timer fires */
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (balanced event 2)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
/* timer */
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (balanced event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,100)
|
||||
ZMK_MOCK_PRESS(1,0,100)
|
||||
ZMK_MOCK_RELEASE(0,0,200)
|
||||
/* timer fires */
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
>;
|
||||
};
|
27
app/tests/hold-tap/balanced/behavior_keymap.dtsi
Normal file
27
app/tests/hold-tap/balanced/behavior_keymap.dtsi
Normal file
|
@ -0,0 +1,27 @@
|
|||
#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
|
||||
&kp D &kp RCTL>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (hold-preferred event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,11 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (hold-preferred event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,11 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,500)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0xe4
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (hold-preferred event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_released: usage_page 0x07 keycode 0xe4
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,13 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,1,10) /*ctrl*/
|
||||
ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,1,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0xe4
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (hold-preferred event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_released: usage_page 0x07 keycode 0xe4
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,1,10) /*ctrl*/
|
||||
ZMK_MOCK_PRESS(0,0,50) /*mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,1,300)
|
||||
/*timer*/
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
ht_decide: 0 decided tap (hold-preferred event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,13 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,0,10) /*d*/
|
||||
ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
ht_decide: 0 decided hold (hold-preferred event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,13 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,0,10) /* d */
|
||||
ZMK_MOCK_PRESS(0,0,100) /* mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,0,400)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (hold-preferred event 1)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_pressed: 1 new undecided hold_tap
|
||||
ht_decide: 1 decided tap (hold-preferred event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x0d
|
||||
kp_released: usage_page 0x07 keycode 0x0d
|
||||
ht_binding_released: 1 cleaning up hold-tap
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,200)
|
||||
ZMK_MOCK_PRESS(0,1,200)
|
||||
/* timer fires */
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (hold-preferred event 1)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,200)
|
||||
ZMK_MOCK_PRESS(1,0,200)
|
||||
/* timer fires */
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (hold-preferred event 1)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,100)
|
||||
ZMK_MOCK_PRESS(1,0,100)
|
||||
ZMK_MOCK_RELEASE(1,0,200)
|
||||
/* timer fires */
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (hold-preferred event 1)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
/* timer */
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (hold-preferred event 1)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,100)
|
||||
ZMK_MOCK_PRESS(1,0,100)
|
||||
ZMK_MOCK_RELEASE(0,0,200)
|
||||
/* timer fires */
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
>;
|
||||
};
|
29
app/tests/hold-tap/hold-preferred/behavior_keymap.dtsi
Normal file
29
app/tests/hold-tap/hold-preferred/behavior_keymap.dtsi
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
|
||||
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
ht_hold: behavior_hold_hold_tap {
|
||||
compatible = "zmk,behavior-hold-tap";
|
||||
label = "hold_hold_tap";
|
||||
#binding-cells = <2>;
|
||||
flavor = "hold-preferred";
|
||||
tapping_term_ms = <300>;
|
||||
bindings = <&kp>, <&kp>;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&ht_hold LSFT F &ht_hold LCTL J
|
||||
&kp D &kp RCTL>;
|
||||
};
|
||||
};
|
||||
};
|
4
app/tests/hold-tap/tap-preferred/1-dn-up/events.patterns
Normal file
4
app/tests/hold-tap/tap-preferred/1-dn-up/events.patterns
Normal file
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-preferred event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
11
app/tests/hold-tap/tap-preferred/1-dn-up/native_posix.keymap
Normal file
11
app/tests/hold-tap/tap-preferred/1-dn-up/native_posix.keymap
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (tap-preferred event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,11 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,500)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0xe4
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-preferred event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_released: usage_page 0x07 keycode 0xe4
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,13 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,1,10) /*ctrl*/
|
||||
ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,1,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0xe4
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (tap-preferred event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_released: usage_page 0x07 keycode 0xe4
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,1,10) /*ctrl*/
|
||||
ZMK_MOCK_PRESS(0,0,50) /*mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,1,300)
|
||||
/*timer*/
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
ht_decide: 0 decided tap (tap-preferred event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09
|
||||
kp_released: usage_page 0x07 keycode 0x09
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,13 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,0,10) /*d*/
|
||||
ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0x07
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
kp_released: usage_page 0x07 keycode 0x07
|
||||
ht_decide: 0 decided hold (tap-preferred event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,13 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,0,10) /* d */
|
||||
ZMK_MOCK_PRESS(0,0,100) /* mt f-shift */
|
||||
ZMK_MOCK_RELEASE(1,0,400)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold (tap-preferred event 3)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_pressed: 1 new undecided hold_tap
|
||||
ht_decide: 1 decided tap (tap-preferred event 0)
|
||||
kp_pressed: usage_page 0x07 keycode 0x0d
|
||||
kp_released: usage_page 0x07 keycode 0x0d
|
||||
ht_binding_released: 1 cleaning up hold-tap
|
||||
kp_released: usage_page 0x07 keycode 0xe1
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,14 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan-mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,200)
|
||||
ZMK_MOCK_PRESS(0,1,200)
|
||||
/* timer fires */
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue