From 72c2e0fe275ed8393e51b018eea4fd4c995bc619 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sat, 26 Feb 2022 10:59:53 -0600 Subject: [PATCH 1/7] Rename *Report functions to *KeyboardReport In preparation for validation of report types other than just Keyboard, rename these keyboard-specific functions (and variables) to have appropriately keyboard-specific names. Signed-off-by: Michael Richters --- testing/VirtualDeviceTest.cpp | 59 ++++++++++++++++++----------------- testing/VirtualDeviceTest.h | 20 ++++++------ testing/bin/ktest-to-cxx | 2 +- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/testing/VirtualDeviceTest.cpp b/testing/VirtualDeviceTest.cpp index eb73ea31..12e2e49f 100644 --- a/testing/VirtualDeviceTest.cpp +++ b/testing/VirtualDeviceTest.cpp @@ -39,7 +39,7 @@ void VirtualDeviceTest::LoadState() { void VirtualDeviceTest::ClearState() { output_state_ = nullptr; input_timestamps_.clear(); - expected_reports_.clear(); + expected_keyboard_reports_.clear(); } const HIDState* VirtualDeviceTest::HIDReports() const { @@ -69,77 +69,78 @@ void VirtualDeviceTest::ReleaseKey(KeyAddr addr) { // ============================================================================= -void VirtualDeviceTest::ExpectReport(Keycodes keys, - std::string description) { +void VirtualDeviceTest::ExpectKeyboardReport(Keycodes keys, + std::string description) { size_t report_timestamp{Runtime.millisAtCycleStart()}; - ClearReport(); + ClearKeyboardReport(); for (Key key : keys) { - AddToReport(key); + AddToKeyboardReport(key); } ExpectedKeyboardReport new_report(report_timestamp, current_keyboard_keycodes_, description); - expected_reports_.push_back(new_report); + expected_keyboard_reports_.push_back(new_report); } // ============================================================================= -void VirtualDeviceTest::ExpectReport(AddKeycodes added_keys, - RemoveKeycodes removed_keys, - std::string description) { +void VirtualDeviceTest::ExpectKeyboardReport(AddKeycodes added_keys, + RemoveKeycodes removed_keys, + std::string description) { uint32_t report_timestamp = Runtime.millisAtCycleStart(); for (Key key : added_keys) { - AddToReport(key); + AddToKeyboardReport(key); } for (Key key : removed_keys) { - RemoveFromReport(key); + RemoveFromKeyboardReport(key); } ExpectedKeyboardReport new_report(report_timestamp, current_keyboard_keycodes_, description); - expected_reports_.push_back(new_report); + expected_keyboard_reports_.push_back(new_report); } // ----------------------------------------------------------------------------- -void VirtualDeviceTest::ExpectReport(AddKeycodes added_keys, - std::string description) { - ExpectReport(added_keys, RemoveKeycodes{}, description); +void VirtualDeviceTest::ExpectKeyboardReport(AddKeycodes added_keys, + std::string description) { + ExpectKeyboardReport(added_keys, RemoveKeycodes{}, description); } -void VirtualDeviceTest::ExpectReport(RemoveKeycodes removed_keys, - std::string description) { - ExpectReport(AddKeycodes{}, removed_keys, description); +void VirtualDeviceTest::ExpectKeyboardReport(RemoveKeycodes removed_keys, + std::string description) { + ExpectKeyboardReport(AddKeycodes{}, removed_keys, description); } // ============================================================================= -void VirtualDeviceTest::ClearReport() { +void VirtualDeviceTest::ClearKeyboardReport() { current_keyboard_keycodes_.clear(); } -void VirtualDeviceTest::AddToReport(Key key) { +void VirtualDeviceTest::AddToKeyboardReport(Key key) { current_keyboard_keycodes_.insert(key.getKeyCode()); } -void VirtualDeviceTest::RemoveFromReport(Key key) { +void VirtualDeviceTest::RemoveFromKeyboardReport(Key key) { current_keyboard_keycodes_.erase(key.getKeyCode()); } // ============================================================================= void VirtualDeviceTest::CheckReports() const { - int observed_report_count = HIDReports()->Keyboard().size(); - int expected_report_count = expected_reports_.size(); + int observed_keyboard_report_count = HIDReports()->Keyboard().size(); + int expected_keyboard_report_count = expected_keyboard_reports_.size(); - EXPECT_EQ(observed_report_count, expected_report_count); + EXPECT_EQ(observed_keyboard_report_count, expected_keyboard_report_count); - int max_count = std::max(observed_report_count, expected_report_count); + int max_count = std::max(observed_keyboard_report_count, + expected_keyboard_report_count); - for (int i = 0; i < observed_report_count; ++i) { + for (int i = 0; i < observed_keyboard_report_count; ++i) { auto observed_report = HIDReports()->Keyboard(i); auto observed_keycodes = observed_report.ActiveKeycodes(); - if (i < expected_report_count) { - auto expected_report = expected_reports_[i]; + if (i < expected_keyboard_report_count) { + auto expected_report = expected_keyboard_reports_[i]; auto expected_keycodes = expected_report.Keycodes(); EXPECT_THAT(observed_keycodes, ::testing::ElementsAreArray(expected_keycodes)) - << expected_reports_[i].Message() << " (i=" << i << ")"; + << expected_keyboard_reports_[i].Message() << " (i=" << i << ")"; EXPECT_EQ(observed_report.Timestamp(), expected_report.Timestamp()) << "Report timestamps don't match (i=" << i << ")"; diff --git a/testing/VirtualDeviceTest.h b/testing/VirtualDeviceTest.h index 893953b3..686cc466 100644 --- a/testing/VirtualDeviceTest.h +++ b/testing/VirtualDeviceTest.h @@ -103,22 +103,22 @@ class VirtualDeviceTest : public ::testing::Test { // keycode changes in a single report; others only a single keycode. Some run // the simulator for a specified number of milliseconds or cycles first. These // expected-value reports are all stored in a vector: - std::vector expected_reports_ = {}; + std::vector expected_keyboard_reports_ = {}; - void ExpectReport(AddKeycodes added_keys, - RemoveKeycodes removed_keys, - std::string description); + void ExpectKeyboardReport(AddKeycodes added_keys, + RemoveKeycodes removed_keys, + std::string description); - void ExpectReport(Keycodes added_keys, std::string description); - void ExpectReport(AddKeycodes added_keys, std::string description); - void ExpectReport(RemoveKeycodes removed_keys, std::string description); + void ExpectKeyboardReport(Keycodes added_keys, std::string description); + void ExpectKeyboardReport(AddKeycodes added_keys, std::string description); + void ExpectKeyboardReport(RemoveKeycodes removed_keys, std::string description); // --------------------------------------------------------------------------- std::set current_keyboard_keycodes_ = {}; // Manage the set of keycodes expected in the next report - void ClearReport(); - void AddToReport(Key key); - void RemoveFromReport(Key key); + void ClearKeyboardReport(); + void AddToKeyboardReport(Key key); + void RemoveFromKeyboardReport(Key key); // --------------------------------------------------------------------------- // Compare accumulated observed and expected reports, matching both timestamps diff --git a/testing/bin/ktest-to-cxx b/testing/bin/ktest-to-cxx index 78daeb51..e788490c 100644 --- a/testing/bin/ktest-to-cxx +++ b/testing/bin/ktest-to-cxx @@ -422,7 +422,7 @@ sub generate_expect_report { : ( $report->{data}->{keys} ) ) ); - cxx( "ExpectReport(Keycodes{$codes}, \"" + cxx( "ExpectKeyboardReport(Keycodes{$codes}, \"" . ( $report->{comment} || 'No explanatory comment specified' ) . "\");" ); cxx(""); From e8c84a0e47fbe0b28f20f0886bd850d73301c44e Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sat, 26 Feb 2022 11:25:30 -0600 Subject: [PATCH 2/7] Add MouseReport class for testing Signed-off-by: Michael Richters --- testing/ExpectedMouseReport.cpp | 65 +++++++++++++++++++++++++++++++++ testing/ExpectedMouseReport.h | 52 ++++++++++++++++++++++++++ testing/MouseReport.cpp | 61 +++++++++++++++++++++++++++++++ testing/MouseReport.h | 56 ++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 testing/ExpectedMouseReport.cpp create mode 100644 testing/ExpectedMouseReport.h create mode 100644 testing/MouseReport.cpp create mode 100644 testing/MouseReport.h diff --git a/testing/ExpectedMouseReport.cpp b/testing/ExpectedMouseReport.cpp new file mode 100644 index 00000000..d59a7aed --- /dev/null +++ b/testing/ExpectedMouseReport.cpp @@ -0,0 +1,65 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2022 Keyboard.io, Inc + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "testing/ExpectedMouseReport.h" + +namespace kaleidoscope { +namespace testing { + +ExpectedMouseReport::ExpectedMouseReport(uint32_t timestamp, + uint8_t buttons, + int8_t x, int8_t y, + int8_t v, int8_t h, + std::string message) { + timestamp_ = timestamp; + report_data_.buttons = buttons; + report_data_.xAxis = x; + report_data_.yAxis = y; + report_data_.vWheel = v; + report_data_.hWheel = h; + failure_message_ = message; +} + +uint32_t ExpectedMouseReport::Timestamp() const { + return timestamp_; +} + +const std::string & ExpectedMouseReport::Message() const { + return failure_message_; +} + +uint8_t ExpectedMouseReport::Buttons() const { + return report_data_.buttons; +} + +int8_t ExpectedMouseReport::XAxis() const { + return report_data_.xAxis; +} + +int8_t ExpectedMouseReport::YAxis() const { + return report_data_.yAxis; +} + +int8_t ExpectedMouseReport::VWheel() const { + return report_data_.vWheel; +} + +int8_t ExpectedMouseReport::HWheel() const { + return report_data_.hWheel; +} + +} // namespace testing +} // namespace kaleidoscope diff --git a/testing/ExpectedMouseReport.h b/testing/ExpectedMouseReport.h new file mode 100644 index 00000000..cb511832 --- /dev/null +++ b/testing/ExpectedMouseReport.h @@ -0,0 +1,52 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2022 Keyboard.io, Inc + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#pragma once + +#include +#include +#include +#include + +#include "MouseReport.h" + +namespace kaleidoscope { +namespace testing { + +class ExpectedMouseReport { + public: + ExpectedMouseReport(uint32_t timestamp, + uint8_t buttons, int8_t x, int8_t y, int8_t v, int8_t h, + std::string message = ""); + + uint8_t Buttons() const; + int8_t XAxis() const; + int8_t YAxis() const; + int8_t VWheel() const; + int8_t HWheel() const; + + uint32_t Timestamp() const; + + const std::string & Message() const; + + private: + uint32_t timestamp_; + MouseReport::ReportData report_data_; + std::string failure_message_; +}; + +} // namespace testing +} // namespace kaleidoscope diff --git a/testing/MouseReport.cpp b/testing/MouseReport.cpp new file mode 100644 index 00000000..25077b44 --- /dev/null +++ b/testing/MouseReport.cpp @@ -0,0 +1,61 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2020 Eric Paniagua (epaniagua@google.com) + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "testing/MouseReport.h" + +#include "Kaleidoscope.h" +#include "testing/fix-macros.h" + +#include + +#include "MouseButtons.h" + +namespace kaleidoscope { +namespace testing { + +MouseReport::MouseReport(const void* data) { + const ReportData& report_data = + *static_cast(data); + memcpy(&report_data_, &report_data, sizeof(report_data_)); + timestamp_ = Runtime.millisAtCycleStart(); +} + +uint32_t MouseReport::Timestamp() const { + return timestamp_; +} + +uint8_t MouseReport::Buttons() const { + return report_data_.buttons; +} + +int8_t MouseReport::XAxis() const { + return report_data_.xAxis; +} + +int8_t MouseReport::YAxis() const { + return report_data_.yAxis; +} + +int8_t MouseReport::VWheel() const { + return report_data_.vWheel; +} + +int8_t MouseReport::HWheel() const { + return report_data_.hWheel; +} + +} // namespace testing +} // namespace kaleidoscope diff --git a/testing/MouseReport.h b/testing/MouseReport.h new file mode 100644 index 00000000..eddd2e7a --- /dev/null +++ b/testing/MouseReport.h @@ -0,0 +1,56 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2020 Eric Paniagua (epaniagua@google.com) + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#pragma once + +#include +#include + +#include "HID-Settings.h" +#include "MultiReport/Mouse.h" + +namespace kaleidoscope { +namespace testing { + +class MouseReport { + public: + typedef HID_MouseReport_Data_t ReportData; + + static constexpr uint8_t kHidReportType = HID_REPORTID_MOUSE; + + MouseReport(const void* data); + + + static constexpr uint8_t kButtonLeft = MOUSE_LEFT; + static constexpr uint8_t kButtonRight = MOUSE_RIGHT; + static constexpr uint8_t kButtonMiddle = MOUSE_MIDDLE; + static constexpr uint8_t kButtonPrev = MOUSE_PREV; + static constexpr uint8_t kButtonNext = MOUSE_NEXT; + + uint32_t Timestamp() const; + uint8_t Buttons() const; + int8_t XAxis() const; + int8_t YAxis() const; + int8_t VWheel() const; + int8_t HWheel() const; + + private: + uint32_t timestamp_; + ReportData report_data_; +}; + +} // namespace testing +} // namespce kaleidoscope From e87306144ef584cb740ee9569b38cdb7887c3791 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sat, 26 Feb 2022 11:29:18 -0600 Subject: [PATCH 3/7] Add MouseReports to HIDState for testing Signed-off-by: Michael Richters --- testing/HIDState.cpp | 25 +++++++++++++++++++++---- testing/HIDState.h | 7 +++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/testing/HIDState.cpp b/testing/HIDState.cpp index f9d72de8..8a4df87b 100644 --- a/testing/HIDState.cpp +++ b/testing/HIDState.cpp @@ -51,6 +51,14 @@ const KeyboardReport& HIDState::Keyboard(size_t i) const { return keyboard_reports_.at(i); } +const std::vector& HIDState::Mouse() const { + return mouse_reports_; +} + +const MouseReport& HIDState::Mouse(size_t i) const { + return mouse_reports_.at(i); +} + const std::vector& HIDState::SystemControl() const { return system_control_reports_; } @@ -65,10 +73,6 @@ namespace internal { void HIDStateBuilder::ProcessHidReport( uint8_t id, const void* data, int len, int result) { switch (id) { - case HID_REPORTID_MOUSE: { - LOG(ERROR) << "Dropped MouseReport: unimplemented"; - break; - } case HID_REPORTID_KEYBOARD: { LOG(ERROR) << "Dropped BootKeyboardReport: unimplemented"; break; @@ -85,6 +89,10 @@ void HIDStateBuilder::ProcessHidReport( ProcessSystemControlReport(SystemControlReport{data}); break; } + case HID_REPORTID_MOUSE: { + ProcessMouseReport(MouseReport{data}); + break; + } case HID_REPORTID_MOUSE_ABSOLUTE: { ProcessAbsoluteMouseReport(AbsoluteMouseReport{data}); break; @@ -107,6 +115,7 @@ std::unique_ptr HIDStateBuilder::Snapshot() { hid_state->absolute_mouse_reports_ = std::move(absolute_mouse_reports_); hid_state->consumer_control_reports_ = std::move(consumer_control_reports_); hid_state->keyboard_reports_ = std::move(keyboard_reports_); + hid_state->mouse_reports_ = std::move(mouse_reports_); hid_state->system_control_reports_ = std::move(system_control_reports_); Clear(); // Clear global state. @@ -118,6 +127,7 @@ void HIDStateBuilder::Clear() { absolute_mouse_reports_.clear(); consumer_control_reports_.clear(); keyboard_reports_.clear(); + mouse_reports_.clear(); system_control_reports_.clear(); } @@ -136,6 +146,11 @@ void HIDStateBuilder::ProcessKeyboardReport(const KeyboardReport& report) { keyboard_reports_.push_back(report); } +// static +void HIDStateBuilder::ProcessMouseReport(const MouseReport& report) { + mouse_reports_.push_back(report); +} + // static void HIDStateBuilder::ProcessSystemControlReport(const SystemControlReport& report) { system_control_reports_.push_back(report); @@ -148,6 +163,8 @@ std::vector HIDStateBuilder::consumer_control_reports_; // static std::vector HIDStateBuilder::keyboard_reports_; // static +std::vector HIDStateBuilder::mouse_reports_; +// static std::vector HIDStateBuilder::system_control_reports_; } // namesapce internal diff --git a/testing/HIDState.h b/testing/HIDState.h index 1068e782..e585fc8e 100644 --- a/testing/HIDState.h +++ b/testing/HIDState.h @@ -19,6 +19,7 @@ #include "testing/AbsoluteMouseReport.h" #include "testing/ConsumerControlReport.h" #include "testing/KeyboardReport.h" +#include "testing/MouseReport.h" #include "testing/SystemControlReport.h" // Out of order due to macro conflicts. @@ -42,6 +43,9 @@ class HIDState { const std::vector& Keyboard() const; const KeyboardReport& Keyboard(size_t i) const; + const std::vector& Mouse() const; + const MouseReport& Mouse(size_t i) const; + const std::vector& SystemControl() const; const SystemControlReport& SystemControl(size_t i) const; @@ -51,6 +55,7 @@ class HIDState { std::vector absolute_mouse_reports_; std::vector consumer_control_reports_; std::vector keyboard_reports_; + std::vector mouse_reports_; std::vector system_control_reports_; }; @@ -68,11 +73,13 @@ class HIDStateBuilder { static void ProcessAbsoluteMouseReport(const AbsoluteMouseReport& report); static void ProcessConsumerControlReport(const ConsumerControlReport& report); static void ProcessKeyboardReport(const KeyboardReport& report); + static void ProcessMouseReport(const MouseReport& report); static void ProcessSystemControlReport(const SystemControlReport& report); static std::vector absolute_mouse_reports_; static std::vector consumer_control_reports_; static std::vector keyboard_reports_; + static std::vector mouse_reports_; static std::vector system_control_reports_; }; From 0670113b660506bf37a2d1325ef49682d3e6b925 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sat, 26 Feb 2022 12:05:07 -0600 Subject: [PATCH 4/7] Move checking of keyboard reports to a separate function Signed-off-by: Michael Richters --- testing/VirtualDeviceTest.cpp | 4 ++++ testing/VirtualDeviceTest.h | 1 + 2 files changed, 5 insertions(+) diff --git a/testing/VirtualDeviceTest.cpp b/testing/VirtualDeviceTest.cpp index 12e2e49f..4db3b862 100644 --- a/testing/VirtualDeviceTest.cpp +++ b/testing/VirtualDeviceTest.cpp @@ -122,6 +122,10 @@ void VirtualDeviceTest::RemoveFromKeyboardReport(Key key) { // ============================================================================= void VirtualDeviceTest::CheckReports() const { + CheckKeyboardReports(); +} + +void VirtualDeviceTest::CheckKeyboardReports() const { int observed_keyboard_report_count = HIDReports()->Keyboard().size(); int expected_keyboard_report_count = expected_keyboard_reports_.size(); diff --git a/testing/VirtualDeviceTest.h b/testing/VirtualDeviceTest.h index 686cc466..a3b76e69 100644 --- a/testing/VirtualDeviceTest.h +++ b/testing/VirtualDeviceTest.h @@ -124,6 +124,7 @@ class VirtualDeviceTest : public ::testing::Test { // Compare accumulated observed and expected reports, matching both timestamps // and keycodes. void CheckReports() const; + void CheckKeyboardReports() const; }; From 29ebffe09968403bb36877fd44743f6ce6e811dc Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sat, 26 Feb 2022 12:13:14 -0600 Subject: [PATCH 5/7] Add function for verification of expected mouse reports Signed-off-by: Michael Richters --- testing/VirtualDeviceTest.cpp | 59 +++++++++++++++++++++++++++++++++++ testing/VirtualDeviceTest.h | 7 +++++ 2 files changed, 66 insertions(+) diff --git a/testing/VirtualDeviceTest.cpp b/testing/VirtualDeviceTest.cpp index 4db3b862..263e02ac 100644 --- a/testing/VirtualDeviceTest.cpp +++ b/testing/VirtualDeviceTest.cpp @@ -19,6 +19,8 @@ #include "HIDReportObserver.h" #include "testing/HIDState.h" +#include + namespace kaleidoscope { namespace testing { @@ -40,6 +42,7 @@ void VirtualDeviceTest::ClearState() { output_state_ = nullptr; input_timestamps_.clear(); expected_keyboard_reports_.clear(); + expected_mouse_reports_.clear(); } const HIDState* VirtualDeviceTest::HIDReports() const { @@ -120,9 +123,23 @@ void VirtualDeviceTest::RemoveFromKeyboardReport(Key key) { current_keyboard_keycodes_.erase(key.getKeyCode()); } +// ============================================================================= +void VirtualDeviceTest::ExpectMouseReport(uint8_t buttons, + int8_t x, int8_t y, + int8_t v, int8_t h, + std::string description) { + uint32_t report_timestamp = Runtime.millisAtCycleStart(); + ExpectedMouseReport new_report(report_timestamp, + buttons, x, y, v, h, + description); + expected_mouse_reports_.push_back(new_report); +} + + // ============================================================================= void VirtualDeviceTest::CheckReports() const { CheckKeyboardReports(); + CheckMouseReports(); } void VirtualDeviceTest::CheckKeyboardReports() const { @@ -160,5 +177,47 @@ void VirtualDeviceTest::CheckKeyboardReports() const { } } +void VirtualDeviceTest::CheckMouseReports() const { + int observed_mouse_report_count = HIDReports()->Mouse().size(); + int expected_mouse_report_count = expected_mouse_reports_.size(); + + EXPECT_EQ(observed_mouse_report_count, expected_mouse_report_count); + + int max_count = std::max(observed_mouse_report_count, + expected_mouse_report_count); + + for (int i = 0; i < observed_mouse_report_count; ++i) { + auto observed_report = HIDReports()->Mouse(i); + + if (i < expected_mouse_report_count) { + auto expected_report = expected_mouse_reports_[i]; + + EXPECT_EQ(observed_report.Buttons(), expected_report.Buttons()) + << expected_mouse_reports_[i].Message() << " (i=" << i << ")"; + EXPECT_EQ(observed_report.XAxis(), expected_report.XAxis()) + << expected_mouse_reports_[i].Message() << " (i=" << i << ")"; + EXPECT_EQ(observed_report.YAxis(), expected_report.YAxis()) + << expected_mouse_reports_[i].Message() << " (i=" << i << ")"; + EXPECT_EQ(observed_report.VWheel(), expected_report.VWheel()) + << expected_mouse_reports_[i].Message() << " (i=" << i << ")"; + EXPECT_EQ(observed_report.HWheel(), expected_report.HWheel()) + << expected_mouse_reports_[i].Message() << " (i=" << i << ")"; + EXPECT_EQ(observed_report.Timestamp(), expected_report.Timestamp()) + << "Report timestamps don't match (i=" << i << ")"; + + } else { + std::bitset<8> observed_buttons{observed_report.Buttons()}; + std::cerr << "Unexpected mouse report at " + << observed_report.Timestamp() << "ms: {" + << " buttons: " << observed_buttons + << " x: " << int(observed_report.XAxis()) + << " y: " << int(observed_report.YAxis()) + << " v: " << int(observed_report.VWheel()) + << " h: " << int(observed_report.HWheel()) + << " }" << std::endl; + } + } +} + } // namespace testing } // namespace kaleidoscope diff --git a/testing/VirtualDeviceTest.h b/testing/VirtualDeviceTest.h index a3b76e69..81c89b35 100644 --- a/testing/VirtualDeviceTest.h +++ b/testing/VirtualDeviceTest.h @@ -19,6 +19,7 @@ #include #include "testing/ExpectedKeyboardReport.h" +#include "testing/ExpectedMouseReport.h" #include "testing/SimHarness.h" #include "testing/State.h" @@ -113,6 +114,11 @@ class VirtualDeviceTest : public ::testing::Test { void ExpectKeyboardReport(AddKeycodes added_keys, std::string description); void ExpectKeyboardReport(RemoveKeycodes removed_keys, std::string description); + std::vector expected_mouse_reports_ = {}; + + void ExpectMouseReport(uint8_t buttons, int8_t x, int8_t y, + int8_t v, int8_t h, std::string description); + // --------------------------------------------------------------------------- std::set current_keyboard_keycodes_ = {}; // Manage the set of keycodes expected in the next report @@ -125,6 +131,7 @@ class VirtualDeviceTest : public ::testing::Test { // and keycodes. void CheckReports() const; void CheckKeyboardReports() const; + void CheckMouseReports() const; }; From f9b9c27852409fbb844f0874c3aaed9e2d5a23b2 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sat, 26 Feb 2022 23:19:33 -0600 Subject: [PATCH 6/7] Add mouse report handling to ktest Signed-off-by: Michael Richters --- testing/bin/ktest-to-cxx | 118 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 5 deletions(-) diff --git a/testing/bin/ktest-to-cxx b/testing/bin/ktest-to-cxx index e788490c..5f1f2aac 100644 --- a/testing/bin/ktest-to-cxx +++ b/testing/bin/ktest-to-cxx @@ -138,6 +138,76 @@ sub load_from_text { keys => [@keys] }; } + if ( $content =~ /^no mouse-report/ ) { + return { + report_type => 'mouse', + count => 0 + }; + } + if ( $content =~ /^mouse-report\s+(.*)$/ ) { + my $report_data = $1; + my @args = split( /,?\s+/, lc $report_data ); + my $mouse_report_data = {}; + $mouse_report_data->{buttons} = []; + $mouse_report_data->{x} = "0"; + $mouse_report_data->{y} = "0"; + $mouse_report_data->{v} = "0"; + $mouse_report_data->{h} = "0"; + if ( scalar(@args) == 1 && $args[0] =~ /^empty$/i ) { + @args = (); + } + for my $arg (@args) { + if ( $arg =~ /(\w+)=([\w\d\-\+]+)/ ) { + my $field = $1; + my $value = $2; + if ( $field =~ /button/ ) { + if ( $value =~ /^l/ ) { + $value = 'MouseReport::kButtonLeft'; + } + elsif ( $value =~ /^r/ ) { + $value = 'MouseReport::kButtonRight'; + } + elsif ( $value =~ /^m/ ) { + $value = 'MouseReport::kButtonMiddle'; + } + elsif ( $value =~ /^n/ ) { + $value = 'MouseReport::kButtonNext'; + } + elsif ( $value =~ /^p/ ) { + $value = 'MouseReport::kButtonPrev'; + } + else { + die +"Couldn't parse mouse button value from $content at line $line_num"; + } + push @{ $mouse_report_data->{buttons} }, $value; + } + elsif ( $field =~ /x/ ) { + $mouse_report_data->{x} = $value; + } + elsif ( $field =~ /y/ ) { + $mouse_report_data->{y} = $value; + } + elsif ( $field =~ /v/ ) { + $mouse_report_data->{v} = $value; + } + elsif ( $field =~ /h/ ) { + $mouse_report_data->{h} = $value; + } + else { + die "Don't know how parse $content at line $line_num"; + } + } + else { + die "Don't know how parse $content at line $line_num"; + } + } + return { + count => 1, # We expect one report here + report_type => 'mouse', + data => $mouse_report_data, + } + } else { die "Don't know how parse $content at line $line_num"; } @@ -394,15 +464,22 @@ sub generate_release { sub generate_expect_report { my $report = shift; - if ( !$report->{data}->{report_type} - || $report->{data}->{report_type} ne 'keyboard' ) - { + if ( $report->{data}->{report_type} eq 'keyboard' ) { + generate_expect_keyboard_report($report); + } + elsif ( $report->{data}->{report_type} eq 'mouse' ) { + generate_expect_mouse_report($report); + } + else { die -"Don't know how to work with expectaions of reports other than 'keyboard' reports at line #" +"Don't know how to handle expectaions of report types other than 'keyboard' and 'mouse' at line #" . $report->{line_num} . "\n"; - } $reports_expected++; +} + +sub generate_expect_keyboard_report { + my $report = shift; if ( $report->{data}->{count} == 0 ) { if ( $report->{comment} ) { @@ -428,6 +505,37 @@ sub generate_expect_report { cxx(""); } +sub generate_expect_mouse_report { + my $report = shift; + + if ( $report->{data}->{count} == 0 ) { + if ( $report->{comment} ) { + cxx_comment( $report->{comment} ); + } + cxx_comment( +"We don't expect any report here, and have told the tests to check that" + ); + return; + } + + my $buttons_code = "0"; + my @buttons = ( ref( $report->{data}->{data}{buttons} ) + ? @{ $report->{data}->{data}{buttons} } + : ( $report->{data}->{data}{buttons} ) ); + for my $button_value (@buttons) { + $buttons_code .= " | $button_value"; + } + cxx("ExpectMouseReport($buttons_code, " + . $report->{data}{data}{x} . ", " + . $report->{data}{data}{y} . ", " + . $report->{data}{data}{v} . ", " + . $report->{data}{data}{h} . ", " + . "\"" + . ( $report->{comment} || 'No explanatory comment specified' ) + . "\");" ); + cxx(""); +} + sub generate_check_expected_reports { cxx(""); cxx("LoadState();"); From 46311f0a64bebdf775f51708cff51a46a19f661a Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sun, 27 Feb 2022 16:32:18 -0600 Subject: [PATCH 7/7] Add MouseKeys basic testcase Signed-off-by: Michael Richters --- tests/plugins/MouseKeys/basic/basic.ino | 49 +++++++++++++++ tests/plugins/MouseKeys/basic/sketch.json | 6 ++ tests/plugins/MouseKeys/basic/test.ktest | 72 +++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 tests/plugins/MouseKeys/basic/basic.ino create mode 100644 tests/plugins/MouseKeys/basic/sketch.json create mode 100644 tests/plugins/MouseKeys/basic/test.ktest diff --git a/tests/plugins/MouseKeys/basic/basic.ino b/tests/plugins/MouseKeys/basic/basic.ino new file mode 100644 index 00000000..09df9b29 --- /dev/null +++ b/tests/plugins/MouseKeys/basic/basic.ino @@ -0,0 +1,49 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2022 Keyboard.io, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include + +// *INDENT-OFF* +KEYMAPS( + [0] = KEYMAP_STACKED + ( + Key_mouseUp, Key_mouseDn, Key_mouseL, Key_mouseR, ___, ___, ___, + Key_mouseScrollUp, Key_mouseScrollDn, Key_mouseScrollL, Key_mouseScrollR, ___, ___, ___, + Key_mouseBtnL, Key_mouseBtnM, Key_mouseBtnR, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___, + + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___ + ), +) +// *INDENT-ON* + +KALEIDOSCOPE_INIT_PLUGINS(MouseKeys); + +void setup() { + Kaleidoscope.setup(); +} + +void loop() { + Kaleidoscope.loop(); +} diff --git a/tests/plugins/MouseKeys/basic/sketch.json b/tests/plugins/MouseKeys/basic/sketch.json new file mode 100644 index 00000000..8cc86922 --- /dev/null +++ b/tests/plugins/MouseKeys/basic/sketch.json @@ -0,0 +1,6 @@ +{ + "cpu": { + "fqbn": "keyboardio:virtual:model01", + "port": "" + } +} diff --git a/tests/plugins/MouseKeys/basic/test.ktest b/tests/plugins/MouseKeys/basic/test.ktest new file mode 100644 index 00000000..577f685d --- /dev/null +++ b/tests/plugins/MouseKeys/basic/test.ktest @@ -0,0 +1,72 @@ +VERSION 1 + +KEYSWITCH MOVE_UP 0 0 +KEYSWITCH MOVE_DOWN 0 1 +KEYSWITCH MOVE_LEFT 0 2 +KEYSWITCH MOVE_RIGHT 0 3 + +KEYSWITCH SCROLL_UP 1 0 +KEYSWITCH SCROLL_DOWN 1 1 +KEYSWITCH SCROLL_LEFT 1 2 +KEYSWITCH SCROLL_RIGHT 1 3 + +KEYSWITCH BUTTON_L 2 0 +KEYSWITCH BUTTON_M 2 1 +KEYSWITCH BUTTON_R 2 2 + +# ============================================================================== +NAME MouseKeys move up + +RUN 3 ms +PRESS MOVE_UP +RUN 1 cycle + +RUN 15 ms +EXPECT mouse-report y=-1 +RUN 1 cycle +EXPECT mouse-report empty + +RUN 15 ms +EXPECT mouse-report y=-1 +RUN 1 cycle +EXPECT mouse-report empty + +RUN 5 ms +RELEASE MOVE_UP +RUN 1 cycle +EXPECT no mouse-report + +RUN 5 ms + +# ============================================================================== +NAME MouseKeys button left + +RUN 4 ms +PRESS BUTTON_L +RUN 1 cycle +EXPECT mouse-report button=L + +RUN 20 ms +RELEASE BUTTON_L +RUN 1 cycle +EXPECT mouse-report empty + +RUN 5 ms + +# ============================================================================== +NAME MouseKeys scroll down + +RUN 4 ms +PRESS SCROLL_UP +RUN 1 cycle +EXPECT mouse-report v=1 + +RUN 50 ms +EXPECT mouse-report v=1 + +RUN 10 ms +RELEASE SCROLL_UP +RUN 1 cycle +EXPECT no mouse-report + +RUN 5 ms