diff --git a/docs/features/layer_lock.md b/docs/features/layer_lock.md index c2af5413a4c4..b6c1091ca55a 100644 --- a/docs/features/layer_lock.md +++ b/docs/features/layer_lock.md @@ -88,8 +88,9 @@ layer is locked or unlocked. This is useful to represent the current lock state for instance by setting an LED. In keymap.c, define ```c -void layer_lock_set_user(layer_state_t locked_layers) { +bool layer_lock_set_user(layer_state_t locked_layers) { // Do something like `set_led(is_layer_locked(NAV));` + return true; } ``` diff --git a/tests/layer_lock/test_layer_lock.cpp b/tests/layer_lock/test_layer_lock.cpp index f6f47dff206a..00742c3b4361 100644 --- a/tests/layer_lock/test_layer_lock.cpp +++ b/tests/layer_lock/test_layer_lock.cpp @@ -8,6 +8,62 @@ using testing::_; class LayerLock : public TestFixture {}; +TEST_F(LayerLock, LayerLockState) { + TestDriver driver; + KeymapKey key_a = KeymapKey(0, 0, 0, KC_A); + KeymapKey key_b = KeymapKey(1, 0, 0, KC_B); + KeymapKey key_c = KeymapKey(2, 0, 0, KC_C); + KeymapKey key_d = KeymapKey(3, 0, 0, KC_C); + + set_keymap({key_a, key_b, key_c, key_d}); + + EXPECT_FALSE(is_layer_locked(1)); + EXPECT_FALSE(is_layer_locked(2)); + EXPECT_FALSE(is_layer_locked(3)); + + layer_lock_invert(1); // Layer 1: unlocked -> locked + layer_lock_on(2); // Layer 2: unlocked -> locked + layer_lock_off(3); // Layer 3: stays unlocked + + // Layers 1 and 2 are now on. + EXPECT_TRUE(layer_state_is(1)); + EXPECT_TRUE(layer_state_is(2)); + // Layers 1 and 2 are now locked. + EXPECT_TRUE(is_layer_locked(1)); + EXPECT_TRUE(is_layer_locked(2)); + EXPECT_FALSE(is_layer_locked(3)); + + layer_lock_invert(1); // Layer 1: locked -> unlocked + layer_lock_on(2); // Layer 2: stays locked + layer_lock_on(3); // Layer 3: unlocked -> locked + + EXPECT_FALSE(layer_state_is(1)); + EXPECT_TRUE(layer_state_is(2)); + EXPECT_TRUE(layer_state_is(3)); + EXPECT_FALSE(is_layer_locked(1)); + EXPECT_TRUE(is_layer_locked(2)); + EXPECT_TRUE(is_layer_locked(3)); + + layer_lock_invert(1); // Layer 1: unlocked -> locked + layer_lock_off(2); // Layer 2: locked -> unlocked + + EXPECT_TRUE(layer_state_is(1)); + EXPECT_FALSE(layer_state_is(2)); + EXPECT_TRUE(layer_state_is(3)); + EXPECT_TRUE(is_layer_locked(1)); + EXPECT_FALSE(is_layer_locked(2)); + EXPECT_TRUE(is_layer_locked(3)); + + layer_lock_all_off(); // Layers 1 and 3: locked -> unlocked + + EXPECT_FALSE(layer_state_is(1)); + EXPECT_FALSE(layer_state_is(2)); + EXPECT_FALSE(layer_state_is(3)); + EXPECT_FALSE(is_layer_locked(1)); + EXPECT_FALSE(is_layer_locked(2)); + EXPECT_FALSE(is_layer_locked(3)); +} + TEST_F(LayerLock, LayerLockMomentaryTest) { TestDriver driver; KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1)); @@ -17,22 +73,32 @@ TEST_F(LayerLock, LayerLockMomentaryTest) { set_keymap({key_layer, key_a, key_trns, key_ll}); - /* Press Lower. */ EXPECT_NO_REPORT(driver); key_layer.press(); run_one_scan_loop(); EXPECT_TRUE(layer_state_is(1)); + EXPECT_FALSE(is_layer_locked(1)); VERIFY_AND_CLEAR(driver); EXPECT_NO_REPORT(driver); tap_key(key_ll); EXPECT_TRUE(layer_state_is(1)); + EXPECT_TRUE(is_layer_locked(1)); VERIFY_AND_CLEAR(driver); EXPECT_NO_REPORT(driver); key_layer.release(); run_one_scan_loop(); EXPECT_TRUE(layer_state_is(1)); + EXPECT_TRUE(is_layer_locked(1)); + VERIFY_AND_CLEAR(driver); + + // Pressing Layer Lock again unlocks the lock. + EXPECT_NO_REPORT(driver); + key_ll.press(); + run_one_scan_loop(); + EXPECT_FALSE(layer_state_is(1)); + EXPECT_FALSE(is_layer_locked(1)); VERIFY_AND_CLEAR(driver); } @@ -45,7 +111,6 @@ TEST_F(LayerLock, LayerLockLayerTapTest) { set_keymap({key_layer, key_a, key_trns, key_ll}); - /* Press Lower. */ EXPECT_NO_REPORT(driver); key_layer.press(); idle_for(TAPPING_TERM); @@ -56,6 +121,15 @@ TEST_F(LayerLock, LayerLockLayerTapTest) { EXPECT_NO_REPORT(driver); tap_key(key_ll); EXPECT_TRUE(layer_state_is(1)); + EXPECT_TRUE(is_layer_locked(1)); + VERIFY_AND_CLEAR(driver); + + // Pressing Layer Lock again unlocks the lock. + EXPECT_NO_REPORT(driver); + key_ll.press(); + run_one_scan_loop(); + EXPECT_FALSE(layer_state_is(1)); + EXPECT_FALSE(is_layer_locked(1)); VERIFY_AND_CLEAR(driver); } @@ -68,7 +142,6 @@ TEST_F(LayerLock, LayerLockOneshotTapTest) { set_keymap({key_layer, key_a, key_trns, key_ll}); - /* Press Lower. */ EXPECT_NO_REPORT(driver); tap_key(key_layer); run_one_scan_loop(); @@ -79,6 +152,15 @@ TEST_F(LayerLock, LayerLockOneshotTapTest) { tap_key(key_ll); run_one_scan_loop(); EXPECT_TRUE(layer_state_is(1)); + EXPECT_TRUE(is_layer_locked(1)); + VERIFY_AND_CLEAR(driver); + + // Pressing Layer Lock again unlocks the lock. + EXPECT_NO_REPORT(driver); + key_ll.press(); + run_one_scan_loop(); + EXPECT_FALSE(layer_state_is(1)); + EXPECT_FALSE(is_layer_locked(1)); VERIFY_AND_CLEAR(driver); } @@ -91,7 +173,6 @@ TEST_F(LayerLock, LayerLockOneshotHoldTest) { set_keymap({key_layer, key_a, key_trns, key_ll}); - /* Press Lower. */ EXPECT_NO_REPORT(driver); key_layer.press(); idle_for(TAPPING_TERM); @@ -109,6 +190,15 @@ TEST_F(LayerLock, LayerLockOneshotHoldTest) { key_layer.release(); run_one_scan_loop(); EXPECT_TRUE(layer_state_is(1)); + EXPECT_TRUE(is_layer_locked(1)); + VERIFY_AND_CLEAR(driver); + + // Pressing Layer Lock again unlocks the lock. + EXPECT_NO_REPORT(driver); + key_ll.press(); + run_one_scan_loop(); + EXPECT_FALSE(layer_state_is(1)); + EXPECT_FALSE(is_layer_locked(1)); VERIFY_AND_CLEAR(driver); } @@ -121,7 +211,6 @@ TEST_F(LayerLock, LayerLockTimeoutTest) { set_keymap({key_layer, key_a, key_trns, key_ll}); - /* Press Lower. */ EXPECT_NO_REPORT(driver); key_layer.press(); run_one_scan_loop(); @@ -137,11 +226,59 @@ TEST_F(LayerLock, LayerLockTimeoutTest) { key_layer.release(); run_one_scan_loop(); EXPECT_TRUE(layer_state_is(1)); + EXPECT_TRUE(is_layer_locked(1)); VERIFY_AND_CLEAR(driver); EXPECT_NO_REPORT(driver); idle_for(LAYER_LOCK_IDLE_TIMEOUT); run_one_scan_loop(); EXPECT_FALSE(layer_state_is(1)); + EXPECT_FALSE(is_layer_locked(1)); + VERIFY_AND_CLEAR(driver); +} + +TEST_F(LayerLock, ToKeyOverridesLayerLock) { + TestDriver driver; + KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1)); + KeymapKey key_to0 = KeymapKey(1, 0, 0, TO(0)); + KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK); + + set_keymap({key_layer, key_to0, key_ll}); + + EXPECT_NO_REPORT(driver); + layer_lock_on(1); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + EXPECT_TRUE(is_layer_locked(1)); + VERIFY_AND_CLEAR(driver); + + EXPECT_NO_REPORT(driver); + tap_key(key_to0); // TO(0) overrides Layer Lock and unlocks layer 1. + EXPECT_FALSE(layer_state_is(1)); + EXPECT_FALSE(is_layer_locked(1)); + VERIFY_AND_CLEAR(driver); +} + +TEST_F(LayerLock, LayerClearOverridesLayerLock) { + TestDriver driver; + KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1)); + KeymapKey key_a = KeymapKey(0, 1, 0, KC_A); + KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK); + + set_keymap({key_layer, key_a, key_ll}); + + EXPECT_NO_REPORT(driver); + layer_lock_on(1); + run_one_scan_loop(); + EXPECT_TRUE(layer_state_is(1)); + EXPECT_TRUE(is_layer_locked(1)); + VERIFY_AND_CLEAR(driver); + + EXPECT_REPORT(driver, (KC_A)); + layer_clear(); // layer_clear() overrides Layer Lock and unlocks layer 1. + key_a.press(); + run_one_scan_loop(); + EXPECT_FALSE(layer_state_is(1)); + EXPECT_FALSE(is_layer_locked(1)); VERIFY_AND_CLEAR(driver); }