| // Copyright 2022 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 "input_server.h" | |
| #include <lib/driver/logging/cpp/structured_logger.h> | |
| namespace input_sample { | |
| // Convert local data structure to a `fuchsia.input.report/InputReport` format. | |
| void SampleInputReport::ToFidlInputReport( | |
| fidl::WireTableBuilder<::fuchsia_input_report::wire::InputReport>& input_report, | |
| fidl::AnyArena& arena) { | |
| std::vector<uint8_t> pressed_buttons; | |
| for (uint8_t i = 0; i < kMouseButtonCount; i++) { | |
| if (buttons & (1 << i)) { | |
| pressed_buttons.push_back(i + 1); | |
| } | |
| } | |
| fidl::VectorView<uint8_t> buttons_vec(arena, pressed_buttons.size()); | |
| size_t idx = 0; | |
| for (const auto& button : pressed_buttons) { | |
| buttons_vec[idx++] = button; | |
| } | |
| auto mouse_input_rpt = fuchsia_input_report::wire::MouseInputReport::Builder(arena); | |
| mouse_input_rpt.pressed_buttons(buttons_vec); | |
| mouse_input_rpt.movement_x(rel_x); | |
| mouse_input_rpt.movement_y(rel_y); | |
| input_report.mouse(mouse_input_rpt.Build()); | |
| input_report.event_time(event_time.get()); | |
| } | |
| // Static | |
| // Handle incoming connection requests from FIDL clients | |
| fidl::ServerBindingRef<fuchsia_input_report::InputDevice> InputSampleServer::BindDeviceClient( | |
| async_dispatcher_t* dispatcher, | |
| std::weak_ptr<input_report_reader::InputReportReaderManager<SampleInputReport>> | |
| input_report_readers, | |
| fidl::ServerEnd<fuchsia_input_report::InputDevice> request) { | |
| // Bind each connection request to a unique FIDL server instance | |
| auto server_impl = std::make_unique<InputSampleServer>(dispatcher, input_report_readers); | |
| return fidl::BindServer(dispatcher, std::move(request), std::move(server_impl), | |
| std::mem_fn(&InputSampleServer::OnUnbound)); | |
| } | |
| // This method is called when a server connection is torn down. | |
| void InputSampleServer::OnUnbound(fidl::UnbindInfo info, | |
| fidl::ServerEnd<fuchsia_input_report::InputDevice> server_end) { | |
| if (info.is_peer_closed()) { | |
| FDF_LOG(DEBUG, "Client disconnected"); | |
| } else if (!info.is_user_initiated()) { | |
| FDF_LOG(ERROR, "Client connection unbound: %s", info.status_string()); | |
| } | |
| } | |
| // Protocol method for `fuchsia.input.report/InputDevice` to begin serving input reports | |
| void InputSampleServer::GetInputReportsReader(GetInputReportsReaderRequestView request, | |
| GetInputReportsReaderCompleter::Sync& completer) { | |
| auto reader_manager = input_report_readers_.lock(); | |
| if (!reader_manager) { | |
| FDF_LOG(ERROR, "Unable to access InputReport reader manager."); | |
| request->reader.Close(ZX_ERR_BAD_STATE); | |
| return; | |
| } | |
| zx_status_t status = reader_manager->CreateReader(dispatcher_, std::move(request->reader)); | |
| if (status != ZX_OK) { | |
| FDF_LOG(ERROR, "Could not create input report reader: %d", status); | |
| request->reader.Close(ZX_ERR_BAD_STATE); | |
| } | |
| } | |
| // Protocol method for `fuchsia.input.report/InputDevice` to return the device descriptor | |
| void InputSampleServer::GetDescriptor(GetDescriptorCompleter::Sync& completer) { | |
| fidl::Arena allocator; | |
| auto descriptor = fuchsia_input_report::wire::DeviceDescriptor::Builder(allocator); | |
| fuchsia_input_report::wire::DeviceInfo device_info; | |
| // We pick random VID/PIDs here, but these should be taken from the HID device, | |
| // or defined in fuchsia.input.report/device_ids.fidl | |
| device_info.vendor_id = 0x12345678; | |
| device_info.product_id = 0x87654321; | |
| fidl::VectorView<uint8_t> buttons(allocator, kMouseButtonCount); | |
| buttons[0] = 0x01; | |
| buttons[1] = 0x02; | |
| buttons[2] = 0x03; | |
| constexpr fuchsia_input_report::wire::Axis movement_x{ | |
| .range = {.min = -127, .max = 127}, | |
| .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0}, | |
| }; | |
| constexpr fuchsia_input_report::wire::Axis movement_y{ | |
| .range = {.min = -127, .max = 127}, | |
| .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0}, | |
| }; | |
| auto mouse_in_desc = fuchsia_input_report::wire::MouseInputDescriptor::Builder(allocator); | |
| mouse_in_desc.buttons(buttons); | |
| mouse_in_desc.movement_x(movement_x); | |
| mouse_in_desc.movement_y(movement_y); | |
| auto mouse_descriptor = fuchsia_input_report::wire::MouseDescriptor::Builder(allocator); | |
| mouse_descriptor.input(mouse_in_desc.Build()); | |
| descriptor.mouse(mouse_descriptor.Build()); | |
| descriptor.device_info(device_info); | |
| completer.Reply(descriptor.Build()); | |
| } | |
| } // namespace input_sample |