summaryrefslogtreecommitdiff
path: root/app/tests/combo
diff options
context:
space:
mode:
Diffstat (limited to 'app/tests/combo')
-rw-r--r--app/tests/combo/combos-and-holdtaps-0/events.patterns2
-rw-r--r--app/tests/combo/combos-and-holdtaps-0/keycode_events.snapshot4
-rw-r--r--app/tests/combo/combos-and-holdtaps-0/native_posix.keymap47
-rw-r--r--app/tests/combo/combos-and-holdtaps-1/events.patterns2
-rw-r--r--app/tests/combo/combos-and-holdtaps-1/keycode_events.snapshot4
-rw-r--r--app/tests/combo/combos-and-holdtaps-1/native_posix.keymap42
-rw-r--r--app/tests/combo/combos-and-holdtaps-2/events.patterns2
-rw-r--r--app/tests/combo/combos-and-holdtaps-2/keycode_events.snapshot2
-rw-r--r--app/tests/combo/combos-and-holdtaps-2/native_posix.keymap45
-rw-r--r--app/tests/combo/multiple-timeouts/events.patterns1
-rw-r--r--app/tests/combo/multiple-timeouts/keycode_events.snapshot4
-rw-r--r--app/tests/combo/multiple-timeouts/native_posix.keymap40
-rw-r--r--app/tests/combo/overlapping-combos-0/events.patterns2
-rw-r--r--app/tests/combo/overlapping-combos-0/keycode_events.snapshot20
-rw-r--r--app/tests/combo/overlapping-combos-0/native_posix.keymap117
-rw-r--r--app/tests/combo/overlapping-combos-1/events.patterns2
-rw-r--r--app/tests/combo/overlapping-combos-1/keycode_events.snapshot8
-rw-r--r--app/tests/combo/overlapping-combos-1/native_posix.keymap65
-rw-r--r--app/tests/combo/overlapping-combos-2/events.patterns2
-rw-r--r--app/tests/combo/overlapping-combos-2/keycode_events.snapshot4
-rw-r--r--app/tests/combo/overlapping-combos-2/native_posix.keymap52
-rw-r--r--app/tests/combo/overlapping-combos-3/events.patterns2
-rw-r--r--app/tests/combo/overlapping-combos-3/keycode_events.snapshot4
-rw-r--r--app/tests/combo/overlapping-combos-3/native_posix.keymap53
-rw-r--r--app/tests/combo/partially-overlapping-combos/events.patterns1
-rw-r--r--app/tests/combo/partially-overlapping-combos/keycode_events.snapshot16
-rw-r--r--app/tests/combo/partially-overlapping-combos/native_posix.keymap84
-rw-r--r--app/tests/combo/press-release/events.patterns1
-rw-r--r--app/tests/combo/press-release/keycode_events.snapshot8
-rw-r--r--app/tests/combo/press-release/native_posix.keymap51
-rw-r--r--app/tests/combo/press-timeout/events.patterns1
-rw-r--r--app/tests/combo/press-timeout/keycode_events.snapshot4
-rw-r--r--app/tests/combo/press-timeout/native_posix.keymap35
-rw-r--r--app/tests/combo/press1-press2-release1-release2/events.patterns2
-rw-r--r--app/tests/combo/press1-press2-release1-release2/keycode_events.snapshot4
-rw-r--r--app/tests/combo/press1-press2-release1-release2/native_posix.keymap45
-rw-r--r--app/tests/combo/press1-press2-release2-release1/events.patterns2
-rw-r--r--app/tests/combo/press1-press2-release2-release1/keycode_events.snapshot4
-rw-r--r--app/tests/combo/press1-press2-release2-release1/native_posix.keymap46
-rw-r--r--app/tests/combo/press1-release1-press2-release2/events.patterns2
-rw-r--r--app/tests/combo/press1-release1-press2-release2/keycode_events.snapshot4
-rw-r--r--app/tests/combo/press1-release1-press2-release2/native_posix.keymap46
-rw-r--r--app/tests/combo/slowrelease-disabled/events.patterns1
-rw-r--r--app/tests/combo/slowrelease-disabled/keycode_events.snapshot4
-rw-r--r--app/tests/combo/slowrelease-disabled/native_posix.keymap38
-rw-r--r--app/tests/combo/slowrelease-enabled/events.patterns1
-rw-r--r--app/tests/combo/slowrelease-enabled/keycode_events.snapshot4
-rw-r--r--app/tests/combo/slowrelease-enabled/native_posix.keymap38
48 files changed, 968 insertions, 0 deletions
diff --git a/app/tests/combo/combos-and-holdtaps-0/events.patterns b/app/tests/combo/combos-and-holdtaps-0/events.patterns
new file mode 100644
index 0000000..b90d786
--- /dev/null
+++ b/app/tests/combo/combos-and-holdtaps-0/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo//p \ No newline at end of file
diff --git a/app/tests/combo/combos-and-holdtaps-0/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-0/keycode_events.snapshot
new file mode 100644
index 0000000..ad86b26
--- /dev/null
+++ b/app/tests/combo/combos-and-holdtaps-0/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0xe0 mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0xe0 mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
diff --git a/app/tests/combo/combos-and-holdtaps-0/native_posix.keymap b/app/tests/combo/combos-and-holdtaps-0/native_posix.keymap
new file mode 100644
index 0000000..d35c727
--- /dev/null
+++ b/app/tests/combo/combos-and-holdtaps-0/native_posix.keymap
@@ -0,0 +1,47 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+&mt {
+ flavor = "hold-preferred";
+};
+
+/*
+This test fails if the order of event handlers for hold-taps
+and combos is wrong. Hold-taps need to process key position events
+first so the decision to hold or tap can be made.
+*/
+/ {
+ combos {
+ compatible = "zmk,combos";
+
+ combo_two {
+ timeout-ms = <100>;
+ key-positions = <1 2>;
+ bindings = <&kp Y>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &mt LEFT_CONTROL A &kp B
+ &kp C &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/combos-and-holdtaps-1/events.patterns b/app/tests/combo/combos-and-holdtaps-1/events.patterns
new file mode 100644
index 0000000..b90d786
--- /dev/null
+++ b/app/tests/combo/combos-and-holdtaps-1/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo//p \ No newline at end of file
diff --git a/app/tests/combo/combos-and-holdtaps-1/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-1/keycode_events.snapshot
new file mode 100644
index 0000000..dc4dbb4
--- /dev/null
+++ b/app/tests/combo/combos-and-holdtaps-1/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
diff --git a/app/tests/combo/combos-and-holdtaps-1/native_posix.keymap b/app/tests/combo/combos-and-holdtaps-1/native_posix.keymap
new file mode 100644
index 0000000..a99c15d
--- /dev/null
+++ b/app/tests/combo/combos-and-holdtaps-1/native_posix.keymap
@@ -0,0 +1,42 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+&mt {
+ flavor = "hold-preferred";
+};
+
+/* this test checks if hold-taps can be part of a combo */
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_two {
+ timeout-ms = <100>;
+ key-positions = <0 1>;
+ bindings = <&kp Y>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &mt LEFT_CONTROL A &kp B
+ &kp C &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/combos-and-holdtaps-2/events.patterns b/app/tests/combo/combos-and-holdtaps-2/events.patterns
new file mode 100644
index 0000000..b90d786
--- /dev/null
+++ b/app/tests/combo/combos-and-holdtaps-2/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo//p \ No newline at end of file
diff --git a/app/tests/combo/combos-and-holdtaps-2/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-2/keycode_events.snapshot
new file mode 100644
index 0000000..a650880
--- /dev/null
+++ b/app/tests/combo/combos-and-holdtaps-2/keycode_events.snapshot
@@ -0,0 +1,2 @@
+pressed: usage_page 0x07 keycode 0xe0 mods 0x00
+pressed: usage_page 0x07 keycode 0xe4 mods 0x00
diff --git a/app/tests/combo/combos-and-holdtaps-2/native_posix.keymap b/app/tests/combo/combos-and-holdtaps-2/native_posix.keymap
new file mode 100644
index 0000000..f8dbe45
--- /dev/null
+++ b/app/tests/combo/combos-and-holdtaps-2/native_posix.keymap
@@ -0,0 +1,45 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+&mt {
+ flavor = "hold-preferred";
+};
+
+/* This test verifies that hold-tap keys can observe
+ * events which were released from combos.
+ */
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <100>;
+ key-positions = <0 2>;
+ bindings = <&kp Y>;
+ };
+ combo_two {
+ timeout-ms = <100>;
+ key-positions = <1 3>;
+ bindings = <&kp Z>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &mt LEFT_CONTROL A &mt RIGHT_CONTROL B
+ &none &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,0)
+ ZMK_MOCK_PRESS(0,1,300)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/multiple-timeouts/events.patterns b/app/tests/combo/multiple-timeouts/events.patterns
new file mode 100644
index 0000000..b1342af
--- /dev/null
+++ b/app/tests/combo/multiple-timeouts/events.patterns
@@ -0,0 +1 @@
+s/.*hid_listener_keycode_//p
diff --git a/app/tests/combo/multiple-timeouts/keycode_events.snapshot b/app/tests/combo/multiple-timeouts/keycode_events.snapshot
new file mode 100644
index 0000000..c5bdd6e
--- /dev/null
+++ b/app/tests/combo/multiple-timeouts/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x04 mods 0x00
+pressed: usage_page 0x07 keycode 0x05 mods 0x00
+released: usage_page 0x07 keycode 0x04 mods 0x00
+released: usage_page 0x07 keycode 0x05 mods 0x00
diff --git a/app/tests/combo/multiple-timeouts/native_posix.keymap b/app/tests/combo/multiple-timeouts/native_posix.keymap
new file mode 100644
index 0000000..91bf523
--- /dev/null
+++ b/app/tests/combo/multiple-timeouts/native_posix.keymap
@@ -0,0 +1,40 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <30>;
+ key-positions = <0 1>;
+ bindings = <&kp C>;
+ };
+ combo_two {
+ timeout-ms = <120>;
+ key-positions = <0 1 2>;
+ bindings = <&kp C>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &none &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,100)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/overlapping-combos-0/events.patterns b/app/tests/combo/overlapping-combos-0/events.patterns
new file mode 100644
index 0000000..b90d786
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-0/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo//p \ No newline at end of file
diff --git a/app/tests/combo/overlapping-combos-0/keycode_events.snapshot b/app/tests/combo/overlapping-combos-0/keycode_events.snapshot
new file mode 100644
index 0000000..ec63b77
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-0/keycode_events.snapshot
@@ -0,0 +1,20 @@
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
diff --git a/app/tests/combo/overlapping-combos-0/native_posix.keymap b/app/tests/combo/overlapping-combos-0/native_posix.keymap
new file mode 100644
index 0000000..e3cbf43
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-0/native_posix.keymap
@@ -0,0 +1,117 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/*
+ combo 0 timeout inf
+ combo 01 timeout inf
+ combo 0123 timeout inf
+ press 012 in any combination, release any of those keys
+ expected: combo 012 on key-release
+ */
+
+/* it is useful to set timeout to a large value when attaching a debugger. */
+#define TIMEOUT (60*60*1000)
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <TIMEOUT>;
+ key-positions = <0 1 2>;
+ bindings = <&kp X>;
+ };
+
+ combo_two {
+ timeout-ms = <TIMEOUT>;
+ key-positions = <0 2>;
+ bindings = <&kp Y>;
+ };
+
+ combo_three {
+ timeout-ms = <TIMEOUT>;
+ key-positions = <1>;
+ bindings = <&kp Z>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp C &none
+ >;
+ };
+ };
+};
+&kscan {
+ events = <
+ /* all permutations of combo one press, combo triggered by release */
+ /* while debugging these, you may want to set the release_timer to a high number */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+
+ /* all permutations of combo two press and release, combo triggered by release */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/overlapping-combos-1/events.patterns b/app/tests/combo/overlapping-combos-1/events.patterns
new file mode 100644
index 0000000..b90d786
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-1/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo//p \ No newline at end of file
diff --git a/app/tests/combo/overlapping-combos-1/keycode_events.snapshot b/app/tests/combo/overlapping-combos-1/keycode_events.snapshot
new file mode 100644
index 0000000..daf7247
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-1/keycode_events.snapshot
@@ -0,0 +1,8 @@
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
diff --git a/app/tests/combo/overlapping-combos-1/native_posix.keymap b/app/tests/combo/overlapping-combos-1/native_posix.keymap
new file mode 100644
index 0000000..c228c47
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-1/native_posix.keymap
@@ -0,0 +1,65 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/*
+ combo 01 timeout 50
+ combo 012 timeout 100
+ AB is pressed within 50ms, C is never pressed.
+ expected outcome: AB after 100ms
+*/
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_two {
+ timeout-ms = <50>;
+ key-positions = <0 1>;
+ bindings = <&kp Y>;
+ };
+
+ combo_three {
+ timeout-ms = <100>;
+ key-positions = <0 1 2>;
+ bindings = <&kp X>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp C &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ /* if you're debugging these, remember that the timer can be triggered between
+ events while stepping through code. */
+ /* all permutations of combo two press and release, combo triggered by timeout */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,100)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,0,100)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,0,100)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,100)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/overlapping-combos-2/events.patterns b/app/tests/combo/overlapping-combos-2/events.patterns
new file mode 100644
index 0000000..b90d786
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-2/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo//p \ No newline at end of file
diff --git a/app/tests/combo/overlapping-combos-2/keycode_events.snapshot b/app/tests/combo/overlapping-combos-2/keycode_events.snapshot
new file mode 100644
index 0000000..dc4dbb4
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-2/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
diff --git a/app/tests/combo/overlapping-combos-2/native_posix.keymap b/app/tests/combo/overlapping-combos-2/native_posix.keymap
new file mode 100644
index 0000000..3d36421
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-2/native_posix.keymap
@@ -0,0 +1,52 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/*
+ combo 01 timeout 100
+ combo 0123 timeout 100
+ press 012, wait until timeout runs out
+ expected: combo 01 after 100ms, immediately followed by key 2.
+ */
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_two {
+ timeout-ms = <100>;
+ key-positions = <0 1>;
+ bindings = <&kp Y>;
+ };
+
+ combo_four {
+ timeout-ms = <100>;
+ key-positions = <0 1 2 3>;
+ bindings = <&kp W>;
+ };
+
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp C &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ /* if you're debugging these, remember that the timer can be triggered between
+ events while stepping through code. */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,2,100)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,2,100)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/overlapping-combos-3/events.patterns b/app/tests/combo/overlapping-combos-3/events.patterns
new file mode 100644
index 0000000..b90d786
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-3/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo//p \ No newline at end of file
diff --git a/app/tests/combo/overlapping-combos-3/keycode_events.snapshot b/app/tests/combo/overlapping-combos-3/keycode_events.snapshot
new file mode 100644
index 0000000..e0cb655
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-3/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x04 mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x04 mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
diff --git a/app/tests/combo/overlapping-combos-3/native_posix.keymap b/app/tests/combo/overlapping-combos-3/native_posix.keymap
new file mode 100644
index 0000000..0622dcd
--- /dev/null
+++ b/app/tests/combo/overlapping-combos-3/native_posix.keymap
@@ -0,0 +1,53 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/*
+ combo 12 timeout 100
+ combo 0123 timeout 100
+ press 012, release 2
+ expected: key pos 0 followed by combo 12
+ */
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_two {
+ timeout-ms = <100>;
+ key-positions = <1 2>;
+ bindings = <&kp Y>;
+ };
+
+
+ combo_four {
+ timeout-ms = <100>;
+ key-positions = <0 1 2 3>;
+ bindings = <&kp W>;
+ };
+
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp C &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ /* if you're debugging these, remember that the timer can be triggered between
+ events while stepping through code. */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,2,100)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,2,100)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/partially-overlapping-combos/events.patterns b/app/tests/combo/partially-overlapping-combos/events.patterns
new file mode 100644
index 0000000..b1342af
--- /dev/null
+++ b/app/tests/combo/partially-overlapping-combos/events.patterns
@@ -0,0 +1 @@
+s/.*hid_listener_keycode_//p
diff --git a/app/tests/combo/partially-overlapping-combos/keycode_events.snapshot b/app/tests/combo/partially-overlapping-combos/keycode_events.snapshot
new file mode 100644
index 0000000..adaa64b
--- /dev/null
+++ b/app/tests/combo/partially-overlapping-combos/keycode_events.snapshot
@@ -0,0 +1,16 @@
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1b mods 0x00
+released: usage_page 0x07 keycode 0x1b mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
+pressed: usage_page 0x07 keycode 0x1c mods 0x00
+released: usage_page 0x07 keycode 0x1c mods 0x00
diff --git a/app/tests/combo/partially-overlapping-combos/native_posix.keymap b/app/tests/combo/partially-overlapping-combos/native_posix.keymap
new file mode 100644
index 0000000..4e68105
--- /dev/null
+++ b/app/tests/combo/partially-overlapping-combos/native_posix.keymap
@@ -0,0 +1,84 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <30>;
+ key-positions = <0 1>;
+ bindings = <&kp X>;
+ };
+
+ combo_two {
+ timeout-ms = <30>;
+ key-positions = <0 2>;
+ bindings = <&kp Y>;
+ };
+
+ combo_three {
+ timeout-ms = <30>;
+ key-positions = <3>;
+ bindings = <&kp Z>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp C &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ /* all permutations of combo one press and release */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+
+ /* all permutations of combo two press and release */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,2,10)
+ ZMK_MOCK_RELEASE(0,2,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+};
diff --git a/app/tests/combo/press-release/events.patterns b/app/tests/combo/press-release/events.patterns
new file mode 100644
index 0000000..b1342af
--- /dev/null
+++ b/app/tests/combo/press-release/events.patterns
@@ -0,0 +1 @@
+s/.*hid_listener_keycode_//p
diff --git a/app/tests/combo/press-release/keycode_events.snapshot b/app/tests/combo/press-release/keycode_events.snapshot
new file mode 100644
index 0000000..01718e7
--- /dev/null
+++ b/app/tests/combo/press-release/keycode_events.snapshot
@@ -0,0 +1,8 @@
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
diff --git a/app/tests/combo/press-release/native_posix.keymap b/app/tests/combo/press-release/native_posix.keymap
new file mode 100644
index 0000000..0f45792
--- /dev/null
+++ b/app/tests/combo/press-release/native_posix.keymap
@@ -0,0 +1,51 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <30>;
+ key-positions = <0 1>;
+ bindings = <&kp C>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &none &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ /* all different combinations of press and release order */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/press-timeout/events.patterns b/app/tests/combo/press-timeout/events.patterns
new file mode 100644
index 0000000..b1342af
--- /dev/null
+++ b/app/tests/combo/press-timeout/events.patterns
@@ -0,0 +1 @@
+s/.*hid_listener_keycode_//p
diff --git a/app/tests/combo/press-timeout/keycode_events.snapshot b/app/tests/combo/press-timeout/keycode_events.snapshot
new file mode 100644
index 0000000..c5bdd6e
--- /dev/null
+++ b/app/tests/combo/press-timeout/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x04 mods 0x00
+pressed: usage_page 0x07 keycode 0x05 mods 0x00
+released: usage_page 0x07 keycode 0x04 mods 0x00
+released: usage_page 0x07 keycode 0x05 mods 0x00
diff --git a/app/tests/combo/press-timeout/native_posix.keymap b/app/tests/combo/press-timeout/native_posix.keymap
new file mode 100644
index 0000000..ff0b749
--- /dev/null
+++ b/app/tests/combo/press-timeout/native_posix.keymap
@@ -0,0 +1,35 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <30>;
+ key-positions = <0 1>;
+ bindings = <&kp C>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &none &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,100)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/press1-press2-release1-release2/events.patterns b/app/tests/combo/press1-press2-release1-release2/events.patterns
new file mode 100644
index 0000000..5f3e4cf
--- /dev/null
+++ b/app/tests/combo/press1-press2-release1-release2/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo/combo/p \ No newline at end of file
diff --git a/app/tests/combo/press1-press2-release1-release2/keycode_events.snapshot b/app/tests/combo/press1-press2-release1-release2/keycode_events.snapshot
new file mode 100644
index 0000000..cfa02de
--- /dev/null
+++ b/app/tests/combo/press1-press2-release1-release2/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+pressed: usage_page 0x07 keycode 0x07 mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x07 mods 0x00
diff --git a/app/tests/combo/press1-press2-release1-release2/native_posix.keymap b/app/tests/combo/press1-press2-release1-release2/native_posix.keymap
new file mode 100644
index 0000000..2518bbc
--- /dev/null
+++ b/app/tests/combo/press1-press2-release1-release2/native_posix.keymap
@@ -0,0 +1,45 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <30>;
+ key-positions = <0 1>;
+ bindings = <&kp C>;
+ };
+
+ combo_two {
+ timeout-ms = <30>;
+ key-positions = <2 3>;
+ bindings = <&kp D>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp Z &kp Y
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(1,0,10)
+ ZMK_MOCK_PRESS(1,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(1,0,10)
+ ZMK_MOCK_RELEASE(1,1,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/press1-press2-release2-release1/events.patterns b/app/tests/combo/press1-press2-release2-release1/events.patterns
new file mode 100644
index 0000000..b54b66b
--- /dev/null
+++ b/app/tests/combo/press1-press2-release2-release1/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo/combo/p
diff --git a/app/tests/combo/press1-press2-release2-release1/keycode_events.snapshot b/app/tests/combo/press1-press2-release2-release1/keycode_events.snapshot
new file mode 100644
index 0000000..b55f09b
--- /dev/null
+++ b/app/tests/combo/press1-press2-release2-release1/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+pressed: usage_page 0x07 keycode 0x07 mods 0x00
+released: usage_page 0x07 keycode 0x07 mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
diff --git a/app/tests/combo/press1-press2-release2-release1/native_posix.keymap b/app/tests/combo/press1-press2-release2-release1/native_posix.keymap
new file mode 100644
index 0000000..4895636
--- /dev/null
+++ b/app/tests/combo/press1-press2-release2-release1/native_posix.keymap
@@ -0,0 +1,46 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <30>;
+ key-positions = <0 1>;
+ bindings = <&kp C>;
+ };
+
+ combo_two {
+ timeout-ms = <30>;
+ key-positions = <2 3>;
+ bindings = <&kp D>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp Z &kp Y
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_PRESS(1,0,10)
+ ZMK_MOCK_PRESS(1,1,10)
+
+ ZMK_MOCK_RELEASE(1,0,10)
+ ZMK_MOCK_RELEASE(1,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/press1-release1-press2-release2/events.patterns b/app/tests/combo/press1-release1-press2-release2/events.patterns
new file mode 100644
index 0000000..5f3e4cf
--- /dev/null
+++ b/app/tests/combo/press1-release1-press2-release2/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo/combo/p \ No newline at end of file
diff --git a/app/tests/combo/press1-release1-press2-release2/keycode_events.snapshot b/app/tests/combo/press1-release1-press2-release2/keycode_events.snapshot
new file mode 100644
index 0000000..c41dee8
--- /dev/null
+++ b/app/tests/combo/press1-release1-press2-release2/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
+pressed: usage_page 0x07 keycode 0x07 mods 0x00
+released: usage_page 0x07 keycode 0x07 mods 0x00
diff --git a/app/tests/combo/press1-release1-press2-release2/native_posix.keymap b/app/tests/combo/press1-release1-press2-release2/native_posix.keymap
new file mode 100644
index 0000000..0c4a698
--- /dev/null
+++ b/app/tests/combo/press1-release1-press2-release2/native_posix.keymap
@@ -0,0 +1,46 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <30>;
+ key-positions = <0 1>;
+ bindings = <&kp C>;
+ };
+
+ combo_two {
+ timeout-ms = <30>;
+ key-positions = <2 3>;
+ bindings = <&kp D>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp Z &kp Y
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+
+ ZMK_MOCK_PRESS(1,0,10)
+ ZMK_MOCK_PRESS(1,1,10)
+ ZMK_MOCK_RELEASE(1,0,10)
+ ZMK_MOCK_RELEASE(1,1,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/slowrelease-disabled/events.patterns b/app/tests/combo/slowrelease-disabled/events.patterns
new file mode 100644
index 0000000..b1342af
--- /dev/null
+++ b/app/tests/combo/slowrelease-disabled/events.patterns
@@ -0,0 +1 @@
+s/.*hid_listener_keycode_//p
diff --git a/app/tests/combo/slowrelease-disabled/keycode_events.snapshot b/app/tests/combo/slowrelease-disabled/keycode_events.snapshot
new file mode 100644
index 0000000..c41dee8
--- /dev/null
+++ b/app/tests/combo/slowrelease-disabled/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
+pressed: usage_page 0x07 keycode 0x07 mods 0x00
+released: usage_page 0x07 keycode 0x07 mods 0x00
diff --git a/app/tests/combo/slowrelease-disabled/native_posix.keymap b/app/tests/combo/slowrelease-disabled/native_posix.keymap
new file mode 100644
index 0000000..3bacb88
--- /dev/null
+++ b/app/tests/combo/slowrelease-disabled/native_posix.keymap
@@ -0,0 +1,38 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <30>;
+ key-positions = <0 1>;
+ bindings = <&kp C>;
+ /* no slow-release! */
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label = "Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp D &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10) /* this should release the combo */
+ ZMK_MOCK_PRESS(1,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(1,0,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/slowrelease-enabled/events.patterns b/app/tests/combo/slowrelease-enabled/events.patterns
new file mode 100644
index 0000000..b1342af
--- /dev/null
+++ b/app/tests/combo/slowrelease-enabled/events.patterns
@@ -0,0 +1 @@
+s/.*hid_listener_keycode_//p
diff --git a/app/tests/combo/slowrelease-enabled/keycode_events.snapshot b/app/tests/combo/slowrelease-enabled/keycode_events.snapshot
new file mode 100644
index 0000000..cfa02de
--- /dev/null
+++ b/app/tests/combo/slowrelease-enabled/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x06 mods 0x00
+pressed: usage_page 0x07 keycode 0x07 mods 0x00
+released: usage_page 0x07 keycode 0x06 mods 0x00
+released: usage_page 0x07 keycode 0x07 mods 0x00
diff --git a/app/tests/combo/slowrelease-enabled/native_posix.keymap b/app/tests/combo/slowrelease-enabled/native_posix.keymap
new file mode 100644
index 0000000..8ac8316
--- /dev/null
+++ b/app/tests/combo/slowrelease-enabled/native_posix.keymap
@@ -0,0 +1,38 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <30>;
+ key-positions = <0 1>;
+ bindings = <&kp C>;
+ slow-release;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp D &none
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10) /* this should not release the combo yet */
+ ZMK_MOCK_PRESS(1,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ ZMK_MOCK_RELEASE(1,0,10)
+ >;
+}; \ No newline at end of file