|
|
@ -29,7 +29,6 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); |
|
|
|
// increase if you have keyboard with more keys.
|
|
|
|
// increase if you have keyboard with more keys.
|
|
|
|
#define ZMK_BHV_HOLD_TAP_POSITION_NOT_USED 9999 |
|
|
|
#define ZMK_BHV_HOLD_TAP_POSITION_NOT_USED 9999 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum flavor { |
|
|
|
enum flavor { |
|
|
|
ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED = 0, |
|
|
|
ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED = 0, |
|
|
|
ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED = 1, |
|
|
|
ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED = 1, |
|
|
@ -71,8 +70,7 @@ 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.
|
|
|
|
// 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] = {}; |
|
|
|
const struct zmk_event_header *captured_events[ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS] = {}; |
|
|
|
|
|
|
|
|
|
|
|
static int capture_event(const struct zmk_event_header *event) |
|
|
|
static int capture_event(const struct zmk_event_header *event) { |
|
|
|
{ |
|
|
|
|
|
|
|
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { |
|
|
|
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { |
|
|
|
if (captured_events[i] == NULL) { |
|
|
|
if (captured_events[i] == NULL) { |
|
|
|
captured_events[i] = event; |
|
|
|
captured_events[i] = event; |
|
|
@ -82,8 +80,7 @@ static int capture_event(const struct zmk_event_header *event) |
|
|
|
return -ENOMEM; |
|
|
|
return -ENOMEM; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct position_state_changed *find_captured_keydown_event(u32_t position) |
|
|
|
static struct position_state_changed *find_captured_keydown_event(u32_t position) { |
|
|
|
{ |
|
|
|
|
|
|
|
struct position_state_changed *last_match = NULL; |
|
|
|
struct position_state_changed *last_match = NULL; |
|
|
|
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { |
|
|
|
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { |
|
|
|
const struct zmk_event_header *eh = captured_events[i]; |
|
|
|
const struct zmk_event_header *eh = captured_events[i]; |
|
|
@ -103,8 +100,7 @@ static struct position_state_changed *find_captured_keydown_event(u32_t position |
|
|
|
|
|
|
|
|
|
|
|
const struct zmk_listener zmk_listener_behavior_hold_tap; |
|
|
|
const struct zmk_listener zmk_listener_behavior_hold_tap; |
|
|
|
|
|
|
|
|
|
|
|
static void release_captured_events() |
|
|
|
static void release_captured_events() { |
|
|
|
{ |
|
|
|
|
|
|
|
if (undecided_hold_tap != NULL) { |
|
|
|
if (undecided_hold_tap != NULL) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
@ -125,8 +121,8 @@ static void release_captured_events() |
|
|
|
// [null, k1_down, k1_up, mt2_up, null, ...]
|
|
|
|
// [null, k1_down, k1_up, mt2_up, null, ...]
|
|
|
|
// ^
|
|
|
|
// ^
|
|
|
|
// k1_down is captured by the mt2 mod-tap
|
|
|
|
// 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
|
|
|
|
// !note that searches for find_captured_keydown_event by the mt2 behavior will stop at the
|
|
|
|
// [mt1_down, null, k1_up, mt2_up, null, ...]
|
|
|
|
// first null encountered [mt1_down, null, k1_up, mt2_up, null, ...]
|
|
|
|
// ^
|
|
|
|
// ^
|
|
|
|
// k1_up event is captured by the new hold-tap:
|
|
|
|
// k1_up event is captured by the new hold-tap:
|
|
|
|
// [k1_down, k1_up, null, mt2_up, null, ...]
|
|
|
|
// [k1_down, k1_up, null, mt2_up, null, ...]
|
|
|
@ -144,18 +140,21 @@ static void release_captured_events() |
|
|
|
k_msleep(10); |
|
|
|
k_msleep(10); |
|
|
|
} |
|
|
|
} |
|
|
|
if (is_position_state_changed(captured_event)) { |
|
|
|
if (is_position_state_changed(captured_event)) { |
|
|
|
struct position_state_changed *position_event = cast_position_state_changed(captured_event); |
|
|
|
struct position_state_changed *position_event = |
|
|
|
LOG_DBG("Releasing key position event for position %d %s", position_event->position, (position_event->state ? "pressed" : "released")); |
|
|
|
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 { |
|
|
|
} else { |
|
|
|
struct keycode_state_changed *modifier_event = cast_keycode_state_changed(captured_event); |
|
|
|
struct keycode_state_changed *modifier_event = |
|
|
|
LOG_DBG("Releasing mods changed event 0x%02X %s", modifier_event->keycode, (modifier_event->state ? "pressed" : "released")); |
|
|
|
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); |
|
|
|
ZMK_EVENT_RAISE_AT(captured_event, behavior_hold_tap); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct active_hold_tap *find_hold_tap(u32_t position) |
|
|
|
static struct active_hold_tap *find_hold_tap(u32_t position) { |
|
|
|
{ |
|
|
|
|
|
|
|
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { |
|
|
|
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { |
|
|
|
if (active_hold_taps[i].position == position) { |
|
|
|
if (active_hold_taps[i].position == position) { |
|
|
|
return &active_hold_taps[i]; |
|
|
|
return &active_hold_taps[i]; |
|
|
@ -164,8 +163,8 @@ static struct active_hold_tap *find_hold_tap(u32_t position) |
|
|
|
return NULL; |
|
|
|
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) |
|
|
|
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++) { |
|
|
|
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) { |
|
|
|
continue; |
|
|
|
continue; |
|
|
@ -181,8 +180,7 @@ static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold, |
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void clear_hold_tap(struct active_hold_tap *hold_tap) |
|
|
|
static void clear_hold_tap(struct active_hold_tap *hold_tap) { |
|
|
|
{ |
|
|
|
|
|
|
|
hold_tap->position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; |
|
|
|
hold_tap->position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; |
|
|
|
hold_tap->is_decided = false; |
|
|
|
hold_tap->is_decided = false; |
|
|
|
hold_tap->is_hold = false; |
|
|
|
hold_tap->is_hold = false; |
|
|
@ -196,8 +194,7 @@ enum decision_moment { |
|
|
|
HT_TIMER_EVENT = 3, |
|
|
|
HT_TIMER_EVENT = 3, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_moment event) |
|
|
|
static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_moment event) { |
|
|
|
{ |
|
|
|
|
|
|
|
switch (event) { |
|
|
|
switch (event) { |
|
|
|
case HT_KEY_UP: |
|
|
|
case HT_KEY_UP: |
|
|
|
hold_tap->is_hold = 0; |
|
|
|
hold_tap->is_hold = 0; |
|
|
@ -208,12 +205,12 @@ static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_mome |
|
|
|
hold_tap->is_hold = 1; |
|
|
|
hold_tap->is_hold = 1; |
|
|
|
hold_tap->is_decided = true; |
|
|
|
hold_tap->is_decided = true; |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: return; |
|
|
|
default: |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) |
|
|
|
static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) { |
|
|
|
{ |
|
|
|
|
|
|
|
switch (event) { |
|
|
|
switch (event) { |
|
|
|
case HT_KEY_UP: |
|
|
|
case HT_KEY_UP: |
|
|
|
hold_tap->is_hold = 0; |
|
|
|
hold_tap->is_hold = 0; |
|
|
@ -223,12 +220,12 @@ static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision |
|
|
|
hold_tap->is_hold = 1; |
|
|
|
hold_tap->is_hold = 1; |
|
|
|
hold_tap->is_decided = true; |
|
|
|
hold_tap->is_decided = true; |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: return; |
|
|
|
default: |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) |
|
|
|
static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) { |
|
|
|
{ |
|
|
|
|
|
|
|
switch (event) { |
|
|
|
switch (event) { |
|
|
|
case HT_KEY_UP: |
|
|
|
case HT_KEY_UP: |
|
|
|
hold_tap->is_hold = 0; |
|
|
|
hold_tap->is_hold = 0; |
|
|
@ -239,7 +236,8 @@ static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decisio |
|
|
|
hold_tap->is_hold = 1; |
|
|
|
hold_tap->is_hold = 1; |
|
|
|
hold_tap->is_decided = true; |
|
|
|
hold_tap->is_decided = true; |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: return; |
|
|
|
default: |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -255,8 +253,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) { |
|
|
|
{ |
|
|
|
|
|
|
|
if (hold_tap->is_decided) { |
|
|
|
if (hold_tap->is_decided) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
@ -279,28 +276,27 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LOG_DBG("%d decided %s (%s event %d)",
|
|
|
|
LOG_DBG("%d decided %s (%s event %d)", hold_tap->position, hold_tap->is_hold ? "hold" : "tap", |
|
|
|
hold_tap->position,
|
|
|
|
flavor_str(hold_tap->config->flavor), event); |
|
|
|
hold_tap->is_hold ? "hold" : "tap",
|
|
|
|
|
|
|
|
flavor_str(hold_tap->config->flavor), |
|
|
|
|
|
|
|
event); |
|
|
|
|
|
|
|
undecided_hold_tap = NULL; |
|
|
|
undecided_hold_tap = NULL; |
|
|
|
|
|
|
|
|
|
|
|
struct zmk_behavior_binding *behavior; |
|
|
|
struct zmk_behavior_binding *behavior; |
|
|
|
if (hold_tap->is_hold) { |
|
|
|
if (hold_tap->is_hold) { |
|
|
|
behavior = &hold_tap->config->behaviors->hold; |
|
|
|
behavior = &hold_tap->config->behaviors->hold; |
|
|
|
struct device *behavior_device = device_get_binding(behavior->behavior_dev); |
|
|
|
struct device *behavior_device = device_get_binding(behavior->behavior_dev); |
|
|
|
behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_hold, 0); |
|
|
|
behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_hold, |
|
|
|
|
|
|
|
0); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
behavior = &hold_tap->config->behaviors->tap; |
|
|
|
behavior = &hold_tap->config->behaviors->tap; |
|
|
|
struct device *behavior_device = device_get_binding(behavior->behavior_dev); |
|
|
|
struct device *behavior_device = device_get_binding(behavior->behavior_dev); |
|
|
|
behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_tap, 0); |
|
|
|
behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_tap, |
|
|
|
|
|
|
|
0); |
|
|
|
} |
|
|
|
} |
|
|
|
release_captured_events(); |
|
|
|
release_captured_events(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t param_hold, u32_t param_tap) |
|
|
|
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; |
|
|
|
const struct behavior_hold_tap_config *cfg = dev->config_info; |
|
|
|
|
|
|
|
|
|
|
|
if (undecided_hold_tap != NULL) { |
|
|
|
if (undecided_hold_tap != NULL) { |
|
|
@ -311,7 +307,8 @@ static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t |
|
|
|
|
|
|
|
|
|
|
|
struct active_hold_tap *hold_tap = store_hold_tap(position, param_hold, param_tap, cfg); |
|
|
|
struct active_hold_tap *hold_tap = store_hold_tap(position, param_hold, param_tap, 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?", ZMK_BHV_HOLD_TAP_MAX_HELD); |
|
|
|
LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?", |
|
|
|
|
|
|
|
ZMK_BHV_HOLD_TAP_MAX_HELD); |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -319,14 +316,13 @@ static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t |
|
|
|
undecided_hold_tap = hold_tap; |
|
|
|
undecided_hold_tap = hold_tap; |
|
|
|
k_delayed_work_submit(&hold_tap->work, cfg->tapping_term_ms()); |
|
|
|
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
|
|
|
|
// todo: once we get timing info for keypresses, start the timer relative to the original
|
|
|
|
// don't forget to simulate a timer-event before the event after that time was handled.
|
|
|
|
// keypress don't forget to simulate a timer-event before the event after that time was handled.
|
|
|
|
|
|
|
|
|
|
|
|
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 device *dev, u32_t position, u32_t _, u32_t __) { |
|
|
|
{ |
|
|
|
|
|
|
|
struct active_hold_tap *hold_tap = find_hold_tap(position); |
|
|
|
struct active_hold_tap *hold_tap = find_hold_tap(position); |
|
|
|
|
|
|
|
|
|
|
|
if (hold_tap == NULL) { |
|
|
|
if (hold_tap == NULL) { |
|
|
@ -341,14 +337,15 @@ static int on_hold_tap_binding_released(struct device *dev, u32_t position, u32_ |
|
|
|
if (hold_tap->is_hold) { |
|
|
|
if (hold_tap->is_hold) { |
|
|
|
behavior = &hold_tap->config->behaviors->hold; |
|
|
|
behavior = &hold_tap->config->behaviors->hold; |
|
|
|
struct device *behavior_device = device_get_binding(behavior->behavior_dev); |
|
|
|
struct device *behavior_device = device_get_binding(behavior->behavior_dev); |
|
|
|
behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_hold, 0); |
|
|
|
behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_hold, |
|
|
|
|
|
|
|
0); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
behavior = &hold_tap->config->behaviors->tap; |
|
|
|
behavior = &hold_tap->config->behaviors->tap; |
|
|
|
struct device *behavior_device = device_get_binding(behavior->behavior_dev); |
|
|
|
struct device *behavior_device = device_get_binding(behavior->behavior_dev); |
|
|
|
behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_tap, 0); |
|
|
|
behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_tap, |
|
|
|
|
|
|
|
0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
@ -367,9 +364,7 @@ static const struct behavior_driver_api behavior_hold_tap_driver_api = { |
|
|
|
.binding_released = on_hold_tap_binding_released, |
|
|
|
.binding_released = on_hold_tap_binding_released, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int position_state_changed_listener(const struct zmk_event_header *eh) { |
|
|
|
static int position_state_changed_listener(const struct zmk_event_header *eh) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct position_state_changed *ev = cast_position_state_changed(eh); |
|
|
|
struct position_state_changed *ev = cast_position_state_changed(eh); |
|
|
|
|
|
|
|
|
|
|
|
if (undecided_hold_tap == NULL) { |
|
|
|
if (undecided_hold_tap == NULL) { |
|
|
@ -390,23 +385,23 @@ static int position_state_changed_listener(const struct zmk_event_header *eh) |
|
|
|
if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { |
|
|
|
if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { |
|
|
|
// no keydown event has been captured, let it bubble.
|
|
|
|
// no keydown event has been captured, let it bubble.
|
|
|
|
// we'll catch modifiers later in modifier_state_changed_listener
|
|
|
|
// we'll catch modifiers later in modifier_state_changed_listener
|
|
|
|
LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->position, ev->position, ev->state ? "down" : "up"); |
|
|
|
LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->position, ev->position, |
|
|
|
|
|
|
|
ev->state ? "down" : "up"); |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LOG_DBG("%d capturing %d %s event", undecided_hold_tap->position, ev->position, ev->state ? "down" : "up"); |
|
|
|
LOG_DBG("%d capturing %d %s event", undecided_hold_tap->position, ev->position, |
|
|
|
|
|
|
|
ev->state ? "down" : "up"); |
|
|
|
capture_event(eh); |
|
|
|
capture_event(eh); |
|
|
|
decide_hold_tap(undecided_hold_tap, ev->state ? HT_OTHER_KEY_DOWN : HT_OTHER_KEY_UP); |
|
|
|
decide_hold_tap(undecided_hold_tap, ev->state ? HT_OTHER_KEY_DOWN : HT_OTHER_KEY_UP); |
|
|
|
return ZMK_EV_EVENT_CAPTURED; |
|
|
|
return ZMK_EV_EVENT_CAPTURED; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool is_mod(struct keycode_state_changed *ev) |
|
|
|
static bool is_mod(struct keycode_state_changed *ev) { |
|
|
|
{ |
|
|
|
|
|
|
|
return ev->usage_page == USAGE_KEYPAD && ev->keycode >= LCTL && ev->keycode <= RGUI; |
|
|
|
return ev->usage_page == USAGE_KEYPAD && ev->keycode >= LCTL && ev->keycode <= RGUI; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int keycode_state_changed_listener(const struct zmk_event_header *eh) |
|
|
|
static int keycode_state_changed_listener(const struct zmk_event_header *eh) { |
|
|
|
{ |
|
|
|
|
|
|
|
// we want to catch layer-up events too... how?
|
|
|
|
// we want to catch layer-up events too... how?
|
|
|
|
struct keycode_state_changed *ev = cast_keycode_state_changed(eh); |
|
|
|
struct keycode_state_changed *ev = cast_keycode_state_changed(eh); |
|
|
|
|
|
|
|
|
|
|
@ -422,14 +417,13 @@ static int keycode_state_changed_listener(const struct zmk_event_header *eh) |
|
|
|
|
|
|
|
|
|
|
|
// only key-up events will bubble through position_state_changed_listener
|
|
|
|
// only key-up events will bubble through position_state_changed_listener
|
|
|
|
// if a undecided_hold_tap is active.
|
|
|
|
// if a undecided_hold_tap is active.
|
|
|
|
LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->position, ev->keycode, ev->state ? "down" : "up"); |
|
|
|
LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->position, ev->keycode, |
|
|
|
|
|
|
|
ev->state ? "down" : "up"); |
|
|
|
capture_event(eh); |
|
|
|
capture_event(eh); |
|
|
|
return ZMK_EV_EVENT_CAPTURED; |
|
|
|
return ZMK_EV_EVENT_CAPTURED; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int behavior_hold_tap_listener(const struct zmk_event_header *eh) { |
|
|
|
int behavior_hold_tap_listener(const struct zmk_event_header *eh) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (is_position_state_changed(eh)) { |
|
|
|
if (is_position_state_changed(eh)) { |
|
|
|
return position_state_changed_listener(eh); |
|
|
|
return position_state_changed_listener(eh); |
|
|
|
} else if (is_keycode_state_changed(eh)) { |
|
|
|
} else if (is_keycode_state_changed(eh)) { |
|
|
@ -443,8 +437,7 @@ ZMK_SUBSCRIPTION(behavior_hold_tap, position_state_changed); |
|
|
|
// this should be modifiers_state_changed, but unfrotunately that's not implemented yet.
|
|
|
|
// this should be modifiers_state_changed, but unfrotunately that's not implemented yet.
|
|
|
|
ZMK_SUBSCRIPTION(behavior_hold_tap, keycode_state_changed); |
|
|
|
ZMK_SUBSCRIPTION(behavior_hold_tap, keycode_state_changed); |
|
|
|
|
|
|
|
|
|
|
|
void behavior_hold_tap_timer_work_handler(struct k_work *item) |
|
|
|
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); |
|
|
|
struct active_hold_tap *hold_tap = CONTAINER_OF(item, struct active_hold_tap, work); |
|
|
|
|
|
|
|
|
|
|
|
if (hold_tap->work_is_cancelled) { |
|
|
|
if (hold_tap->work_is_cancelled) { |
|
|
@ -454,8 +447,7 @@ void behavior_hold_tap_timer_work_handler(struct k_work *item) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int behavior_hold_tap_init(struct device *dev) |
|
|
|
static int behavior_hold_tap_init(struct device *dev) { |
|
|
|
{ |
|
|
|
|
|
|
|
static bool init_first_run = true; |
|
|
|
static bool init_first_run = true; |
|
|
|
|
|
|
|
|
|
|
|
if (init_first_run) { |
|
|
|
if (init_first_run) { |
|
|
@ -474,29 +466,27 @@ static struct behavior_hold_tap_data behavior_hold_tap_data; |
|
|
|
#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)), \
|
|
|
|
.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))), \
|
|
|
|
.param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), \
|
|
|
|
.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))), \
|
|
|
|
(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) \ |
|
|
|
#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 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) \
|
|
|
|
.hold = _TRANSFORM_ENTRY(0, n).tap = _TRANSFORM_ENTRY(1, 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 = &behavior_hold_tap_config_##n##_gettime, \
|
|
|
|
.flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \
|
|
|
|
.flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \
|
|
|
|
}; \
|
|
|
|
}; \
|
|
|
|
DEVICE_AND_API_INIT( \
|
|
|
|
DEVICE_AND_API_INIT(behavior_hold_tap_##n, DT_INST_LABEL(n), behavior_hold_tap_init, \
|
|
|
|
behavior_hold_tap_##n, DT_INST_LABEL(n), behavior_hold_tap_init, \
|
|
|
|
&behavior_hold_tap_data, &behavior_hold_tap_config_##n, APPLICATION, \
|
|
|
|
&behavior_hold_tap_data, \
|
|
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_hold_tap_driver_api); |
|
|
|
&behavior_hold_tap_config_##n, \
|
|
|
|
|
|
|
|
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
|
|
|
|
|
|
|
&behavior_hold_tap_driver_api); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(KP_INST) |
|
|
|
DT_INST_FOREACH_STATUS_OKAY(KP_INST) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
#endif |