| // Copyright 2020 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/lib/input_report_reader/input_interpreter.h" |
| |
| #include <fuchsia/ui/input/cpp/fidl.h> |
| #include <lib/fidl/cpp/clone.h> |
| #include <sys/types.h> |
| #include <sys/uio.h> |
| #include <zircon/errors.h> |
| #include <zircon/types.h> |
| |
| #include <trace/event.h> |
| |
| #include "src/lib/fxl/arraysize.h" |
| #include "src/lib/fxl/logging.h" |
| |
| namespace ui_input { |
| |
| namespace { |
| |
| fuchsia::ui::input::Axis ConvertAxis(fuchsia::input::report::Axis axis) { |
| fuchsia::ui::input::Axis a = {}; |
| a.range.min = axis.range.min; |
| a.range.max = axis.range.max; |
| return a; |
| } |
| |
| // Sets the fuchsia::ui::input Mouse button bit vector. |
| // prev_buttons represents the current button bit vector. |
| // button_id is the new button to set. |
| // The function returns the new button bit vector. |
| uint32_t SetMouseButton(uint32_t prev_buttons, uint8_t button_id) { |
| if (button_id == 0 || button_id > 32) { |
| return prev_buttons; |
| } |
| return prev_buttons | (1 << (button_id - 1)); |
| } |
| |
| } // namespace |
| |
| InputInterpreter::InputInterpreter(zx::channel channel, |
| fuchsia::ui::input::InputDeviceRegistry* registry, |
| std::string name) |
| : device_(std::move(channel)), registry_(registry), name_(name) {} |
| |
| InputInterpreter::~InputInterpreter() {} |
| |
| void InputInterpreter::DispatchReport(const fuchsia::ui::input::InputDevicePtr& device, |
| fuchsia::ui::input::InputReport report) { |
| report.trace_id = TRACE_NONCE(); |
| TRACE_FLOW_BEGIN("input", "hid_read_to_listener", report.trace_id); |
| device->DispatchReport(std::move(report)); |
| } |
| |
| bool InputInterpreter::Initialize() { |
| // Get the event. |
| zx_status_t out_status; |
| zx_status_t status = device_.GetReportsEvent(&out_status, &event_); |
| if ((status != ZX_OK) || (out_status != ZX_OK)) { |
| return false; |
| } |
| |
| RegisterDevices(); |
| |
| return true; |
| } |
| |
| void InputInterpreter::RegisterConsumerControl( |
| const fuchsia::input::report::DeviceDescriptor& descriptor) { |
| fuchsia::ui::input::DeviceDescriptor ui_descriptor; |
| |
| if (descriptor.has_device_info()) { |
| auto info = std::make_unique<fuchsia::ui::input::DeviceInfo>(); |
| info->vendor_id = descriptor.device_info().vendor_id; |
| info->product_id = descriptor.device_info().product_id; |
| info->version = descriptor.device_info().version; |
| ui_descriptor.device_info = std::move(info); |
| } |
| |
| auto media_buttons = std::make_unique<fuchsia::ui::input::MediaButtonsDescriptor>(); |
| if (descriptor.consumer_control().input().has_buttons()) { |
| for (auto button : descriptor.consumer_control().input().buttons()) { |
| switch (button) { |
| case fuchsia::input::report::ConsumerControlButton::VOLUME_UP: |
| media_buttons->buttons |= fuchsia::ui::input::kVolumeUp; |
| break; |
| case fuchsia::input::report::ConsumerControlButton::VOLUME_DOWN: |
| media_buttons->buttons |= fuchsia::ui::input::kVolumeDown; |
| break; |
| case fuchsia::input::report::ConsumerControlButton::MIC_MUTE: |
| media_buttons->buttons |= fuchsia::ui::input::kMicMute; |
| break; |
| case fuchsia::input::report::ConsumerControlButton::PAUSE: |
| media_buttons->buttons |= fuchsia::ui::input::kPause; |
| break; |
| case fuchsia::input::report::ConsumerControlButton::REBOOT: |
| media_buttons->buttons |= fuchsia::ui::input::kReset; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| ui_descriptor.media_buttons = std::move(media_buttons); |
| registry_->RegisterDevice(std::move(ui_descriptor), consumer_control_ptr_.NewRequest()); |
| } |
| |
| void InputInterpreter::RegisterMouse(const fuchsia::input::report::DeviceDescriptor& descriptor) { |
| fuchsia::ui::input::DeviceDescriptor ui_descriptor; |
| |
| if (descriptor.has_device_info()) { |
| auto info = std::make_unique<fuchsia::ui::input::DeviceInfo>(); |
| info->vendor_id = descriptor.device_info().vendor_id; |
| info->product_id = descriptor.device_info().product_id; |
| info->version = descriptor.device_info().version; |
| ui_descriptor.device_info = std::move(info); |
| } |
| |
| auto mouse = std::make_unique<fuchsia::ui::input::MouseDescriptor>(); |
| if (descriptor.mouse().input().has_movement_x()) { |
| mouse->rel_x = ConvertAxis(descriptor.mouse().input().movement_x()); |
| } |
| if (descriptor.mouse().input().has_movement_y()) { |
| mouse->rel_y = ConvertAxis(descriptor.mouse().input().movement_y()); |
| } |
| if (descriptor.mouse().input().has_buttons()) { |
| for (uint8_t button : descriptor.mouse().input().buttons()) { |
| mouse->buttons = SetMouseButton(mouse->buttons, button); |
| } |
| } |
| ui_descriptor.mouse = std::move(mouse); |
| registry_->RegisterDevice(std::move(ui_descriptor), mouse_ptr_.NewRequest()); |
| } |
| |
| void InputInterpreter::RegisterTouchscreen( |
| const fuchsia::input::report::DeviceDescriptor& descriptor) { |
| fuchsia::ui::input::DeviceDescriptor ui_descriptor; |
| |
| if (descriptor.has_device_info()) { |
| auto info = std::make_unique<fuchsia::ui::input::DeviceInfo>(); |
| info->vendor_id = descriptor.device_info().vendor_id; |
| info->product_id = descriptor.device_info().product_id; |
| info->version = descriptor.device_info().version; |
| ui_descriptor.device_info = std::move(info); |
| } |
| |
| auto touch = std::make_unique<fuchsia::ui::input::TouchscreenDescriptor>(); |
| if (descriptor.touch().input().has_contacts()) { |
| if (descriptor.touch().input().contacts()[0].has_position_x()) { |
| touch->x.range.min = descriptor.touch().input().contacts()[0].position_x().range.min; |
| touch->x.range.max = descriptor.touch().input().contacts()[0].position_x().range.max; |
| } |
| if (descriptor.touch().input().contacts()[0].has_position_y()) { |
| touch->y.range.min = descriptor.touch().input().contacts()[0].position_y().range.min; |
| touch->y.range.max = descriptor.touch().input().contacts()[0].position_y().range.max; |
| } |
| } |
| if (descriptor.touch().input().has_max_contacts()) { |
| touch->max_finger_id = descriptor.touch().input().max_contacts(); |
| } |
| ui_descriptor.touchscreen = std::move(touch); |
| registry_->RegisterDevice(std::move(ui_descriptor), touch_ptr_.NewRequest()); |
| } |
| |
| void InputInterpreter::RegisterDevices() { |
| fuchsia::input::report::DeviceDescriptor descriptor; |
| zx_status_t status = device_.GetDescriptor(&descriptor); |
| if (status != ZX_OK) { |
| return; |
| } |
| |
| if (descriptor.has_touch() && descriptor.touch().has_input()) { |
| if (descriptor.touch().input().has_touch_type() && |
| (descriptor.touch().input().touch_type() == |
| fuchsia::input::report::TouchType::TOUCHSCREEN)) { |
| RegisterTouchscreen(descriptor); |
| } |
| } |
| |
| if (descriptor.has_mouse() && descriptor.mouse().has_input()) { |
| RegisterMouse(descriptor); |
| } |
| |
| if (descriptor.has_consumer_control() && descriptor.consumer_control().has_input()) { |
| RegisterConsumerControl(descriptor); |
| } |
| } |
| |
| void InputInterpreter::DispatchTouchReport(const fuchsia::input::report::InputReport& report) { |
| fuchsia::ui::input::InputReport input_report; |
| if (report.has_event_time()) { |
| input_report.event_time = report.event_time(); |
| } |
| auto input_touchscreen = std::make_unique<fuchsia::ui::input::TouchscreenReport>(); |
| if (report.touch().has_contacts()) { |
| for (const fuchsia::input::report::ContactInputReport& contact : report.touch().contacts()) { |
| fuchsia::ui::input::Touch input_touch; |
| if (contact.has_contact_id()) { |
| input_touch.finger_id = contact.contact_id(); |
| } |
| if (contact.has_position_x()) { |
| input_touch.x = contact.position_x(); |
| } |
| if (contact.has_position_y()) { |
| input_touch.y = contact.position_y(); |
| } |
| input_touchscreen->touches.push_back(std::move(input_touch)); |
| } |
| } |
| input_report.touchscreen = std::move(input_touchscreen); |
| DispatchReport(touch_ptr_, std::move(input_report)); |
| } |
| |
| void InputInterpreter::DispatchMouseReport(const fuchsia::input::report::InputReport& report) { |
| fuchsia::ui::input::InputReport input_report; |
| if (report.has_event_time()) { |
| input_report.event_time = report.event_time(); |
| } |
| auto input_mouse = std::make_unique<fuchsia::ui::input::MouseReport>(); |
| if (report.mouse().has_movement_x()) { |
| input_mouse->rel_x = report.mouse().movement_x(); |
| } |
| if (report.mouse().has_movement_y()) { |
| input_mouse->rel_y = report.mouse().movement_y(); |
| } |
| if (report.mouse().has_pressed_buttons()) { |
| for (uint8_t button : report.mouse().pressed_buttons()) { |
| input_mouse->pressed_buttons = SetMouseButton(input_mouse->pressed_buttons, button); |
| } |
| } |
| input_report.mouse = std::move(input_mouse); |
| DispatchReport(mouse_ptr_, std::move(input_report)); |
| } |
| |
| void InputInterpreter::DispatchConsumerControlReport( |
| const fuchsia::input::report::InputReport& report) { |
| fuchsia::ui::input::InputReport input_report; |
| if (report.has_event_time()) { |
| input_report.event_time = report.event_time(); |
| } |
| auto media_buttons = std::make_unique<fuchsia::ui::input::MediaButtonsReport>(); |
| if (report.consumer_control().has_pressed_buttons()) { |
| for (const fuchsia::input::report::ConsumerControlButton& button : |
| report.consumer_control().pressed_buttons()) { |
| switch (button) { |
| case fuchsia::input::report::ConsumerControlButton::VOLUME_UP: |
| media_buttons->volume_up = true; |
| break; |
| case fuchsia::input::report::ConsumerControlButton::VOLUME_DOWN: |
| media_buttons->volume_down = true; |
| break; |
| case fuchsia::input::report::ConsumerControlButton::MIC_MUTE: |
| media_buttons->mic_mute = true; |
| break; |
| case fuchsia::input::report::ConsumerControlButton::PAUSE: |
| media_buttons->pause = true; |
| break; |
| case fuchsia::input::report::ConsumerControlButton::REBOOT: |
| media_buttons->reset = true; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| input_report.media_buttons = std::move(media_buttons); |
| DispatchReport(consumer_control_ptr_, std::move(input_report)); |
| } |
| |
| bool InputInterpreter::Read(bool discard) { |
| TRACE_DURATION("input", "input_report_reader Read"); |
| std::vector<fuchsia::input::report::InputReport> reports; |
| zx_status_t status = device_.GetReports(&reports); |
| if (status != ZX_OK) { |
| return false; |
| } |
| if (discard) { |
| return true; |
| } |
| |
| for (const auto& report : reports) { |
| if (report.has_trace_id()) { |
| TRACE_FLOW_END("input", "input_report", report.trace_id()); |
| } |
| if (report.has_touch()) { |
| DispatchTouchReport(report); |
| } |
| if (report.has_consumer_control()) { |
| DispatchConsumerControlReport(report); |
| } |
| if (report.has_mouse()) { |
| DispatchMouseReport(report); |
| } |
| } |
| |
| // Create reports and call DispatchReport |
| return true; |
| } |
| |
| } // namespace ui_input |