qmk / qmk_firmware

Open-source keyboard firmware for Atmel AVR and Arm USB families
https://qmk.fm
GNU General Public License v2.0
18.07k stars 38.83k forks source link

[Bug] SH_T Swap-hands action produces extra tap depending on timing #24410

Open ilikeheaps opened 1 week ago

ilikeheaps commented 1 week ago

I have r key mirrored to i. Quick SH_T(KC_SPC) + r combination results in i while doing it slowly results in i as expected. Logs below contain both cases in order.

ilikeheaps:plyboard:1: ---- action_exec: start -----
ilikeheaps:plyboard:1: EVENT: 0305d(21482)
ilikeheaps:plyboard:1: Tapping: Start(Press tap key).
ilikeheaps:plyboard:1: TAPPING_KEY=0305d(21482):0 
ilikeheaps:plyboard:1: processed: 0305d(21482):0 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: ---- action_exec: start -----
ilikeheaps:plyboard:1: EVENT: 0102d(21553)
ilikeheaps:plyboard:1: waiting_buffer_enq: { [7]=0602d(21553):0  }
ilikeheaps:plyboard:1: ---- action_exec: process waiting_buffer -----
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: ---- action_exec: start -----
ilikeheaps:plyboard:1: EVENT: 0305u(21590)
ilikeheaps:plyboard:1: Tapping: First tap(0->1).
ilikeheaps:plyboard:1: TAPPING_KEY=0305d(21482):1-
ilikeheaps:plyboard:1: ACTION: ACT_SWAP_HANDS[0:2C] layer_state:  default_layer_state: 
ilikeheaps:plyboard:1: keyboard_report: 00 | 2C 00 00 00 00 00 
ilikeheaps:plyboard:1: waiting_buffer_enq: { [7]=0602d(21553):0  [0]=0305u(21590):1- }
ilikeheaps:plyboard:1: ---- action_exec: process waiting_buffer -----
ilikeheaps:plyboard:1: Tapping: key event while last tap(>0).
ilikeheaps:plyboard:1: ACTION: ACT_LMODS[0:0F] layer_state:  default_layer_state: 
ilikeheaps:plyboard:1: keyboard_report: 00 | 2C 0F 00 00 00 00 
ilikeheaps:plyboard:1: processed: waiting_buffer[7] =0602d(21553):0 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: Tapping: Tap release(1)
ilikeheaps:plyboard:1: ACTION: ACT_SWAP_HANDS[0:2C] layer_state:  default_layer_state: 
ilikeheaps:plyboard:1: keyboard_report: 00 | 00 0F 00 00 00 00 
ilikeheaps:plyboard:1: TAPPING_KEY=0000u(0):0 
ilikeheaps:plyboard:1: processed: waiting_buffer[0] =0000u(0):0 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: ---- action_exec: start -----
ilikeheaps:plyboard:1: EVENT: 0102u(21626)
ilikeheaps:plyboard:1: ACTION: ACT_LMODS[0:0F] layer_state:  default_layer_state: 
ilikeheaps:plyboard:1: keyboard_report: 00 | 00 00 00 00 00 00 
ilikeheaps:plyboard:1: processed: 0602u(21626):0 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: ---- action_exec: start -----
ilikeheaps:plyboard:1: EVENT: 0305d(23288)
ilikeheaps:plyboard:1: Tapping: Start(Press tap key).
ilikeheaps:plyboard:1: TAPPING_KEY=0305d(23288):0 
ilikeheaps:plyboard:1: processed: 0305d(23288):0 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: Tapping: End. Timeout. Not tap(0): 0000u(23488)
ilikeheaps:plyboard:1: ACTION: ACT_SWAP_HANDS[0:2C] layer_state:  default_layer_state: 
ilikeheaps:plyboard:1: TAPPING_KEY=0000u(0):0 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: ---- action_exec: start -----
ilikeheaps:plyboard:1: EVENT: 0102d(23572)
ilikeheaps:plyboard:1: ACTION: ACT_LMODS[0:0F] layer_state:  default_layer_state: 
ilikeheaps:plyboard:1: keyboard_report: 00 | 0F 00 00 00 00 00 
ilikeheaps:plyboard:1: processed: 0602d(23572):0 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: ---- action_exec: start -----
ilikeheaps:plyboard:1: EVENT: 0102u(23798)
ilikeheaps:plyboard:1: ACTION: ACT_LMODS[0:0F] layer_state:  default_layer_state: 
ilikeheaps:plyboard:1: keyboard_report: 00 | 00 00 00 00 00 00 
ilikeheaps:plyboard:1: processed: 0602u(23798):0 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: 
ilikeheaps:plyboard:1: ---- action_exec: start -----
ilikeheaps:plyboard:1: EVENT: 0305u(23843)
ilikeheaps:plyboard:1: ACTION: ACT_SWAP_HANDS[0:2C] layer_state:  default_layer_state: 
ilikeheaps:plyboard:1: processed: 0305u(23843):0 
ilikeheaps commented 1 week ago

