summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorjmding8 <44815547+jmding8@users.noreply.github.com>2021-11-01 09:37:20 -0700
committerGitHub <noreply@github.com>2021-11-01 12:37:20 -0400
commit19ee7849f80e18d8f29ac47ffeee3bb223c35a80 (patch)
treea081670ab0db1a77cf32f7881c180d6f0d4b6738 /app
parentf946dc68931a712bae1c2be0ed1581815ccc8767 (diff)
feat(behaviors) Required keys for tap-hold behaviors
* Add optional `hold-trigger-key-positions` hold-tap configuration * Leverage configuration for decision making around when to trigger hold decision in hold-taps. * Add docs for new configuration. * Tests for the new config/decision logic.
Diffstat (limited to 'app')
-rw-r--r--app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml4
-rw-r--r--app/src/behaviors/behavior_hold_tap.c54
-rw-r--r--app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/events.patterns4
-rw-r--r--app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/keycode_events.snapshot5
-rw-r--r--app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/native_posix.keymap11
-rw-r--r--app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns4
-rw-r--r--app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot7
-rw-r--r--app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap14
-rw-r--r--app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns4
-rw-r--r--app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot7
-rw-r--r--app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap14
-rw-r--r--app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi29
-rw-r--r--app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns4
-rw-r--r--app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot9
-rw-r--r--app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap16
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/events.patterns4
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot5
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/native_posix.keymap11
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns4
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot7
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap14
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns4
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot7
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap14
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi29
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns4
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot9
-rw-r--r--app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap16
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/events.patterns4
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot5
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/native_posix.keymap11
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns4
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot7
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap14
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns4
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot7
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap14
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi29
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns4
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot9
-rw-r--r--app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap16
41 files changed, 442 insertions, 0 deletions
diff --git a/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml
index f46b36a..9d489e8 100644
--- a/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml
+++ b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml
@@ -30,3 +30,7 @@ properties:
- "tap-preferred"
retro-tap:
type: boolean
+ hold-trigger-key-positions:
+ type: array
+ required: false
+ default: []
diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c
index 02ca5e3..a5c4e90 100644
--- a/app/src/behaviors/behavior_hold_tap.c
+++ b/app/src/behaviors/behavior_hold_tap.c
@@ -58,6 +58,8 @@ struct behavior_hold_tap_config {
int quick_tap_ms;
enum flavor flavor;
bool retro_tap;
+ int32_t hold_trigger_key_positions_len;
+ int32_t hold_trigger_key_positions[];
};
// this data is specific for each hold-tap
@@ -70,6 +72,9 @@ struct active_hold_tap {
const struct behavior_hold_tap_config *config;
struct k_delayed_work work;
bool work_is_cancelled;
+
+ // initialized to -1, which is to be interpreted as "no other key has been pressed yet"
+ int32_t position_of_first_other_key_pressed;
};
// The undecided hold tap is the hold tap that needs to be decided before
@@ -206,6 +211,7 @@ static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_
active_hold_taps[i].param_hold = param_hold;
active_hold_taps[i].param_tap = param_tap;
active_hold_taps[i].timestamp = timestamp;
+ active_hold_taps[i].position_of_first_other_key_pressed = -1;
return &active_hold_taps[i];
}
return NULL;
@@ -359,6 +365,39 @@ static int release_binding(struct active_hold_tap *hold_tap) {
return behavior_keymap_binding_released(&binding, event);
}
+static bool is_first_other_key_pressed_trigger_key(struct active_hold_tap *hold_tap) {
+ for (int i = 0; i < hold_tap->config->hold_trigger_key_positions_len; i++) {
+ if (hold_tap->config->hold_trigger_key_positions[i] ==
+ hold_tap->position_of_first_other_key_pressed) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Force a tap decision if the positional conditions for a hold decision are not met.
+static void decide_positional_hold(struct active_hold_tap *hold_tap) {
+ // Only force a tap decision if the positional hold/tap feature is enabled.
+ if (!(hold_tap->config->hold_trigger_key_positions_len > 0)) {
+ return;
+ }
+
+ // Only force a tap decision if another key was pressed after
+ // the hold/tap key.
+ if (hold_tap->position_of_first_other_key_pressed == -1) {
+ return;
+ }
+
+ // Only force a tap decision if the first other key to be pressed
+ // (after the hold/tap key) is not one of the trigger keys.
+ if (is_first_other_key_pressed_trigger_key(hold_tap)) {
+ return;
+ }
+
+ // Since the positional key conditions have failed, force a TAP decision.
+ hold_tap->status = STATUS_TAP;
+}
+
static void decide_hold_tap(struct active_hold_tap *hold_tap,
enum decision_moment decision_moment) {
if (hold_tap->status != STATUS_UNDECIDED) {
@@ -370,6 +409,7 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap,
return;
}
+ // If the hold-tap behavior is still undecided, attempt to decide it.
switch (hold_tap->config->flavor) {
case FLAVOR_HOLD_PREFERRED:
decide_hold_preferred(hold_tap, decision_moment);
@@ -383,6 +423,10 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap,
return;
}
+ decide_positional_hold(hold_tap);
+
+ // Since the hold-tap has been decided, clean up undecided_hold_tap and
+ // execute the decided behavior.
LOG_DBG("%d decided %s (%s decision moment %s)", hold_tap->position,
status_str(hold_tap->status), flavor_str(hold_tap->config->flavor),
decision_moment_str(decision_moment));
@@ -501,6 +545,14 @@ static int position_state_changed_listener(const zmk_event_t *eh) {
return ZMK_EV_EVENT_BUBBLE;
}
+ // Store the position of pressed key for positional hold-tap purposes.
+ if ((ev->state) // i.e. key pressed (not released)
+ && (undecided_hold_tap->position_of_first_other_key_pressed ==
+ -1) // i.e. no other key has been pressed yet
+ ) {
+ undecided_hold_tap->position_of_first_other_key_pressed = ev->position;
+ }
+
if (undecided_hold_tap->position == ev->position) {
if (ev->state) { // keydown
LOG_ERR("hold-tap listener should be called before before most other listeners!");
@@ -604,6 +656,8 @@ static struct behavior_hold_tap_data behavior_hold_tap_data;
.quick_tap_ms = DT_INST_PROP(n, quick_tap_ms), \
.flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \
.retro_tap = DT_INST_PROP(n, retro_tap), \
+ .hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions), \
+ .hold_trigger_key_positions_len = DT_INST_PROP_LEN(n, hold_trigger_key_positions), \
}; \
DEVICE_DT_INST_DEFINE(n, behavior_hold_tap_init, device_pm_control_nop, \
&behavior_hold_tap_data, &behavior_hold_tap_config_##n, APPLICATION, \
diff --git a/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/events.patterns b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/keycode_events.snapshot
new file mode 100644
index 0000000..926174b
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/keycode_events.snapshot
@@ -0,0 +1,5 @@
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided hold-timer (balanced decision moment timer)
+kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/native_posix.keymap b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/native_posix.keymap
new file mode 100644
index 0000000..11d033f
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/native_posix.keymap
@@ -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)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot
new file mode 100644
index 0000000..1b5cc8f
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot
@@ -0,0 +1,7 @@
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided tap (balanced decision moment timer)
+kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap
new file mode 100644
index 0000000..d1d2b75
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap
@@ -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,1,200) // non trigger key
+ /* timer fires */
+ ZMK_MOCK_RELEASE(1,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot
new file mode 100644
index 0000000..242b31f
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot
@@ -0,0 +1,7 @@
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided hold-timer (balanced decision moment timer)
+kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap
new file mode 100644
index 0000000..94d9a92
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap
@@ -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) // trigger key
+ /* timer fires */
+ ZMK_MOCK_RELEASE(1,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi b/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi
new file mode 100644
index 0000000..5657644
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi
@@ -0,0 +1,29 @@
+#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>;
+ quick-tap-ms = <200>;
+ bindings = <&kp>, <&kp>;
+ hold-trigger-key-positions = <2>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &ht_bal LEFT_SHIFT F &ht_bal LEFT_CONTROL J
+ &kp D &kp E>;
+ };
+ };
+};
diff --git a/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot
new file mode 100644
index 0000000..1e1ea6b
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot
@@ -0,0 +1,9 @@
+kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided tap (balanced decision moment timer)
+kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap
new file mode 100644
index 0000000..6ddf87f
--- /dev/null
+++ b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap
@@ -0,0 +1,16 @@
+#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) // trigger key
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(1,1,400) // not trigger key
+ /* timer fires */
+ ZMK_MOCK_RELEASE(1,1,10)
+ ZMK_MOCK_RELEASE(1,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot
new file mode 100644
index 0000000..827ac98
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot
@@ -0,0 +1,5 @@
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided hold-timer (hold-preferred decision moment timer)
+kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/native_posix.keymap b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/native_posix.keymap
new file mode 100644
index 0000000..11d033f
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/native_posix.keymap
@@ -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)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot
new file mode 100644
index 0000000..964cbaf
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot
@@ -0,0 +1,7 @@
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided tap (hold-preferred decision moment other-key-down)
+kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap
new file mode 100644
index 0000000..d1d2b75
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap
@@ -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,1,200) // non trigger key
+ /* timer fires */
+ ZMK_MOCK_RELEASE(1,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot
new file mode 100644
index 0000000..1d2b827
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot
@@ -0,0 +1,7 @@
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down)
+kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap
new file mode 100644
index 0000000..94d9a92
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap
@@ -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) // trigger key
+ /* timer fires */
+ ZMK_MOCK_RELEASE(1,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi b/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi
new file mode 100644
index 0000000..bf68100
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi
@@ -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>;
+ quick-tap-ms = <200>;
+ bindings = <&kp>, <&kp>;
+ hold-trigger-key-positions = <2>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &ht_hold LEFT_SHIFT F &ht_hold LEFT_CONTROL J
+ &kp D &kp E>;
+ };
+ };
+};
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot
new file mode 100644
index 0000000..2838194
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot
@@ -0,0 +1,9 @@
+kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided tap (hold-preferred decision moment other-key-down)
+kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap
new file mode 100644
index 0000000..6ddf87f
--- /dev/null
+++ b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap
@@ -0,0 +1,16 @@
+#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) // trigger key
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(1,1,400) // not trigger key
+ /* timer fires */
+ ZMK_MOCK_RELEASE(1,1,10)
+ ZMK_MOCK_RELEASE(1,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot
new file mode 100644
index 0000000..4bf3e7c
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot
@@ -0,0 +1,5 @@
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided hold-timer (tap-preferred decision moment timer)
+kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/native_posix.keymap b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/native_posix.keymap
new file mode 100644
index 0000000..11d033f
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/native_posix.keymap
@@ -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)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot
new file mode 100644
index 0000000..337af3e
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot
@@ -0,0 +1,7 @@
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided tap (tap-preferred decision moment timer)
+kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap
new file mode 100644
index 0000000..d1d2b75
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix.keymap
@@ -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,1,200) // non trigger key
+ /* timer fires */
+ ZMK_MOCK_RELEASE(1,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot
new file mode 100644
index 0000000..2d98556
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot
@@ -0,0 +1,7 @@
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided hold-timer (tap-preferred decision moment timer)
+kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap
new file mode 100644
index 0000000..94d9a92
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix.keymap
@@ -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) // trigger key
+ /* timer fires */
+ ZMK_MOCK_RELEASE(1,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi b/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi
new file mode 100644
index 0000000..e4be8d1
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi
@@ -0,0 +1,29 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan_mock.h>
+
+/ {
+ behaviors {
+ tp: behavior_tap_preferred {
+ compatible = "zmk,behavior-hold-tap";
+ label = "MOD_TAP";
+ #binding-cells = <2>;
+ flavor = "tap-preferred";
+ tapping-term-ms = <300>;
+ quick-tap-ms = <200>;
+ bindings = <&kp>, <&kp>;
+ hold-trigger-key-positions = <2>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &tp LEFT_SHIFT F &tp LEFT_CONTROL J
+ &kp D &kp E>;
+ };
+ };
+};
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns
new file mode 100644
index 0000000..fdf2b15
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/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 \ No newline at end of file
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot
new file mode 100644
index 0000000..4ecb1b8
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot
@@ -0,0 +1,9 @@
+kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_pressed: 0 new undecided hold_tap
+ht_decide: 0 decided tap (tap-preferred decision moment timer)
+kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
+kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
+ht_binding_released: 0 cleaning up hold-tap
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap
new file mode 100644
index 0000000..6ddf87f
--- /dev/null
+++ b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix.keymap
@@ -0,0 +1,16 @@
+#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) // trigger key
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(1,1,400) // not trigger key
+ /* timer fires */
+ ZMK_MOCK_RELEASE(1,1,10)
+ ZMK_MOCK_RELEASE(1,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file