blob: fc80cd4d53e7d4f7ce9559a36d77ed6a574a28be [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 <lib/hid-parser/parser.h>
#include <lib/hid-parser/report.h>
#include <lib/hid-parser/units.h>
#include <lib/hid-parser/usages.h>
#include <stdint.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::wire::kMouseMaxNumButtons];
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::wire::kMouseMaxNumButtons) {
return ParseResult::kTooManyItems;
}
buttons[num_buttons++] = field.attr;
}
}
if (!movement_x && !movement_y && !position_x && !position_y && !scroll_v && (num_buttons == 0)) {
return ParseResult::kItemNotFound;
}
// 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::AnyArena& allocator,
fuchsia_input_report::wire::DeviceDescriptor& descriptor) {
fuchsia_input_report::wire::MouseInputDescriptor mouse_input(allocator);
if (movement_x_) {
mouse_input.set_movement_x(allocator, LlcppAxisFromAttribute(*movement_x_));
}
if (movement_y_) {
mouse_input.set_movement_y(allocator, LlcppAxisFromAttribute(*movement_y_));
}
if (position_x_) {
mouse_input.set_position_x(allocator, LlcppAxisFromAttribute(*position_x_));
}
if (position_y_) {
mouse_input.set_position_y(allocator, LlcppAxisFromAttribute(*position_y_));
}
if (scroll_v_) {
mouse_input.set_scroll_v(allocator, LlcppAxisFromAttribute(*scroll_v_));
}
// Set the buttons array.
{
fidl::VectorView<uint8_t> buttons(allocator, num_buttons_);
size_t index = 0;
for (auto& button : buttons_) {
buttons[index++] = button.usage.usage;
}
mouse_input.set_buttons(allocator, std::move(buttons));
}
fuchsia_input_report::wire::MouseDescriptor mouse(allocator);
mouse.set_input(allocator, std::move(mouse_input));
descriptor.set_mouse(allocator, std::move(mouse));
return ParseResult::kOk;
}
ParseResult Mouse::ParseInputReportInternal(const uint8_t* data, size_t len,
fidl::AnyArena& allocator,
fuchsia_input_report::wire::InputReport& input_report) {
if (len != report_size_) {
return ParseResult::kReportSizeMismatch;
}
fuchsia_input_report::wire::MouseInputReport mouse_report(allocator);
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::wire::kMouseMaxNumButtons> 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);
}
}
}
fidl::VectorView<uint8_t> fidl_buttons(allocator, buttons_size);
for (size_t i = 0; i < buttons_size; i++) {
fidl_buttons[i] = buttons[i];
}
mouse_report.set_pressed_buttons(allocator, std::move(fidl_buttons));
input_report.set_mouse(allocator, std::move(mouse_report));
return ParseResult::kOk;
}
} // namespace hid_input_report