Merge pull request #1120 from gedankenexperimenter/testing/mouse-reports

Add verification of mouse reports to testing infrastructure
pull/1122/head
Jesse Vincent 3 years ago committed by GitHub
commit d898725725
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
#include <vector>
#include <set>
#include <string>
#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

@ -51,6 +51,14 @@ const KeyboardReport& HIDState::Keyboard(size_t i) const {
return keyboard_reports_.at(i); return keyboard_reports_.at(i);
} }
const std::vector<MouseReport>& HIDState::Mouse() const {
return mouse_reports_;
}
const MouseReport& HIDState::Mouse(size_t i) const {
return mouse_reports_.at(i);
}
const std::vector<SystemControlReport>& HIDState::SystemControl() const { const std::vector<SystemControlReport>& HIDState::SystemControl() const {
return system_control_reports_; return system_control_reports_;
} }
@ -65,10 +73,6 @@ namespace internal {
void HIDStateBuilder::ProcessHidReport( void HIDStateBuilder::ProcessHidReport(
uint8_t id, const void* data, int len, int result) { uint8_t id, const void* data, int len, int result) {
switch (id) { switch (id) {
case HID_REPORTID_MOUSE: {
LOG(ERROR) << "Dropped MouseReport: unimplemented";
break;
}
case HID_REPORTID_KEYBOARD: { case HID_REPORTID_KEYBOARD: {
LOG(ERROR) << "Dropped BootKeyboardReport: unimplemented"; LOG(ERROR) << "Dropped BootKeyboardReport: unimplemented";
break; break;
@ -85,6 +89,10 @@ void HIDStateBuilder::ProcessHidReport(
ProcessSystemControlReport(SystemControlReport{data}); ProcessSystemControlReport(SystemControlReport{data});
break; break;
} }
case HID_REPORTID_MOUSE: {
ProcessMouseReport(MouseReport{data});
break;
}
case HID_REPORTID_MOUSE_ABSOLUTE: { case HID_REPORTID_MOUSE_ABSOLUTE: {
ProcessAbsoluteMouseReport(AbsoluteMouseReport{data}); ProcessAbsoluteMouseReport(AbsoluteMouseReport{data});
break; break;
@ -107,6 +115,7 @@ std::unique_ptr<HIDState> HIDStateBuilder::Snapshot() {
hid_state->absolute_mouse_reports_ = std::move(absolute_mouse_reports_); hid_state->absolute_mouse_reports_ = std::move(absolute_mouse_reports_);
hid_state->consumer_control_reports_ = std::move(consumer_control_reports_); hid_state->consumer_control_reports_ = std::move(consumer_control_reports_);
hid_state->keyboard_reports_ = std::move(keyboard_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_); hid_state->system_control_reports_ = std::move(system_control_reports_);
Clear(); // Clear global state. Clear(); // Clear global state.
@ -118,6 +127,7 @@ void HIDStateBuilder::Clear() {
absolute_mouse_reports_.clear(); absolute_mouse_reports_.clear();
consumer_control_reports_.clear(); consumer_control_reports_.clear();
keyboard_reports_.clear(); keyboard_reports_.clear();
mouse_reports_.clear();
system_control_reports_.clear(); system_control_reports_.clear();
} }
@ -136,6 +146,11 @@ void HIDStateBuilder::ProcessKeyboardReport(const KeyboardReport& report) {
keyboard_reports_.push_back(report); keyboard_reports_.push_back(report);
} }
// static
void HIDStateBuilder::ProcessMouseReport(const MouseReport& report) {
mouse_reports_.push_back(report);
}
// static // static
void HIDStateBuilder::ProcessSystemControlReport(const SystemControlReport& report) { void HIDStateBuilder::ProcessSystemControlReport(const SystemControlReport& report) {
system_control_reports_.push_back(report); system_control_reports_.push_back(report);
@ -148,6 +163,8 @@ std::vector<ConsumerControlReport> HIDStateBuilder::consumer_control_reports_;
// static // static
std::vector<KeyboardReport> HIDStateBuilder::keyboard_reports_; std::vector<KeyboardReport> HIDStateBuilder::keyboard_reports_;
// static // static
std::vector<MouseReport> HIDStateBuilder::mouse_reports_;
// static
std::vector<SystemControlReport> HIDStateBuilder::system_control_reports_; std::vector<SystemControlReport> HIDStateBuilder::system_control_reports_;
} // namesapce internal } // namesapce internal

@ -19,6 +19,7 @@
#include "testing/AbsoluteMouseReport.h" #include "testing/AbsoluteMouseReport.h"
#include "testing/ConsumerControlReport.h" #include "testing/ConsumerControlReport.h"
#include "testing/KeyboardReport.h" #include "testing/KeyboardReport.h"
#include "testing/MouseReport.h"
#include "testing/SystemControlReport.h" #include "testing/SystemControlReport.h"
// Out of order due to macro conflicts. // Out of order due to macro conflicts.
@ -42,6 +43,9 @@ class HIDState {
const std::vector<KeyboardReport>& Keyboard() const; const std::vector<KeyboardReport>& Keyboard() const;
const KeyboardReport& Keyboard(size_t i) const; const KeyboardReport& Keyboard(size_t i) const;
const std::vector<MouseReport>& Mouse() const;
const MouseReport& Mouse(size_t i) const;
const std::vector<SystemControlReport>& SystemControl() const; const std::vector<SystemControlReport>& SystemControl() const;
const SystemControlReport& SystemControl(size_t i) const; const SystemControlReport& SystemControl(size_t i) const;
@ -51,6 +55,7 @@ class HIDState {
std::vector<AbsoluteMouseReport> absolute_mouse_reports_; std::vector<AbsoluteMouseReport> absolute_mouse_reports_;
std::vector<ConsumerControlReport> consumer_control_reports_; std::vector<ConsumerControlReport> consumer_control_reports_;
std::vector<KeyboardReport> keyboard_reports_; std::vector<KeyboardReport> keyboard_reports_;
std::vector<MouseReport> mouse_reports_;
std::vector<SystemControlReport> system_control_reports_; std::vector<SystemControlReport> system_control_reports_;
}; };
@ -68,11 +73,13 @@ class HIDStateBuilder {
static void ProcessAbsoluteMouseReport(const AbsoluteMouseReport& report); static void ProcessAbsoluteMouseReport(const AbsoluteMouseReport& report);
static void ProcessConsumerControlReport(const ConsumerControlReport& report); static void ProcessConsumerControlReport(const ConsumerControlReport& report);
static void ProcessKeyboardReport(const KeyboardReport& report); static void ProcessKeyboardReport(const KeyboardReport& report);
static void ProcessMouseReport(const MouseReport& report);
static void ProcessSystemControlReport(const SystemControlReport& report); static void ProcessSystemControlReport(const SystemControlReport& report);
static std::vector<AbsoluteMouseReport> absolute_mouse_reports_; static std::vector<AbsoluteMouseReport> absolute_mouse_reports_;
static std::vector<ConsumerControlReport> consumer_control_reports_; static std::vector<ConsumerControlReport> consumer_control_reports_;
static std::vector<KeyboardReport> keyboard_reports_; static std::vector<KeyboardReport> keyboard_reports_;
static std::vector<MouseReport> mouse_reports_;
static std::vector<SystemControlReport> system_control_reports_; static std::vector<SystemControlReport> system_control_reports_;
}; };

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "testing/MouseReport.h"
#include "Kaleidoscope.h"
#include "testing/fix-macros.h"
#include <cstring>
#include "MouseButtons.h"
namespace kaleidoscope {
namespace testing {
MouseReport::MouseReport(const void* data) {
const ReportData& report_data =
*static_cast<const ReportData*>(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

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
#include <vector>
#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

@ -19,6 +19,8 @@
#include "HIDReportObserver.h" #include "HIDReportObserver.h"
#include "testing/HIDState.h" #include "testing/HIDState.h"
#include <bitset>
namespace kaleidoscope { namespace kaleidoscope {
namespace testing { namespace testing {
@ -39,7 +41,8 @@ void VirtualDeviceTest::LoadState() {
void VirtualDeviceTest::ClearState() { void VirtualDeviceTest::ClearState() {
output_state_ = nullptr; output_state_ = nullptr;
input_timestamps_.clear(); input_timestamps_.clear();
expected_reports_.clear(); expected_keyboard_reports_.clear();
expected_mouse_reports_.clear();
} }
const HIDState* VirtualDeviceTest::HIDReports() const { const HIDState* VirtualDeviceTest::HIDReports() const {
@ -69,77 +72,96 @@ void VirtualDeviceTest::ReleaseKey(KeyAddr addr) {
// ============================================================================= // =============================================================================
void VirtualDeviceTest::ExpectReport(Keycodes keys, void VirtualDeviceTest::ExpectKeyboardReport(Keycodes keys,
std::string description) { std::string description) {
size_t report_timestamp{Runtime.millisAtCycleStart()}; size_t report_timestamp{Runtime.millisAtCycleStart()};
ClearReport(); ClearKeyboardReport();
for (Key key : keys) { for (Key key : keys) {
AddToReport(key); AddToKeyboardReport(key);
} }
ExpectedKeyboardReport new_report(report_timestamp, ExpectedKeyboardReport new_report(report_timestamp,
current_keyboard_keycodes_, current_keyboard_keycodes_,
description); description);
expected_reports_.push_back(new_report); expected_keyboard_reports_.push_back(new_report);
} }
// ============================================================================= // =============================================================================
void VirtualDeviceTest::ExpectReport(AddKeycodes added_keys, void VirtualDeviceTest::ExpectKeyboardReport(AddKeycodes added_keys,
RemoveKeycodes removed_keys, RemoveKeycodes removed_keys,
std::string description) { std::string description) {
uint32_t report_timestamp = Runtime.millisAtCycleStart(); uint32_t report_timestamp = Runtime.millisAtCycleStart();
for (Key key : added_keys) { for (Key key : added_keys) {
AddToReport(key); AddToKeyboardReport(key);
} }
for (Key key : removed_keys) { for (Key key : removed_keys) {
RemoveFromReport(key); RemoveFromKeyboardReport(key);
} }
ExpectedKeyboardReport new_report(report_timestamp, ExpectedKeyboardReport new_report(report_timestamp,
current_keyboard_keycodes_, current_keyboard_keycodes_,
description); description);
expected_reports_.push_back(new_report); expected_keyboard_reports_.push_back(new_report);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void VirtualDeviceTest::ExpectReport(AddKeycodes added_keys, void VirtualDeviceTest::ExpectKeyboardReport(AddKeycodes added_keys,
std::string description) { std::string description) {
ExpectReport(added_keys, RemoveKeycodes{}, description); ExpectKeyboardReport(added_keys, RemoveKeycodes{}, description);
} }
void VirtualDeviceTest::ExpectReport(RemoveKeycodes removed_keys, void VirtualDeviceTest::ExpectKeyboardReport(RemoveKeycodes removed_keys,
std::string description) { std::string description) {
ExpectReport(AddKeycodes{}, removed_keys, description); ExpectKeyboardReport(AddKeycodes{}, removed_keys, description);
} }
// ============================================================================= // =============================================================================
void VirtualDeviceTest::ClearReport() { void VirtualDeviceTest::ClearKeyboardReport() {
current_keyboard_keycodes_.clear(); current_keyboard_keycodes_.clear();
} }
void VirtualDeviceTest::AddToReport(Key key) { void VirtualDeviceTest::AddToKeyboardReport(Key key) {
current_keyboard_keycodes_.insert(key.getKeyCode()); current_keyboard_keycodes_.insert(key.getKeyCode());
} }
void VirtualDeviceTest::RemoveFromReport(Key key) { void VirtualDeviceTest::RemoveFromKeyboardReport(Key key) {
current_keyboard_keycodes_.erase(key.getKeyCode()); 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 { void VirtualDeviceTest::CheckReports() const {
int observed_report_count = HIDReports()->Keyboard().size(); CheckKeyboardReports();
int expected_report_count = expected_reports_.size(); CheckMouseReports();
}
EXPECT_EQ(observed_report_count, expected_report_count); void VirtualDeviceTest::CheckKeyboardReports() const {
int observed_keyboard_report_count = HIDReports()->Keyboard().size();
int expected_keyboard_report_count = expected_keyboard_reports_.size();
int max_count = std::max(observed_report_count, expected_report_count); EXPECT_EQ(observed_keyboard_report_count, expected_keyboard_report_count);
for (int i = 0; i < observed_report_count; ++i) { int max_count = std::max(observed_keyboard_report_count,
expected_keyboard_report_count);
for (int i = 0; i < observed_keyboard_report_count; ++i) {
auto observed_report = HIDReports()->Keyboard(i); auto observed_report = HIDReports()->Keyboard(i);
auto observed_keycodes = observed_report.ActiveKeycodes(); auto observed_keycodes = observed_report.ActiveKeycodes();
if (i < expected_report_count) { if (i < expected_keyboard_report_count) {
auto expected_report = expected_reports_[i]; auto expected_report = expected_keyboard_reports_[i];
auto expected_keycodes = expected_report.Keycodes(); auto expected_keycodes = expected_report.Keycodes();
EXPECT_THAT(observed_keycodes, EXPECT_THAT(observed_keycodes,
::testing::ElementsAreArray(expected_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()) EXPECT_EQ(observed_report.Timestamp(), expected_report.Timestamp())
<< "Report timestamps don't match (i=" << i << ")"; << "Report timestamps don't match (i=" << i << ")";
@ -155,5 +177,47 @@ void VirtualDeviceTest::CheckReports() 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 testing
} // namespace kaleidoscope } // namespace kaleidoscope

@ -19,6 +19,7 @@
#include <cstddef> #include <cstddef>
#include "testing/ExpectedKeyboardReport.h" #include "testing/ExpectedKeyboardReport.h"
#include "testing/ExpectedMouseReport.h"
#include "testing/SimHarness.h" #include "testing/SimHarness.h"
#include "testing/State.h" #include "testing/State.h"
@ -103,27 +104,34 @@ class VirtualDeviceTest : public ::testing::Test {
// keycode changes in a single report; others only a single keycode. Some run // 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 // the simulator for a specified number of milliseconds or cycles first. These
// expected-value reports are all stored in a vector: // expected-value reports are all stored in a vector:
std::vector<ExpectedKeyboardReport> expected_reports_ = {}; std::vector<ExpectedKeyboardReport> expected_keyboard_reports_ = {};
void ExpectReport(AddKeycodes added_keys, void ExpectKeyboardReport(AddKeycodes added_keys,
RemoveKeycodes removed_keys, RemoveKeycodes removed_keys,
std::string description); std::string description);
void ExpectReport(Keycodes added_keys, std::string description); void ExpectKeyboardReport(Keycodes added_keys, std::string description);
void ExpectReport(AddKeycodes added_keys, std::string description); void ExpectKeyboardReport(AddKeycodes added_keys, std::string description);
void ExpectReport(RemoveKeycodes removed_keys, std::string description); void ExpectKeyboardReport(RemoveKeycodes removed_keys, std::string description);
std::vector<ExpectedMouseReport> 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<uint8_t> current_keyboard_keycodes_ = {}; std::set<uint8_t> current_keyboard_keycodes_ = {};
// Manage the set of keycodes expected in the next report // Manage the set of keycodes expected in the next report
void ClearReport(); void ClearKeyboardReport();
void AddToReport(Key key); void AddToKeyboardReport(Key key);
void RemoveFromReport(Key key); void RemoveFromKeyboardReport(Key key);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Compare accumulated observed and expected reports, matching both timestamps // Compare accumulated observed and expected reports, matching both timestamps
// and keycodes. // and keycodes.
void CheckReports() const; void CheckReports() const;
void CheckKeyboardReports() const;
void CheckMouseReports() const;
}; };

@ -138,6 +138,76 @@ sub load_from_text {
keys => [@keys] 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 { else {
die "Don't know how parse $content at line $line_num"; die "Don't know how parse $content at line $line_num";
} }
@ -394,15 +464,22 @@ sub generate_release {
sub generate_expect_report { sub generate_expect_report {
my $report = shift; my $report = shift;
if ( !$report->{data}->{report_type} if ( $report->{data}->{report_type} eq 'keyboard' ) {
|| $report->{data}->{report_type} ne 'keyboard' ) generate_expect_keyboard_report($report);
{ }
elsif ( $report->{data}->{report_type} eq 'mouse' ) {
generate_expect_mouse_report($report);
}
else {
die 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"; . $report->{line_num} . "\n";
} }
$reports_expected++; $reports_expected++;
}
sub generate_expect_keyboard_report {
my $report = shift;
if ( $report->{data}->{count} == 0 ) { if ( $report->{data}->{count} == 0 ) {
if ( $report->{comment} ) { if ( $report->{comment} ) {
@ -422,7 +499,38 @@ sub generate_expect_report {
: ( $report->{data}->{keys} ) : ( $report->{data}->{keys} )
) )
); );
cxx( "ExpectReport(Keycodes{$codes}, \"" cxx( "ExpectKeyboardReport(Keycodes{$codes}, \""
. ( $report->{comment} || 'No explanatory comment specified' )
. "\");" );
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' ) . ( $report->{comment} || 'No explanatory comment specified' )
. "\");" ); . "\");" );
cxx(""); cxx("");

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-MouseKeys.h>
// *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();
}

@ -0,0 +1,6 @@
{
"cpu": {
"fqbn": "keyboardio:virtual:model01",
"port": ""
}
}

@ -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
Loading…
Cancel
Save