blob: ba264b0abf8420e1b4925aeefcf0a0d125422ab9 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ui/lib/input_reader/stylus.h"
#include <fuchsia/ui/input/cpp/fidl.h>
#include <gtest/gtest.h>
#include <hid-parser/parser.h>
#include <hid-parser/usages.h>
#include <hid/acer12.h>
#include <hid/paradise.h>
#include "src/lib/fxl/time/time_point.h"
namespace input {
namespace {
bool usage_is_stylus(hid::Usage usage) {
using ::hid::usage::Digitizer;
using ::hid::usage::Page;
return ((usage == hid::USAGE(Page::kDigitizer, Digitizer::kStylus)) ||
(usage == hid::USAGE(Page::kDigitizer, Digitizer::kPen)));
}
const hid::ReportDescriptor *get_stylus_descriptor(const hid::DeviceDescriptor *dev_desc) {
const hid::ReportDescriptor *desc = nullptr;
for (size_t rep = 0; rep < dev_desc->rep_count; rep++) {
const hid::ReportDescriptor *tmp_desc = &dev_desc->report[rep];
// Traverse up the nested collections to the Application collection.
hid::Collection *collection = tmp_desc->input_fields[0].col;
while (collection != nullptr) {
if (collection->type == hid::CollectionType::kApplication) {
break;
}
collection = collection->parent;
}
if (!collection) {
return nullptr;
}
if (usage_is_stylus(collection->usage)) {
desc = tmp_desc;
break;
}
}
return desc;
}
} // namespace
// Each test parses the report descriptor for the mouse and then sends one
// report to ensure that it has been parsed correctly.
namespace test {
TEST(StylusTest, Paradise) {
hid::DeviceDescriptor *dev_desc = nullptr;
size_t desc_size;
const uint8_t *paradise_touch_v1_report_desc = get_paradise_touch_report_desc(&desc_size);
auto parse_res = hid::ParseReportDescriptor(paradise_touch_v1_report_desc, desc_size, &dev_desc);
ASSERT_EQ(hid::ParseResult::kParseOk, parse_res);
auto desc = get_stylus_descriptor(dev_desc);
ASSERT_NE(nullptr, desc);
ui_input::Stylus stylus = {};
ui_input::Device::Descriptor device_descriptor = {};
bool success = stylus.ParseReportDescriptor(*desc, &device_descriptor);
ASSERT_TRUE(success);
ASSERT_TRUE(device_descriptor.has_stylus);
ASSERT_TRUE(device_descriptor.stylus_descriptor != nullptr);
EXPECT_EQ(0, device_descriptor.stylus_descriptor->x.range.min);
EXPECT_EQ(25920, device_descriptor.stylus_descriptor->x.range.max);
EXPECT_EQ(0, device_descriptor.stylus_descriptor->y.range.min);
EXPECT_EQ(17280, device_descriptor.stylus_descriptor->y.range.max);
EXPECT_TRUE(device_descriptor.stylus_descriptor->is_invertible);
EXPECT_EQ(fuchsia::ui::input::kStylusBarrel, device_descriptor.stylus_descriptor->buttons);
const uint8_t report_data[20] = {
0x06, // Report ID
0xFF, // Tip switch, barrel switch, eraser, invert, in_range
0x34, 0x12, // X
0x34, 0x12, // Y
0x20, 0x00, // Tip pressure
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
fuchsia::ui::input::InputReport report;
report.stylus = fuchsia::ui::input::StylusReport::New();
success = stylus.ParseReport(report_data, sizeof(report_data), &report);
ASSERT_EQ(true, success);
// Multiply by a hundred for the unit standardization
EXPECT_EQ(0x1234 * 100, report.stylus->x);
EXPECT_EQ(0x1234 * 100, report.stylus->y);
EXPECT_EQ(0x20U, report.stylus->pressure);
EXPECT_EQ(true, report.stylus->is_in_contact);
EXPECT_EQ(true, report.stylus->is_inverted);
EXPECT_EQ(fuchsia::ui::input::kStylusBarrel, report.stylus->pressed_buttons);
}
TEST(StylusTest, Acer12) {
hid::DeviceDescriptor *dev_desc = nullptr;
size_t desc_size;
const uint8_t *acer12_touch_report_desc = get_acer12_touch_report_desc(&desc_size);
auto parse_res = hid::ParseReportDescriptor(acer12_touch_report_desc, desc_size, &dev_desc);
ASSERT_EQ(hid::ParseResult::kParseOk, parse_res);
auto desc = get_stylus_descriptor(dev_desc);
ASSERT_NE(nullptr, desc);
ui_input::Stylus stylus = {};
ui_input::Device::Descriptor device_descriptor = {};
bool success = stylus.ParseReportDescriptor(*desc, &device_descriptor);
ASSERT_TRUE(success);
ASSERT_TRUE(device_descriptor.has_stylus);
ASSERT_TRUE(device_descriptor.stylus_descriptor != nullptr);
EXPECT_EQ(0, device_descriptor.stylus_descriptor->x.range.min);
EXPECT_EQ(254, device_descriptor.stylus_descriptor->x.range.max);
EXPECT_EQ(0, device_descriptor.stylus_descriptor->y.range.min);
EXPECT_EQ(169, device_descriptor.stylus_descriptor->y.range.max);
EXPECT_TRUE(device_descriptor.stylus_descriptor->is_invertible);
EXPECT_EQ(fuchsia::ui::input::kStylusBarrel, device_descriptor.stylus_descriptor->buttons);
const uint8_t report_data[8] = {
0x07, // Report ID
0xFF, // Tip switch, barrel switch, eraser, invert, in_range
0x23, 0x01, // X
0x23, 0x01, // Y
0x20, 0x00, // Tip pressure
};
fuchsia::ui::input::InputReport report;
report.stylus = fuchsia::ui::input::StylusReport::New();
success = stylus.ParseReport(report_data, sizeof(report_data), &report);
ASSERT_EQ(true, success);
// Manually calculated logical -> physical units
EXPECT_EQ(183318, report.stylus->x);
EXPECT_EQ(178702, report.stylus->y);
EXPECT_EQ(0x20U, report.stylus->pressure);
EXPECT_EQ(true, report.stylus->is_in_contact);
EXPECT_EQ(true, report.stylus->is_inverted);
EXPECT_EQ(fuchsia::ui::input::kStylusBarrel, report.stylus->pressed_buttons);
}
} // namespace test
} // namespace input