blob: e2108e02458919f27b3c65eed924567fad79d3cc [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/input/lib/hid-input-report/mouse.h"
#include <stdint.h>
#include <hid-parser/parser.h>
#include <hid-parser/report.h>
#include <hid-parser/units.h>
#include <hid-parser/usages.h>
#include "src/ui/input/lib/hid-input-report/device.h"
namespace hid_input_report {
ParseResult Mouse::ParseReportDescriptor(const hid::ReportDescriptor& hid_report_descriptor) {
std::optional<hid::Attributes> movement_x;
std::optional<hid::Attributes> movement_y;
std::optional<hid::Attributes> position_x;
std::optional<hid::Attributes> position_y;
std::optional<hid::Attributes> scroll_v;
hid::Attributes buttons[fuchsia_input_report::MOUSE_MAX_NUM_BUTTONS];
uint8_t num_buttons = 0;
for (size_t i = 0; i < hid_report_descriptor.input_count; i++) {
const hid::ReportField& field = hid_report_descriptor.input_fields[i];
if (field.attr.usage ==
hid::USAGE(hid::usage::Page::kGenericDesktop, hid::usage::GenericDesktop::kX)) {
if (field.flags & hid::FieldTypeFlags::kAbsolute) {
position_x = field.attr;
} else {
movement_x = field.attr;
}
} else if (field.attr.usage ==
hid::USAGE(hid::usage::Page::kGenericDesktop, hid::usage::GenericDesktop::kY)) {
if (field.flags & hid::FieldTypeFlags::kAbsolute) {
position_y = field.attr;
} else {
movement_y = field.attr;
}
} else if (field.attr.usage ==
hid::USAGE(hid::usage::Page::kGenericDesktop, hid::usage::GenericDesktop::kWheel)) {
scroll_v = field.attr;
} else if (field.attr.usage.page == hid::usage::Page::kButton) {
if (num_buttons == fuchsia_input_report::MOUSE_MAX_NUM_BUTTONS) {
return ParseResult::kTooManyItems;
}
buttons[num_buttons++] = field.attr;
}
}
// No error, write to class members.
if (movement_x) {
movement_x_ = movement_x;
}
if (movement_y) {
movement_y_ = movement_y;
}
if (position_x) {
position_x_ = position_x;
}
if (position_y) {
position_y_ = position_y;
}
if (scroll_v) {
scroll_v_ = scroll_v;
}
for (size_t i = 0; i < num_buttons; i++) {
buttons_[i] = buttons[i];
}
num_buttons_ = num_buttons;
report_size_ = hid_report_descriptor.input_byte_sz;
report_id_ = hid_report_descriptor.report_id;
return ParseResult::kOk;
}
ParseResult Mouse::CreateDescriptor(fidl::Allocator* allocator,
fuchsia_input_report::DeviceDescriptor::Builder* descriptor) {
auto mouse_input = fuchsia_input_report::MouseInputDescriptor::Builder(
allocator->make<fuchsia_input_report::MouseInputDescriptor::Frame>());
if (movement_x_) {
mouse_input.set_movement_x(
allocator->make<fuchsia_input_report::Axis>(LlcppAxisFromAttribute(*movement_x_)));
}
if (movement_y_) {
mouse_input.set_movement_y(
allocator->make<fuchsia_input_report::Axis>(LlcppAxisFromAttribute(*movement_y_)));
}
if (position_x_) {
mouse_input.set_position_x(
allocator->make<fuchsia_input_report::Axis>(LlcppAxisFromAttribute(*position_x_)));
}
if (position_y_) {
mouse_input.set_position_y(
allocator->make<fuchsia_input_report::Axis>(LlcppAxisFromAttribute(*position_y_)));
}
if (scroll_v_) {
mouse_input.set_scroll_v(
allocator->make<fuchsia_input_report::Axis>(LlcppAxisFromAttribute(*scroll_v_)));
}
// Set the buttons array.
{
auto buttons = allocator->make<uint8_t[]>(num_buttons_);
size_t index = 0;
for (auto& button : buttons_) {
buttons[index++] = button.usage.usage;
}
auto buttons_view =
allocator->make<fidl::VectorView<uint8_t>>(std::move(buttons), num_buttons_);
mouse_input.set_buttons(std::move(buttons_view));
}
auto mouse = fuchsia_input_report::MouseDescriptor::Builder(
allocator->make<fuchsia_input_report::MouseDescriptor::Frame>());
mouse.set_input(allocator->make<fuchsia_input_report::MouseInputDescriptor>(mouse_input.build()));
descriptor->set_mouse(allocator->make<fuchsia_input_report::MouseDescriptor>(mouse.build()));
return ParseResult::kOk;
}
ParseResult Mouse::ParseInputReport(const uint8_t* data, size_t len, fidl::Allocator* allocator,
fuchsia_input_report::InputReport::Builder* report) {
if (len != report_size_) {
return ParseResult::kReportSizeMismatch;
}
auto mouse_report = fuchsia_input_report::MouseInputReport::Builder(
allocator->make<fuchsia_input_report::MouseInputReport::Frame>());
if (movement_x_) {
mouse_report.set_movement_x(Extract<int64_t>(data, len, *movement_x_, allocator));
}
if (movement_y_) {
mouse_report.set_movement_y(Extract<int64_t>(data, len, *movement_y_, allocator));
}
if (position_x_) {
mouse_report.set_position_x(Extract<int64_t>(data, len, *position_x_, allocator));
}
if (position_y_) {
mouse_report.set_position_y(Extract<int64_t>(data, len, *position_y_, allocator));
}
if (scroll_v_) {
mouse_report.set_scroll_v(Extract<int64_t>(data, len, *scroll_v_, allocator));
}
std::array<uint8_t, fuchsia_input_report::MOUSE_MAX_NUM_BUTTONS> buttons;
size_t buttons_size = 0;
for (size_t i = 0; i < num_buttons_; i++) {
double value_out;
if (hid::ExtractAsUnitType(data, len, buttons_[i], &value_out)) {
uint8_t pressed = (value_out > 0) ? 1 : 0;
if (pressed) {
buttons[buttons_size++] = static_cast<uint8_t>(buttons_[i].usage.usage);
}
}
}
auto fidl_buttons = allocator->make<uint8_t[]>(buttons_size);
for (size_t i = 0; i < buttons_size; i++) {
fidl_buttons[i] = buttons[i];
}
mouse_report.set_pressed_buttons(
allocator->make<fidl::VectorView<uint8_t>>(std::move(fidl_buttons), buttons_size));
report->set_mouse(allocator->make<fuchsia_input_report::MouseInputReport>(mouse_report.build()));
return ParseResult::kOk;
}
} // namespace hid_input_report