diff --git a/app/dts/bindings/zmk,combos.yaml b/app/dts/bindings/zmk,combos.yaml
index d094b5c4..6f6794ba 100644
--- a/app/dts/bindings/zmk,combos.yaml
+++ b/app/dts/bindings/zmk,combos.yaml
@@ -18,6 +18,9 @@ child-binding:
     timeout-ms:
       type: int
       default: 50
+    global-quick-tap-ms:
+      type: int
+      default: -1
     slow-release:
       type: boolean
     layers:
diff --git a/app/src/combo.c b/app/src/combo.c
index 87a93143..0d6de4f1 100644
--- a/app/src/combo.c
+++ b/app/src/combo.c
@@ -16,6 +16,7 @@
 #include <zmk/behavior.h>
 #include <zmk/event_manager.h>
 #include <zmk/events/position_state_changed.h>
+#include <zmk/events/keycode_state_changed.h>
 #include <zmk/hid.h>
 #include <zmk/matrix.h>
 #include <zmk/keymap.h>
@@ -30,6 +31,7 @@ struct combo_cfg {
     int32_t key_position_len;
     struct zmk_behavior_binding behavior;
     int32_t timeout_ms;
+    int32_t global_quick_tap_ms;
     // if slow release is set, the combo releases when the last key is released.
     // otherwise, the combo releases when the first key is released.
     bool slow_release;
@@ -72,6 +74,17 @@ int active_combo_count = 0;
 struct k_work_delayable timeout_task;
 int64_t timeout_task_timeout_at;
 
+// this keeps track of the last non-combo, non-mod key tap
+int64_t last_tapped_timestamp = INT32_MIN;
+// this keeps track of the last time a combo was pressed
+int64_t last_combo_timestamp = INT32_MIN;
+
+static void store_last_tapped(int64_t timestamp) {
+    if (timestamp > last_combo_timestamp) {
+        last_tapped_timestamp = timestamp;
+    }
+}
+
 // Store the combo key pointer in the combos array, one pointer for each key position
 // The combos are sorted shortest-first, then by virtual-key-position.
 static int initialize_combo(struct combo_cfg *new_combo) {
@@ -122,6 +135,10 @@ static bool combo_active_on_layer(struct combo_cfg *combo, uint8_t layer) {
     return false;
 }
 
+static bool is_quick_tap(struct combo_cfg *combo, int64_t timestamp) {
+    return (last_tapped_timestamp + combo->global_quick_tap_ms) > timestamp;
+}
+
 static int setup_candidates_for_first_keypress(int32_t position, int64_t timestamp) {
     int number_of_combo_candidates = 0;
     uint8_t highest_active_layer = zmk_keymap_highest_layer_active();
@@ -130,7 +147,7 @@ static int setup_candidates_for_first_keypress(int32_t position, int64_t timesta
         if (combo == NULL) {
             return number_of_combo_candidates;
         }
-        if (combo_active_on_layer(combo, highest_active_layer)) {
+        if (combo_active_on_layer(combo, highest_active_layer) && !is_quick_tap(combo, timestamp)) {
             candidates[number_of_combo_candidates].combo = combo;
             candidates[number_of_combo_candidates].timeout_at = timestamp + combo->timeout_ms;
             number_of_combo_candidates++;
@@ -252,7 +269,7 @@ static int capture_pressed_key(const zmk_event_t *ev) {
         pressed_keys[i] = ev;
         return ZMK_EV_EVENT_CAPTURED;
     }
-    return 0;
+    return ZMK_EV_EVENT_BUBBLE;
 }
 
 const struct zmk_listener zmk_listener_combo;
@@ -284,6 +301,8 @@ static inline int press_combo_behavior(struct combo_cfg *combo, int32_t timestam
         .timestamp = timestamp,
     };
 
+    last_combo_timestamp = timestamp;
+
     return behavior_keymap_binding_pressed(&combo->behavior, event);
 }
 
@@ -413,7 +432,7 @@ static int position_state_down(const zmk_event_t *ev, struct zmk_position_state_
     if (candidates[0].combo == NULL) {
         num_candidates = setup_candidates_for_first_keypress(data->position, data->timestamp);
         if (num_candidates == 0) {
-            return 0;
+            return ZMK_EV_EVENT_BUBBLE;
         }
     } else {
         filter_timed_out_candidates(data->timestamp);
@@ -453,7 +472,7 @@ static int position_state_up(const zmk_event_t *ev, struct zmk_position_state_ch
         ZMK_EVENT_RAISE(ev);
         return ZMK_EV_EVENT_CAPTURED;
     }
-    return 0;
+    return ZMK_EV_EVENT_BUBBLE;
 }
 
 static void combo_timeout_handler(struct k_work *item) {
@@ -470,7 +489,7 @@ static void combo_timeout_handler(struct k_work *item) {
 static int position_state_changed_listener(const zmk_event_t *ev) {
     struct zmk_position_state_changed *data = as_zmk_position_state_changed(ev);
     if (data == NULL) {
-        return 0;
+        return ZMK_EV_EVENT_BUBBLE;
     }
 
     if (data->state) { // keydown
@@ -480,12 +499,31 @@ static int position_state_changed_listener(const zmk_event_t *ev) {
     }
 }
 
-ZMK_LISTENER(combo, position_state_changed_listener);
+static int keycode_state_changed_listener(const zmk_event_t *eh) {
+    struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh);
+    if (ev->state && !is_mod(ev->usage_page, ev->keycode)) {
+        store_last_tapped(ev->timestamp);
+    }
+    return ZMK_EV_EVENT_BUBBLE;
+}
+
+int behavior_combo_listener(const zmk_event_t *eh) {
+    if (as_zmk_position_state_changed(eh) != NULL) {
+        return position_state_changed_listener(eh);
+    } else if (as_zmk_keycode_state_changed(eh) != NULL) {
+        return keycode_state_changed_listener(eh);
+    }
+    return ZMK_EV_EVENT_BUBBLE;
+}
+
+ZMK_LISTENER(combo, behavior_combo_listener);
 ZMK_SUBSCRIPTION(combo, zmk_position_state_changed);
+ZMK_SUBSCRIPTION(combo, zmk_keycode_state_changed);
 
 #define COMBO_INST(n)                                                                              \
     static struct combo_cfg combo_config_##n = {                                                   \
         .timeout_ms = DT_PROP(n, timeout_ms),                                                      \
+        .global_quick_tap_ms = DT_PROP(n, global_quick_tap_ms),                                    \
         .key_positions = DT_PROP(n, key_positions),                                                \
         .key_position_len = DT_PROP_LEN(n, key_positions),                                         \
         .behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, n),                                              \
diff --git a/app/tests/combo/global-quick-tap/events.patterns b/app/tests/combo/global-quick-tap/events.patterns
new file mode 100644
index 00000000..833100f6
--- /dev/null
+++ b/app/tests/combo/global-quick-tap/events.patterns
@@ -0,0 +1 @@
+s/.*hid_listener_keycode_//p
\ No newline at end of file
diff --git a/app/tests/combo/global-quick-tap/keycode_events.snapshot b/app/tests/combo/global-quick-tap/keycode_events.snapshot
new file mode 100644
index 00000000..ee4dd064
--- /dev/null
+++ b/app/tests/combo/global-quick-tap/keycode_events.snapshot
@@ -0,0 +1,14 @@
+pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00
diff --git a/app/tests/combo/global-quick-tap/native_posix_64.keymap b/app/tests/combo/global-quick-tap/native_posix_64.keymap
new file mode 100644
index 00000000..92b5a8ae
--- /dev/null
+++ b/app/tests/combo/global-quick-tap/native_posix_64.keymap
@@ -0,0 +1,64 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+    combos {
+        compatible = "zmk,combos";
+        combo_one {
+            timeout-ms = <50>;
+            key-positions = <0 1>;
+            bindings = <&kp X>;
+            global-quick-tap-ms = <100>;
+        };
+
+        combo_two {
+            timeout-ms = <50>;
+            key-positions = <0 2>;
+            bindings = <&kp Y>;
+        };
+    };
+
+    keymap {
+        compatible = "zmk,keymap";
+        label ="Default keymap";
+
+        default_layer {
+            bindings = <
+                &kp A &kp B
+                &kp C &kp D
+            >;
+        };
+    };
+};
+
+&kscan {
+    events = <
+        /* Tap A  */
+        ZMK_MOCK_PRESS(0,0,10)
+        ZMK_MOCK_RELEASE(0,0,60)
+        /* Quick Tap A and B */
+        ZMK_MOCK_PRESS(0,0,10)
+        ZMK_MOCK_PRESS(0,1,10)
+        ZMK_MOCK_RELEASE(0,0,10)
+        ZMK_MOCK_RELEASE(0,1,200)
+        /* Combo One */
+        ZMK_MOCK_PRESS(0,0,10)
+        ZMK_MOCK_PRESS(0,1,10)
+        ZMK_MOCK_RELEASE(0,0,10)
+        ZMK_MOCK_RELEASE(0,1,10)
+        /* Combo One Again (shouldn't quick tap) */
+        ZMK_MOCK_PRESS(0,0,10)
+        ZMK_MOCK_PRESS(0,1,10)
+        ZMK_MOCK_RELEASE(0,0,10)
+        ZMK_MOCK_RELEASE(0,1,10)
+        /* Tap A  */
+        ZMK_MOCK_PRESS(0,0,10)
+        ZMK_MOCK_RELEASE(0,0,60)
+        /* Combo 2  */
+        ZMK_MOCK_PRESS(0,0,10)
+        ZMK_MOCK_PRESS(1,0,10)
+        ZMK_MOCK_RELEASE(0,0,10)
+        ZMK_MOCK_RELEASE(1,0,10)
+    >;
+};