blob: 7f2a3050ec84285f38b9995015c1ab7babd384d7 [file] [log] [blame]
// 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