I tried making a simple test for it (dirty copying other tests) but can’t get hands swap setup to work in the test yet. Pasting patch here rather than draft PR because I’m having some issues with ssh setup (and GitHub somehow doesn't accept patch files as attachments).

diff --git a/tests/swap_hands/config.h b/tests/swap_hands/config.h
new file mode 100644
index 0000000000..76578428a7
--- /dev/null
+++ b/tests/swap_hands/config.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "test_common.h"
+
+#define ACTION_DEBUG
diff --git a/tests/swap_hands/test.cpp b/tests/swap_hands/test.cpp
new file mode 100644
index 0000000000..991a9d215a
--- /dev/null
+++ b/tests/swap_hands/test.cpp
@@ -0,0 +1,41 @@
+#include "action_util.h"
+#include "keyboard_report_util.hpp"
+#include "test_common.hpp"
+
+using testing::_;
+using testing::InSequence;
+
+class SH : public TestFixture {};
+class SHParametrizedTestFixture : public ::testing::WithParamInterface<std::pair<KeymapKey, KeymapKey>>, public SH {};
+
+const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
+  {{0, 0}, {0, 2}, {0, 1}}
+};
+
+TEST_F(SH, Dummy) {
+    TestDriver driver;
+    auto       key_sh_t = KeymapKey(0, 0, 0, SH_T(KC_SPACE));
+    auto       key_a = KeymapKey(0, 0, 1, KC_A);
+    auto       key_b = KeymapKey(0, 0, 2, KC_B);
+
+    set_keymap({key_sh_t, key_a, key_b});
+
+    debug_enable = true;
+    debug_keyboard = true;
+
+    key_sh_t.press();
+    idle_for(722);
+    assert(is_swap_hands_on());
+    printf("pre\n");
+    key_a.press();
+    idle_for(3);
+    printf("post\n");
+    keyboard_task();
+    EXPECT_REPORT(driver, (key_b.report_code)); // somehow SH_T registers a tap instead
+    key_sh_t.release();
+    keyboard_task();
+    key_a.release();
+    
+    EXPECT_EMPTY_REPORT(driver);
+    keyboard_task();
+}
diff --git a/tests/swap_hands/test.mk b/tests/swap_hands/test.mk
new file mode 100644
index 0000000000..f3f730c6ad
--- /dev/null
+++ b/tests/swap_hands/test.mk
@@ -0,0 +1,2 @@
+SWAP_HANDS_ENABLE = yes
+CONSOLE_ENABLE = yes
ilikeheaps commented 1 week ago

Oh, found the problem. Mixed col/row order in two places so it avoided an obvious error and unexpectedly mapped A to SH_T. So basic case works now and I will try to reproduce my issue.

ilikeheaps commented 1 week ago

Alright, this seems to reproduce my issue:

