blob: 538716b14f4542b0d86ca739376f9b7cd0c432d0 [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/consumer_control.h"
#include <stdint.h>
#include <set>
#include <fbl/span.h>
#include <hid-parser/parser.h>
#include <hid-parser/report.h>
#include <hid-parser/units.h>
#include <hid-parser/usages.h>
#include <hid/usages.h>
#include "src/ui/input/lib/hid-input-report/device.h"
namespace hid_input_report {
namespace {
std::optional<fuchsia_input_report::ConsumerControlButton> HidToConsumerControlButton(
hid::Usage usage) {
struct {
hid::Usage usage;
fuchsia_input_report::ConsumerControlButton button;
} usage_to_button[] = {
{hid::USAGE(hid::usage::Page::kConsumer, hid::usage::Consumer::kVolumeUp),
fuchsia_input_report::ConsumerControlButton::VOLUME_UP},
{hid::USAGE(hid::usage::Page::kConsumer, hid::usage::Consumer::kVolumeDown),
fuchsia_input_report::ConsumerControlButton::VOLUME_DOWN},
{hid::USAGE(hid::usage::Page::kConsumer, hid::usage::Consumer::kReset),
fuchsia_input_report::ConsumerControlButton::REBOOT},
{hid::USAGE(hid::usage::Page::kConsumer, hid::usage::Consumer::kCameraAccessDisabled),
fuchsia_input_report::ConsumerControlButton::CAMERA_DISABLE},
{hid::USAGE(hid::usage::Page::kTelephony, hid::usage::Telephony::kPhoneMute),
fuchsia_input_report::ConsumerControlButton::MIC_MUTE},
};
for (auto& map : usage_to_button) {
if (map.usage == usage) {
return map.button;
}
}
return std::nullopt;
}
} // namespace
ParseResult ConsumerControl::ParseInputReportDescriptor(
const hid::ReportDescriptor& hid_report_descriptor) {
std::array<hid::ReportField, fuchsia_input_report::CONSUMER_CONTROL_MAX_NUM_BUTTONS>
button_fields;
size_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];
auto button = HidToConsumerControlButton(field.attr.usage);
if (button) {
if (num_buttons >= button_fields.size()) {
return ParseResult::kTooManyItems;
}
button_fields[num_buttons] = field;
num_buttons += 1;
}
}
// No error, write to class members.
num_buttons_ = num_buttons;
button_fields_ = button_fields;
input_report_size_ = hid_report_descriptor.input_byte_sz;
input_report_id_ = hid_report_descriptor.report_id;
return ParseResult::kOk;
}
ParseResult ConsumerControl::ParseReportDescriptor(
const hid::ReportDescriptor& hid_report_descriptor) {
return ParseInputReportDescriptor(hid_report_descriptor);
};
ParseResult ConsumerControl::CreateDescriptor(
fidl::Allocator* allocator, fuchsia_input_report::DeviceDescriptor::Builder* descriptor) {
auto input = fuchsia_input_report::ConsumerControlInputDescriptor::Builder(
allocator->make<fuchsia_input_report::ConsumerControlInputDescriptor::Frame>());
// Set the buttons array.
{
auto buttons = allocator->make<fuchsia_input_report::ConsumerControlButton[]>(num_buttons_);
for (size_t i = 0; i < num_buttons_; i++) {
auto button = HidToConsumerControlButton(button_fields_[i].attr.usage);
if (button) {
buttons[i] = *button;
}
}
auto buttons_view =
allocator->make<fidl::VectorView<fuchsia_input_report::ConsumerControlButton>>(
std::move(buttons), num_buttons_);
input.set_buttons(std::move(buttons_view));
}
auto consumer = fuchsia_input_report::ConsumerControlDescriptor::Builder(
allocator->make<fuchsia_input_report::ConsumerControlDescriptor::Frame>());
consumer.set_input(
allocator->make<fuchsia_input_report::ConsumerControlInputDescriptor>(input.build()));
descriptor->set_consumer_control(
allocator->make<fuchsia_input_report::ConsumerControlDescriptor>(consumer.build()));
return ParseResult::kOk;
}
ParseResult ConsumerControl::ParseInputReport(const uint8_t* data, size_t len,
fidl::Allocator* allocator,
fuchsia_input_report::InputReport::Builder* report) {
auto consumer_report = fuchsia_input_report::ConsumerControlInputReport::Builder(
allocator->make<fuchsia_input_report::ConsumerControlInputReport::Frame>());
std::array<fuchsia_input_report::ConsumerControlButton,
fuchsia_input_report::CONSUMER_CONTROL_MAX_NUM_BUTTONS>
buttons;
size_t buttons_size = 0;
for (const hid::ReportField& field : button_fields_) {
double val_out;
if (!ExtractAsUnitType(data, len, field.attr, &val_out)) {
continue;
}
if (static_cast<uint32_t>(val_out) == 0) {
continue;
}
auto button = HidToConsumerControlButton(field.attr.usage);
if (!button) {
continue;
}
buttons[buttons_size++] = *button;
}
auto fidl_buttons = allocator->make<fuchsia_input_report::ConsumerControlButton[]>(buttons_size);
for (size_t i = 0; i < buttons_size; i++) {
fidl_buttons[i] = buttons[i];
}
consumer_report.set_pressed_buttons(
allocator->make<fidl::VectorView<fuchsia_input_report::ConsumerControlButton>>(
std::move(fidl_buttons), buttons_size));
report->set_consumer_control(
allocator->make<fuchsia_input_report::ConsumerControlInputReport>(consumer_report.build()));
return ParseResult::kOk;
}
} // namespace hid_input_report