@@ -320,6 +320,30 @@ namespace {
320320 return report;
321321 }
322322
323+ template <typename Predicate>
324+ std::optional<std::vector<std::uint8_t >> read_hid_report_matching (
325+ HANDLE hid,
326+ std::size_t report_size,
327+ std::chrono::milliseconds timeout,
328+ Predicate predicate
329+ ) {
330+ const auto deadline = std::chrono::steady_clock::now () + timeout;
331+ while (std::chrono::steady_clock::now () < deadline) {
332+ const auto remaining = std::chrono::duration_cast<std::chrono::milliseconds>(
333+ deadline - std::chrono::steady_clock::now ()
334+ );
335+ auto report = read_hid_report_with_timeout (hid, report_size, std::max (remaining, 1ms));
336+ if (!report.has_value ()) {
337+ return std::nullopt ;
338+ }
339+ if (predicate (*report)) {
340+ return report;
341+ }
342+ }
343+
344+ return std::nullopt ;
345+ }
346+
323347 HidInterfacePaths current_gamepad_interface_paths () {
324348 HidInterfacePaths paths;
325349 for (const auto &hid_interface : enumerate_gamepad_interfaces ()) {
@@ -780,7 +804,14 @@ TEST_F(WindowsConsumerTest, NativeSwitchHandshakeAndInputReportReachHidClient) {
780804 )) << " Switch proprietary WriteFile failed: "
781805 << GetLastError ();
782806 EXPECT_EQ (bytes_written, output.size ());
783- return read_hid_report_with_timeout (reader.get (), hid_interface->input_report_size , 5s);
807+ return read_hid_report_matching (
808+ reader.get (),
809+ hid_interface->input_report_size ,
810+ 5s,
811+ [command](const auto &report) {
812+ return report.size () >= 2U && report[0 ] == 0x81U && report[1 ] == command;
813+ }
814+ );
784815 };
785816
786817 const auto status_reply = send_proprietary_command (0x01 );
@@ -854,11 +885,17 @@ TEST_F(WindowsConsumerTest, NativeSwitchHandshakeAndInputReportReachHidClient) {
854885 << GetLastError ();
855886 ASSERT_EQ (bytes_written, player_lights_report.size ());
856887
857- const auto player_lights_reply = read_hid_report_with_timeout (reader.get (), hid_interface->input_report_size , 5s);
888+ const auto player_lights_reply = read_hid_report_matching (
889+ reader.get (),
890+ hid_interface->input_report_size ,
891+ 5s,
892+ [](const auto &report) {
893+ return report.size () >= 15U && report[0 ] == 0x21U && report[14 ] == 0x30U ;
894+ }
895+ );
858896 ASSERT_TRUE (player_lights_reply.has_value ()) << " No Switch player-light acknowledgement reached the HID client" ;
859897 ASSERT_GE (player_lights_reply->size (), 15U );
860898 EXPECT_EQ (player_lights_reply->at (0 ), 0x21U );
861- EXPECT_EQ (player_lights_reply->at (1 ), 0x00U );
862899 EXPECT_EQ (player_lights_reply->at (13 ), 0x80U );
863900 EXPECT_EQ (player_lights_reply->at (14 ), 0x30U );
864901
@@ -881,11 +918,17 @@ TEST_F(WindowsConsumerTest, NativeSwitchHandshakeAndInputReportReachHidClient) {
881918 state.gyroscope = lvh::Vector3 {.x = 1 .0F , .y = 2 .0F , .z = -3 .0F };
882919 ASSERT_TRUE (created.adapter ->set_state (state).ok ());
883920
884- const auto input = read_hid_report_with_timeout (reader.get (), hid_interface->input_report_size , 5s);
921+ const auto input = read_hid_report_matching (
922+ reader.get (),
923+ hid_interface->input_report_size ,
924+ 5s,
925+ [](const auto &report) {
926+ return report.size () >= 6U && report[0 ] == 0x30U && report[3 ] == 0x08U && report[4 ] == 0x14U && report[5 ] == 0x08U ;
927+ }
928+ );
885929 ASSERT_TRUE (input.has_value ()) << " No native Switch 0x30 input report reached the HID client" ;
886930 ASSERT_EQ (input->size (), profile.input_report_size );
887931 EXPECT_EQ (input->at (0 ), 0x30U );
888- EXPECT_EQ (input->at (1 ), static_cast <std::uint8_t >(player_lights_reply->at (1 ) + 1U ));
889932 EXPECT_EQ (input->at (3 ), 0x08U ); // Nintendo A in the native right-button byte.
890933 EXPECT_EQ (input->at (4 ), 0x14U ); // R3 and Home.
891934 EXPECT_EQ (input->at (5 ), 0x08U ); // D-pad left.
@@ -912,10 +955,17 @@ TEST_F(WindowsConsumerTest, NativeSwitchHandshakeAndInputReportReachHidClient) {
912955
913956 state.gyroscope = lvh::Vector3 {.x = -4 .0F , .y = 5 .0F , .z = 6 .0F };
914957 ASSERT_TRUE (created.adapter ->set_state (state).ok ());
915- const auto next_input = read_hid_report_with_timeout (reader.get (), hid_interface->input_report_size , 5s);
958+ const auto next_input = read_hid_report_matching (
959+ reader.get (),
960+ hid_interface->input_report_size ,
961+ 5s,
962+ [&input](const auto &report) {
963+ return report.size () > 19U && report[0 ] == 0x30U && report[19 ] != input->at (19 );
964+ }
965+ );
916966 ASSERT_TRUE (next_input.has_value ()) << " No second native Switch motion report reached the HID client" ;
917967 ASSERT_EQ (next_input->size (), profile.input_report_size );
918- EXPECT_EQ (next_input->at (1 ), static_cast <std:: uint8_t >( input->at (1 ) + 1U ));
968+ EXPECT_NE (next_input->at (1 ), input->at (1 ));
919969 EXPECT_NE (next_input->at (19 ), input->at (19 ));
920970 ASSERT_TRUE (created.adapter ->close ().ok ());
921971}
0 commit comments