diff --git a/tests/swap_hands/config.h b/tests/swap_hands/config.h
new file mode 100644
index 0000000000..76578428a7
--- /dev/null
+++ b/tests/swap_hands/config.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "test_common.h"
+
+#define ACTION_DEBUG
diff --git a/tests/swap_hands/test.cpp b/tests/swap_hands/test.cpp
new file mode 100644
index 0000000000..92d0c86920
--- /dev/null
+++ b/tests/swap_hands/test.cpp
@@ -0,0 +1,66 @@
+#include "action_util.h"
+#include "keyboard_report_util.hpp"
+#include "test_common.hpp"
+
+using testing::_;
+using testing::InSequence;
+
+class SH : public TestFixture {};
+class SHParametrizedTestFixture : public ::testing::WithParamInterface<std::pair<KeymapKey, KeymapKey>>, public SH {};
+
+// XXX hand_swap_config[row][column] -> column, row
+const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
+  {{0, 0}, {2, 0}, {1, 0}}
+};
+
+// works
+TEST_F(SH, SwapHandsTapLongHoldSwaps) {
+    TestDriver driver;
+    auto       key_sh_t = KeymapKey(0, 0, 0, SH_T(KC_SPACE));
+    auto       key_a = KeymapKey(0, 1, 0, KC_A);
+    auto       key_b = KeymapKey(0, 2, 0, KC_B);
+
+    set_keymap({key_sh_t, key_a, key_b});
+
+    debug_enable = true;
+    debug_keyboard = true;
+
+    key_sh_t.press();
+    idle_for(211);
+    assert(is_swap_hands_on());
+    key_a.press();
+    EXPECT_REPORT(driver, (key_b.report_code));
+    idle_for(1);
+    key_sh_t.release();
+    idle_for(1);
+    key_a.release();
+    
+    EXPECT_EMPTY_REPORT(driver);
+    keyboard_task();
+}
+
+// fails
+TEST_F(SH, SwapHandsTapShortHoldSwaps) {
+    TestDriver driver;
+    auto       key_sh_t = KeymapKey(0, 0, 0, SH_T(KC_SPACE));
+    auto       key_a = KeymapKey(0, 1, 0, KC_A);
+    auto       key_b = KeymapKey(0, 2, 0, KC_B);
+
+    set_keymap({key_sh_t, key_a, key_b});
+
+    debug_enable = true;
+    debug_keyboard = true;
+
+    key_sh_t.press();
+    idle_for(1);
+    assert(is_swap_hands_on());
+    key_a.press();
+    EXPECT_REPORT(driver, (key_b.report_code));
+    idle_for(1);
+    key_sh_t.release();
+    idle_for(1);
+    key_a.release();
+
+    EXPECT_EMPTY_REPORT(driver);
+    keyboard_task();
+}
diff --git a/tests/swap_hands/test.mk b/tests/swap_hands/test.mk
new file mode 100644
index 0000000000..f3f730c6ad
--- /dev/null
+++ b/tests/swap_hands/test.mk
@@ -0,0 +1,2 @@
+SWAP_HANDS_ENABLE = yes
+CONSOLE_ENABLE = yes
ilikeheaps commented 1 week ago

Oh right, I could paste test output here (with some mysterious debug prints):

[nix-shell:~/mnt/by-label/tmp-transfer-bkp/messy/qmk_firmware]$ make test:swap_hands
QMK Firmware 0.26.4
Making test swap_hands

