blob: d19463c52f8f5eda616ee314cb17f7d779385598 [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 <lib/hid-parser/parser.h>
#include <lib/hid-parser/report.h>
#include <lib/hid-parser/units.h>
#include <lib/hid-parser/usages.h>
#include <lib/hid/usages.h>
#include <lib/stdcompat/span.h>
#include <stdint.h>
#include <set>
#include "src/ui/input/lib/hid-input-report/device.h"
namespace hid_input_report {
using fuchsia_input_report::wire::ConsumerControlButton;
namespace {
std::optional<fuchsia_input_report::wire::ConsumerControlButton> HidToConsumerControlButton(
hid::Usage usage) {
struct {
hid::Usage usage;
ConsumerControlButton button;
} usage_to_button[] = {
{hid::USAGE(hid::usage::Page::kConsumer, hid::usage::Consumer::kVolumeUp),
ConsumerControlButton::kVolumeUp},
{hid::USAGE(hid::usage::Page::kConsumer, hid::usage::Consumer::kVolumeDown),
ConsumerControlButton::kVolumeDown},
{hid::USAGE(hid::usage::Page::kConsumer, hid::usage::Consumer::kReset),
ConsumerControlButton::kFactoryReset},
{hid::USAGE(hid::usage::Page::kConsumer, hid::usage::Consumer::kCameraAccessDisabled),
ConsumerControlButton::kCameraDisable},
{hid::USAGE(hid::usage::Page::kConsumer, hid::usage::Consumer::kPause),
ConsumerControlButton::kPause},
{hid::USAGE(hid::usage::Page::kTelephony, hid::usage::Telephony::kPhoneMute),
ConsumerControlButton::kMicMute},
};
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::wire::kConsumerControlMaxNumButtons>
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::AnyArena& allocator, fuchsia_input_report::wire::DeviceDescriptor& descriptor) {
fuchsia_input_report::wire::ConsumerControlInputDescriptor input(allocator);
// Set the buttons array.
{
fidl::VectorView<ConsumerControlButton> buttons(allocator, num_buttons_);
for (size_t i = 0; i < num_buttons_; i++) {
auto button = HidToConsumerControlButton(button_fields_[i].attr.usage);
if (button) {
buttons[i] = *button;
}
}
input.set_buttons(allocator, std::move(buttons));
}
fuchsia_input_report::wire::ConsumerControlDescriptor consumer(allocator);
consumer.set_input(allocator, std::move(input));
descriptor.set_consumer_control(allocator, std::move(consumer));
return ParseResult::kOk;
}
ParseResult ConsumerControl::ParseInputReportInternal(
const uint8_t* data, size_t len, fidl::AnyArena& allocator,
fuchsia_input_report::wire::InputReport& input_report) {
fuchsia_input_report::wire::ConsumerControlInputReport consumer_report(allocator);
std::array<ConsumerControlButton, fuchsia_input_report::wire::kConsumerControlMaxNumButtons>
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;
}
fidl::VectorView<ConsumerControlButton> fidl_buttons(allocator, buttons_size);
for (size_t i = 0; i < buttons_size; i++) {
fidl_buttons[i] = buttons[i];
}
consumer_report.set_pressed_buttons(allocator, std::move(fidl_buttons));
input_report.set_consumer_control(allocator, std::move(consumer_report));
return ParseResult::kOk;
}
} // namespace hid_input_report