diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py index a2f297f8cc9..72c684e0b06 100644 --- a/lib/python/qmk/info.py +++ b/lib/python/qmk/info.py @@ -99,6 +99,13 @@ def _validate_build_target(keyboard, info_data): if info_file != keyboard_json_path: _log_error(info_data, f'Invalid keyboard.json location detected: {info_file}.') + # No keyboard.json next to info.json + for conf_file in config_files: + if conf_file.name == 'keyboard.json': + info_file = conf_file.parent / 'info.json' + if info_file.exists(): + _log_error(info_data, f'Invalid info.json location detected: {info_file}.') + # Moving forward keyboard.json should be used as a build target if keyboard_json_count == 0: _log_warning(info_data, 'Build marker "keyboard.json" not found.') diff --git a/quantum/action_tapping.c b/quantum/action_tapping.c index 91719707023..e42a98554d3 100644 --- a/quantum/action_tapping.c +++ b/quantum/action_tapping.c @@ -736,7 +736,7 @@ static void waiting_buffer_chordal_hold_taps_until(keypos_t key) { while (waiting_buffer_tail != waiting_buffer_head) { keyrecord_t *record = &waiting_buffer[waiting_buffer_tail]; ac_dprintf("waiting_buffer_chordal_hold_taps_until: processing [%u]\n", waiting_buffer_tail); - if (is_tap_record(record)) { + if (record->event.pressed && is_tap_record(record)) { record->tap.count = 1; registered_taps_add(record->event.key); } diff --git a/quantum/quantum.c b/quantum/quantum.c index f1a2623193c..79ccddbb58e 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -329,13 +329,13 @@ bool process_record_quantum(keyrecord_t *record) { #ifdef HAPTIC_ENABLE process_haptic(keycode, record) && #endif -#if defined(VIA_ENABLE) - process_record_via(keycode, record) && -#endif #if defined(POINTING_DEVICE_ENABLE) && defined(POINTING_DEVICE_AUTO_MOUSE_ENABLE) process_auto_mouse(keycode, record) && #endif process_record_kb(keycode, record) && +#if defined(VIA_ENABLE) + process_record_via(keycode, record) && +#endif #if defined(SECURE_ENABLE) process_secure(keycode, record) && #endif diff --git a/tests/tap_hold_configurations/chordal_hold/hold_on_other_key_press/test_tap_hold.cpp b/tests/tap_hold_configurations/chordal_hold/hold_on_other_key_press/test_tap_hold.cpp index e6852bbbb1e..7691f226af6 100644 --- a/tests/tap_hold_configurations/chordal_hold/hold_on_other_key_press/test_tap_hold.cpp +++ b/tests/tap_hold_configurations/chordal_hold/hold_on_other_key_press/test_tap_hold.cpp @@ -805,3 +805,46 @@ TEST_F(ChordalHoldHoldOnOtherKeyPress, roll_layer_tap_key_with_regular_key) { run_one_scan_loop(); VERIFY_AND_CLEAR(driver); } + +TEST_F(ChordalHoldHoldOnOtherKeyPress, two_mod_tap_keys_stuttered_press) { + TestDriver driver; + InSequence s; + + auto mod_tap_key1 = KeymapKey(0, 1, 0, LSFT_T(KC_A)); + auto mod_tap_key2 = KeymapKey(0, 2, 0, LCTL_T(KC_B)); + + set_keymap({mod_tap_key1, mod_tap_key2}); + + // Hold first mod-tap key until the tapping term. + EXPECT_REPORT(driver, (KC_LSFT)); + mod_tap_key1.press(); + idle_for(TAPPING_TERM + 1); + VERIFY_AND_CLEAR(driver); + + // Press the second mod-tap key, then quickly release and press the first. + EXPECT_NO_REPORT(driver); + mod_tap_key2.press(); + run_one_scan_loop(); + mod_tap_key1.release(); + run_one_scan_loop(); + VERIFY_AND_CLEAR(driver); + + EXPECT_REPORT(driver, (KC_LSFT, KC_B)); + EXPECT_REPORT(driver, (KC_B)); + EXPECT_REPORT(driver, (KC_B, KC_A)); + mod_tap_key1.press(); + run_one_scan_loop(); + EXPECT_EQ(get_mods(), 0); // Verify that Shift was released. + VERIFY_AND_CLEAR(driver); + + // Release both keys. + EXPECT_REPORT(driver, (KC_A)); + mod_tap_key2.release(); + run_one_scan_loop(); + VERIFY_AND_CLEAR(driver); + + EXPECT_EMPTY_REPORT(driver); + mod_tap_key1.release(); + run_one_scan_loop(); + VERIFY_AND_CLEAR(driver); +} diff --git a/tests/tap_hold_configurations/chordal_hold/permissive_hold/test_tap_hold.cpp b/tests/tap_hold_configurations/chordal_hold/permissive_hold/test_tap_hold.cpp index 1f89ab3eae4..19e73edb027 100644 --- a/tests/tap_hold_configurations/chordal_hold/permissive_hold/test_tap_hold.cpp +++ b/tests/tap_hold_configurations/chordal_hold/permissive_hold/test_tap_hold.cpp @@ -877,6 +877,7 @@ TEST_F(ChordalHoldPermissiveHold, roll_layer_tap_key_with_regular_key) { VERIFY_AND_CLEAR(driver); // Press regular key. + EXPECT_NO_REPORT(driver); regular_key.press(); run_one_scan_loop(); VERIFY_AND_CLEAR(driver); @@ -885,7 +886,6 @@ TEST_F(ChordalHoldPermissiveHold, roll_layer_tap_key_with_regular_key) { EXPECT_REPORT(driver, (KC_P)); EXPECT_REPORT(driver, (KC_P, KC_A)); EXPECT_REPORT(driver, (KC_A)); - EXPECT_NO_REPORT(driver); layer_tap_hold_key.release(); run_one_scan_loop(); VERIFY_AND_CLEAR(driver); @@ -896,3 +896,46 @@ TEST_F(ChordalHoldPermissiveHold, roll_layer_tap_key_with_regular_key) { run_one_scan_loop(); VERIFY_AND_CLEAR(driver); } + +TEST_F(ChordalHoldPermissiveHold, two_mod_tap_keys_stuttered_press) { + TestDriver driver; + InSequence s; + + auto mod_tap_key1 = KeymapKey(0, 1, 0, LSFT_T(KC_A)); + auto mod_tap_key2 = KeymapKey(0, 2, 0, LCTL_T(KC_B)); + + set_keymap({mod_tap_key1, mod_tap_key2}); + + // Hold first mod-tap key until the tapping term. + EXPECT_REPORT(driver, (KC_LSFT)); + mod_tap_key1.press(); + idle_for(TAPPING_TERM + 1); + VERIFY_AND_CLEAR(driver); + + // Press the second mod-tap key, then quickly release and press the first. + EXPECT_NO_REPORT(driver); + mod_tap_key2.press(); + run_one_scan_loop(); + mod_tap_key1.release(); + run_one_scan_loop(); + VERIFY_AND_CLEAR(driver); + + EXPECT_REPORT(driver, (KC_LSFT, KC_B)); + EXPECT_REPORT(driver, (KC_B)); + EXPECT_REPORT(driver, (KC_B, KC_A)); + mod_tap_key1.press(); + run_one_scan_loop(); + EXPECT_EQ(get_mods(), 0); // Verify that Shift was released. + VERIFY_AND_CLEAR(driver); + + // Release both keys. + EXPECT_REPORT(driver, (KC_A)); + mod_tap_key2.release(); + run_one_scan_loop(); + VERIFY_AND_CLEAR(driver); + + EXPECT_EMPTY_REPORT(driver); + mod_tap_key1.release(); + run_one_scan_loop(); + VERIFY_AND_CLEAR(driver); +}