gcc (GCC) 13.2.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Compiling: tests/swap_hands/test.cpp                                                                [OK]
Linking: .build/test/swap_hands.elf                                                                 [OK]
Testing swap_hands
[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from SH
default_layer_state: 00000001(0) to 00000001(0)
[ RUN      ] SH.SwapHandsTapLongHoldSwaps

---- action_exec: start -----
EVENT: 0000d(0)
hello
yes?
0 0 1 0 sh 0
Tapping: Start(Press tap key).
toggle
TAPPING_KEY=0000d(0):0 
processed: 0000d(0):0 

Tapping: End. Timeout. Not tap(0): 0000u(200)
ACTION: ACT_SWAP_HANDS[0:2C] layer_state: 00000000(0) default_layer_state: 00000001(0)
TAPPING_KEY=0000u(0):0 

---- action_exec: start -----
EVENT: 0001d(211)
hello
yes?
1 0 1 1 sh 1
yes
ACTION: ACT_LMODS[0:05] layer_state: 00000000(0) default_layer_state: 00000001(0)
keyboard_report: 00 | 05 00 00 00 00 00 
processed: 0002d(211):0 

---- action_exec: start -----
EVENT: 0000u(212)
hello
yes?
0 0 0 0 sh 1
ACTION: ACT_SWAP_HANDS[0:2C] layer_state: 00000000(0) default_layer_state: 00000001(0)
toggle
processed: 0000u(212):0 

---- action_exec: start -----
EVENT: 0001u(213)
hello
yes?
1 0 0 1 sh 0
yes
ACTION: ACT_LMODS[0:05] layer_state: 00000000(0) default_layer_state: 00000001(0)
keyboard_report: 00 | 00 00 00 00 00 00 
processed: 0002u(213):0 

layer_state: 00000000(0) to 00000000(0)
[       OK ] SH.SwapHandsTapLongHoldSwaps (0 ms)
[ RUN      ] SH.SwapHandsTapShortHoldSwaps

---- action_exec: start -----
EVENT: 0000d(0)
hello
yes?
0 0 1 0 sh 0
Tapping: Start(Press tap key).
toggle
TAPPING_KEY=0000d(0):0 
processed: 0000d(0):0 

---- action_exec: start -----
EVENT: 0001d(1)
hello
yes?
1 0 1 1 sh 1
yes
waiting_buffer_enq: { [0]=0002d(1):0  }
---- action_exec: process waiting_buffer -----

---- action_exec: start -----
EVENT: 0000u(2)
hello
yes?
0 0 0 0 sh 1
Tapping: First tap(0->1).
TAPPING_KEY=0000d(0):1-
ACTION: ACT_SWAP_HANDS[0:2C] layer_state: 00000000(0) default_layer_state: 00000001(0)
toggle
unknown file: Failure

Unexpected mock function call - returning directly.
    Function call: send_keyboard_mock(@0x46d0d8 report:   (KC_SPACE) []
)
Google Mock tried the following 1 expectation, but it didn't match:

tests/swap_hands/test.cpp:58: EXPECT_CALL((driver), send_keyboard_mock(KeyboardReport (key_b.report_code)))...
  Expected arg #0: is equal to report:   (KC_B) []

           Actual: report:   (KC_SPACE) []

         Expected: to be called once
           Actual: never called - unsatisfied and active
keyboard_report: 00 | 2C 00 00 00 00 00 
waiting_buffer_enq: { [0]=0002d(1):0  [1]=0000u(2):1- }
---- action_exec: process waiting_buffer -----
Tapping: key event while last tap(>0).
ACTION: ACT_LMODS[0:05] layer_state: 00000000(0) default_layer_state: 00000001(0)
unknown file: Failure

Unexpected mock function call - returning directly.
    Function call: send_keyboard_mock(@0x46d0d8 report:   (KC_B, KC_SPACE) []
)
Google Mock tried the following 1 expectation, but it didn't match:

tests/swap_hands/test.cpp:58: EXPECT_CALL((driver), send_keyboard_mock(KeyboardReport (key_b.report_code)))...
  Expected arg #0: is equal to report:   (KC_B) []

           Actual: report:   (KC_B, KC_SPACE) []

         Expected: to be called once
           Actual: never called - unsatisfied and active
keyboard_report: 00 | 2C 05 00 00 00 00 
processed: waiting_buffer[0] =0002d(1):0 

Tapping: Tap release(1)
ACTION: ACT_SWAP_HANDS[0:2C] layer_state: 00000000(0) default_layer_state: 00000001(0)
keyboard_report: 00 | 00 05 00 00 00 00 
TAPPING_KEY=0000u(0):0 
processed: waiting_buffer[1] =0000u(0):0 

---- action_exec: start -----
EVENT: 0001u(3)
hello
yes?
1 0 0 1 sh 0
yes
ACTION: ACT_LMODS[0:05] layer_state: 00000000(0) default_layer_state: 00000001(0)
keyboard_report: 00 | 00 00 00 00 00 00 
processed: 0002u(3):0 

layer_state: 00000000(0) to 00000000(0)
SH.SwapHandsTapShortHoldSwaps failed!
[ LEVEL    ] [TIME] [EVENT]
[ INFO     ] 0      tapping term is 200ms
[ TRACE    ] 0      pressed:  unknown keycode: 0x562c. Add conversion to generate_identifier
[ TRACE    ] 0      1 keyboard task loop
[ TRACE    ] 1      pressed:  KC_A
[ TRACE    ] 1      1 keyboard task loop
[ TRACE    ] 2      released: unknown keycode: 0x562c. Add conversion to generate_identifier was pressed for 2ms
[ TRACE    ] 2      1 keyboard task loop
[ TRACE    ] 2      report:   (KC_SPACE) []
[ TRACE    ] 2      report:   (KC_B, KC_SPACE) []
[ TRACE    ] 2      report:   (KC_B) []
[ TRACE    ] 3      released: KC_A was pressed for 2ms
[ TRACE    ] 3      report:   empty
[ INFO     ] 3      test fixture clean-up start.
[ TRACE    ] 3      2000 keyboard task loops
[ TRACE    ] 2003   2000 keyboard task loops
[ INFO     ] 4003   test fixture clean-up end.
[  FAILED  ] SH.SwapHandsTapShortHoldSwaps (0 ms)
[----------] 2 tests from SH (0 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] SH.SwapHandsTapShortHoldSwaps

 1 FAILED TEST

Make finished with errors
make: *** [Makefile:417: test:swap_hands] Error 1

Edit: mixed up revisions

ilikeheaps commented 1 week ago

Okay, found the (edit: an?) issue: I should read the manual and use PERMISSIVE_HOLD. Well, I did read it but didn't notice different tapping modes when reading about swap-hands and one shot modifiers. I assumed PERMISSIVE_HOLD behaviour when reading keys descriptions:

The Mod-Tap key MT(mod, kc) acts like a modifier when held, and a regular keycode when tapped. In other words, you can have a key that sends Escape when you tap it, but functions as a Control or Shift key when you hold it down.

SH_T(kc) -- Momentary swap when held, kc when tapped

Anyway:

  1. SH_T still breaks the description - it works as both SH toggle and tap in the same press
  2. I didn't find tests for swap-hands, would anyone like to see PR with mine after I fix their configuration?
ilikeheaps commented 1 week ago

I've set PERMISSIVE_HOLD for my keyboard but I am still having issues. Perhaps I will try to refine tests to isolate the problem.

ilikeheaps commented 1 week ago

Another issue I found is that tapping OSM breaks subsequent SH_T (with HOLD_ON_OTHER_KEY_PRESS).

TEST_F(SH, SwapHandsAfterOSM) {
    TestDriver driver;
    auto       key_sh_t = KeymapKey(0, 0, 0, SH_T(KC_SPACE));
    auto       key_a = KeymapKey(0, 1, 0, KC_A);
    auto       key_b = KeymapKey(0, 2, 0, KC_B);
    auto       key_m = KeymapKey(0, 3, 0, OSM(MOD_LSFT));

    set_keymap({key_sh_t, key_a, key_b, key_m});

    debug_enable = true;
    debug_keyboard = true;

    key_m.press();
    idle_for(1);
    key_m.release();
    idle_for(1);
    key_sh_t.press();
    idle_for(1);
    key_a.press();
    EXPECT_REPORT(driver, (key_b.report_code, KC_LEFT_SHIFT));
    idle_for(1);
    key_sh_t.release();
    idle_for(1);
    key_a.release();

    EXPECT_EMPTY_REPORT(driver);
    keyboard_task();
}

results in

...
[       OK ] SH.SwapHandsTapShortHoldSwaps (0 ms)
[ RUN      ] SH.SwapHandsAfterOSM

---- action_exec: start -----
EVENT: 0003d(0)
Tapping: Start(Press tap key).
TAPPING_KEY=0003d(0):0 
processed: 0003d(0):0 

---- action_exec: start -----
EVENT: 0003u(1)
Tapping: First tap(0->1).
TAPPING_KEY=0003d(0):1 
ACTION: ACT_LMODS_TAP[2:00] layer_state: 00000000(0) default_layer_state: 00000001(0)
MODS_TAP: Oneshot: start
waiting_buffer_enq: { [1]=0003u(1):1  }
---- action_exec: process waiting_buffer -----
Tapping: Tap release(1)
ACTION: ACT_LMODS_TAP[2:00] layer_state: 00000000(0) default_layer_state: 00000001(0)
TAPPING_KEY=0003u(1):1 
processed: waiting_buffer[1] =0003u(1):1 

---- action_exec: start -----
EVENT: 0000d(2)
Tapping: Start with interfering other tap.
TAPPING_KEY=0000d(2):0 
processed: 0000d(2):0 

---- action_exec: start -----
EVENT: 0001d(3)
Tapping: End. No tap. Interfered by pressed key
ACTION: ACT_SWAP_HANDS[0:2C] layer_state: 00000000(0) default_layer_state: 00000001(0)
TAPPING_KEY=0000u(0):0 
waiting_buffer_enq: { [2]=0001d(3):0  }
---- action_exec: process waiting_buffer -----
ACTION: ACT_LMODS[0:04] layer_state: 00000000(0) default_layer_state: 00000001(0)
unknown file: Failure

Unexpected mock function call - returning directly.
    Function call: send_keyboard_mock(@0x46e0d8 report:   (KC_A) [KC_LEFT_SHIFT]
)
Google Mock tried the following 1 expectation, but it didn't match:

tests/swap_hands/test.cpp:86: EXPECT_CALL((driver), send_keyboard_mock(KeyboardReport (key_b.report_code, KC_LEFT_SHIFT)))...
  Expected arg #0: is equal to report:   (KC_B) [KC_LEFT_SHIFT]

           Actual: report:   (KC_A) [KC_LEFT_SHIFT]

         Expected: to be called once
           Actual: never called - unsatisfied and active
keyboard_report: 02 | 04 00 00 00 00 00 
processed: waiting_buffer[2] =0001d(3):0 

---- action_exec: start -----
EVENT: 0000u(4)
ACTION: ACT_SWAP_HANDS[0:2C] layer_state: 00000000(0) default_layer_state: 00000001(0)
processed: 0000u(4):0 

---- action_exec: start -----
EVENT: 0001u(5)
ACTION: ACT_LMODS[0:04] layer_state: 00000000(0) default_layer_state: 00000001(0)
keyboard_report: 00 | 00 00 00 00 00 00 
processed: 0001u(5):0 

tests/swap_hands/test.cpp:86: Failure
Actual function call count doesn't match EXPECT_CALL((driver), send_keyboard_mock(KeyboardReport (key_b.report_code, KC_LEFT_SHIFT)))...
         Expected: to be called once
           Actual: never called - unsatisfied and active
layer_state: 00000000(0) to 00000000(0)
SH.SwapHandsAfterOSM failed!
[ LEVEL    ] [TIME] [EVENT]
[ INFO     ] 0      tapping term is 200ms
[ TRACE    ] 0      pressed:  OSM(MOD_LSFT)
[ TRACE    ] 0      1 keyboard task loop
[ TRACE    ] 1      released: OSM(MOD_LSFT) was pressed for 1ms
[ TRACE    ] 1      1 keyboard task loop
[ TRACE    ] 2      pressed:  unknown keycode: 0x562c. Add conversion to generate_identifier
[ TRACE    ] 2      1 keyboard task loop
[ TRACE    ] 3      pressed:  KC_A
[ TRACE    ] 3      1 keyboard task loop
[ TRACE    ] 3      report:   (KC_A) [KC_LEFT_SHIFT]
[ TRACE    ] 4      released: unknown keycode: 0x562c. Add conversion to generate_identifier was pressed for 2ms
[ TRACE    ] 4      1 keyboard task loop
[ TRACE    ] 5      released: KC_A was pressed for 2ms
[ TRACE    ] 5      report:   empty
[ INFO     ] 5      test fixture clean-up start.
[ TRACE    ] 5      2000 keyboard task loops
[ TRACE    ] 2005   2000 keyboard task loops
[ INFO     ] 4005   test fixture clean-up end.
[  FAILED  ] SH.SwapHandsAfterOSM (0 ms)
[----------] 3 tests from SH (0 ms total)

[----------] Global test environment tear-down
[==========] 3 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 2 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] SH.SwapHandsAfterOSM

 1 FAILED TEST
ilikeheaps commented 1 week ago

Posted my tests (one failing, bug or wrong assumptions?) in https://github.com/qmk/qmk_firmware/pull/24420