qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

test_tap_hold.cpp (7803B)


      1 // Copyright 2024 Google LLC
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "keyboard_report_util.hpp"
     16 #include "keycode.h"
     17 #include "test_common.hpp"
     18 #include "action_tapping.h"
     19 #include "test_fixture.hpp"
     20 #include "test_keymap_key.hpp"
     21 
     22 using testing::_;
     23 using testing::InSequence;
     24 
     25 class ChordalHoldDefault : public TestFixture {};
     26 
     27 TEST_F(ChordalHoldDefault, chord_nested_press_settled_as_tap) {
     28     TestDriver driver;
     29     InSequence s;
     30     // Mod-tap key on the left hand.
     31     auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
     32     // Regular key on the right hand.
     33     auto regular_key = KeymapKey(0, MATRIX_COLS - 1, 0, KC_A);
     34 
     35     set_keymap({mod_tap_key, regular_key});
     36 
     37     // Press mod-tap key.
     38     EXPECT_NO_REPORT(driver);
     39     mod_tap_key.press();
     40     run_one_scan_loop();
     41     // Tap regular key.
     42     tap_key(regular_key);
     43     VERIFY_AND_CLEAR(driver);
     44 
     45     // Release mod-tap key.
     46     EXPECT_REPORT(driver, (KC_P));
     47     EXPECT_REPORT(driver, (KC_P, KC_A));
     48     EXPECT_REPORT(driver, (KC_P));
     49     EXPECT_EMPTY_REPORT(driver);
     50     mod_tap_key.release();
     51     run_one_scan_loop();
     52     VERIFY_AND_CLEAR(driver);
     53 }
     54 
     55 TEST_F(ChordalHoldDefault, chord_rolled_press_settled_as_tap) {
     56     TestDriver driver;
     57     InSequence s;
     58     // Mod-tap key on the left hand.
     59     auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
     60     // Regular key on the right hand.
     61     auto regular_key = KeymapKey(0, MATRIX_COLS - 1, 0, KC_A);
     62 
     63     set_keymap({mod_tap_key, regular_key});
     64 
     65     // Press mod-tap key and regular key.
     66     EXPECT_NO_REPORT(driver);
     67     mod_tap_key.press();
     68     run_one_scan_loop();
     69     regular_key.press();
     70     run_one_scan_loop();
     71     VERIFY_AND_CLEAR(driver);
     72 
     73     // Release mod-tap key.
     74     EXPECT_REPORT(driver, (KC_P));
     75     EXPECT_REPORT(driver, (KC_P, KC_A));
     76     EXPECT_REPORT(driver, (KC_A));
     77     mod_tap_key.release();
     78     run_one_scan_loop();
     79     VERIFY_AND_CLEAR(driver);
     80 
     81     // Release regular key.
     82     EXPECT_EMPTY_REPORT(driver);
     83     regular_key.release();
     84     run_one_scan_loop();
     85     VERIFY_AND_CLEAR(driver);
     86 }
     87 
     88 TEST_F(ChordalHoldDefault, non_chord_with_mod_tap_settled_as_tap) {
     89     TestDriver driver;
     90     InSequence s;
     91     // Mod-tap key and regular key both on the left hand.
     92     auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
     93     auto regular_key = KeymapKey(0, 2, 0, KC_A);
     94 
     95     set_keymap({mod_tap_key, regular_key});
     96 
     97     // Press mod-tap-hold key.
     98     EXPECT_NO_REPORT(driver);
     99     mod_tap_key.press();
    100     run_one_scan_loop();
    101     VERIFY_AND_CLEAR(driver);
    102 
    103     // Press regular key.
    104     EXPECT_REPORT(driver, (KC_P));
    105     EXPECT_REPORT(driver, (KC_P, KC_A));
    106     regular_key.press();
    107     run_one_scan_loop();
    108     VERIFY_AND_CLEAR(driver);
    109 
    110     // Release regular key.
    111     EXPECT_REPORT(driver, (KC_P));
    112     regular_key.release();
    113     run_one_scan_loop();
    114     VERIFY_AND_CLEAR(driver);
    115 
    116     // Release mod-tap-hold key.
    117     EXPECT_EMPTY_REPORT(driver);
    118     mod_tap_key.release();
    119     run_one_scan_loop();
    120     VERIFY_AND_CLEAR(driver);
    121 }
    122 
    123 TEST_F(ChordalHoldDefault, tap_mod_tap_key) {
    124     TestDriver driver;
    125     InSequence s;
    126     auto       mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
    127 
    128     set_keymap({mod_tap_key});
    129 
    130     EXPECT_NO_REPORT(driver);
    131     mod_tap_key.press();
    132     idle_for(TAPPING_TERM - 1);
    133     VERIFY_AND_CLEAR(driver);
    134 
    135     EXPECT_REPORT(driver, (KC_P));
    136     EXPECT_EMPTY_REPORT(driver);
    137     mod_tap_key.release();
    138     run_one_scan_loop();
    139     VERIFY_AND_CLEAR(driver);
    140 }
    141 
    142 TEST_F(ChordalHoldDefault, hold_mod_tap_key) {
    143     TestDriver driver;
    144     InSequence s;
    145     auto       mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P));
    146 
    147     set_keymap({mod_tap_key});
    148 
    149     EXPECT_REPORT(driver, (KC_LEFT_SHIFT));
    150     mod_tap_key.press();
    151     idle_for(TAPPING_TERM + 1);
    152     VERIFY_AND_CLEAR(driver);
    153 
    154     EXPECT_EMPTY_REPORT(driver);
    155     mod_tap_key.release();
    156     run_one_scan_loop();
    157     VERIFY_AND_CLEAR(driver);
    158 }
    159 
    160 TEST_F(ChordalHoldDefault, two_mod_taps_same_hand_hold_til_timeout) {
    161     TestDriver driver;
    162     InSequence s;
    163     auto       mod_tap_key1 = KeymapKey(0, MATRIX_COLS - 2, 0, RCTL_T(KC_A));
    164     auto       mod_tap_key2 = KeymapKey(0, MATRIX_COLS - 1, 0, RSFT_T(KC_B));
    165 
    166     set_keymap({mod_tap_key1, mod_tap_key2});
    167 
    168     // Press mod-tap keys.
    169     EXPECT_NO_REPORT(driver);
    170     mod_tap_key1.press();
    171     run_one_scan_loop();
    172     mod_tap_key2.press();
    173     run_one_scan_loop();
    174     VERIFY_AND_CLEAR(driver);
    175 
    176     // Continue holding til the tapping term.
    177     EXPECT_REPORT(driver, (KC_RIGHT_CTRL));
    178     EXPECT_REPORT(driver, (KC_RIGHT_CTRL, KC_RIGHT_SHIFT));
    179     idle_for(TAPPING_TERM);
    180     VERIFY_AND_CLEAR(driver);
    181 
    182     // Release mod-tap keys.
    183     EXPECT_REPORT(driver, (KC_RIGHT_SHIFT));
    184     mod_tap_key1.release();
    185     run_one_scan_loop();
    186     VERIFY_AND_CLEAR(driver);
    187 
    188     EXPECT_EMPTY_REPORT(driver);
    189     mod_tap_key2.release();
    190     run_one_scan_loop();
    191     VERIFY_AND_CLEAR(driver);
    192 }
    193 
    194 TEST_F(ChordalHoldDefault, three_mod_taps_same_hand_streak_roll) {
    195     TestDriver driver;
    196     InSequence s;
    197     auto       mod_tap_key1 = KeymapKey(0, 1, 0, SFT_T(KC_A));
    198     auto       mod_tap_key2 = KeymapKey(0, 2, 0, CTL_T(KC_B));
    199     auto       mod_tap_key3 = KeymapKey(0, 3, 0, RSFT_T(KC_C));
    200 
    201     set_keymap({mod_tap_key1, mod_tap_key2, mod_tap_key3});
    202 
    203     // Press mod-tap keys.
    204     EXPECT_NO_REPORT(driver);
    205     mod_tap_key1.press();
    206     run_one_scan_loop();
    207     mod_tap_key2.press();
    208     run_one_scan_loop();
    209     mod_tap_key3.press();
    210     run_one_scan_loop();
    211     VERIFY_AND_CLEAR(driver);
    212 
    213     // Release keys 1, 2, 3.
    214     //
    215     // NOTE: The correct order of events should be
    216     // EXPECT_REPORT(driver, (KC_A, KC_B, KC_C));
    217     // EXPECT_REPORT(driver, (KC_B, KC_C));
    218     // EXPECT_REPORT(driver, (KC_C));
    219     // EXPECT_EMPTY_REPORT(driver);
    220     //
    221     // However, due to a workaround for https://github.com/tmk/tmk_keyboard/issues/60,
    222     // the events are processed out of order, with the first two keys released
    223     // before pressing KC_C.
    224     EXPECT_REPORT(driver, (KC_A));
    225     EXPECT_REPORT(driver, (KC_A, KC_B));
    226     EXPECT_REPORT(driver, (KC_B));
    227     EXPECT_EMPTY_REPORT(driver);
    228     EXPECT_REPORT(driver, (KC_C));
    229     EXPECT_EMPTY_REPORT(driver);
    230     mod_tap_key1.release();
    231     run_one_scan_loop();
    232     mod_tap_key2.release();
    233     run_one_scan_loop();
    234     mod_tap_key3.release();
    235     run_one_scan_loop();
    236     VERIFY_AND_CLEAR(driver);
    237 }
    238 
    239 TEST_F(ChordalHoldDefault, tap_regular_key_while_layer_tap_key_is_held) {
    240     TestDriver driver;
    241     InSequence s;
    242     auto       layer_tap_hold_key = KeymapKey(0, 1, 0, LT(1, KC_P));
    243     auto       regular_key        = KeymapKey(0, MATRIX_COLS - 1, 0, KC_A);
    244     auto       layer_key          = KeymapKey(1, MATRIX_COLS - 1, 0, KC_B);
    245 
    246     set_keymap({layer_tap_hold_key, regular_key, layer_key});
    247 
    248     EXPECT_NO_REPORT(driver);
    249     layer_tap_hold_key.press(); // Press layer-tap-hold key.
    250     run_one_scan_loop();
    251     regular_key.press(); // Press regular key.
    252     run_one_scan_loop();
    253     regular_key.release(); // Release regular key.
    254     run_one_scan_loop();
    255     VERIFY_AND_CLEAR(driver);
    256 
    257     EXPECT_REPORT(driver, (KC_P));
    258     EXPECT_REPORT(driver, (KC_P, KC_A));
    259     EXPECT_REPORT(driver, (KC_P));
    260     EXPECT_EMPTY_REPORT(driver);
    261     layer_tap_hold_key.release(); // Release layer-tap-hold key.
    262     run_one_scan_loop();
    263     VERIFY_AND_CLEAR(driver);
    264 }