| // 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 |