1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/libs/input_connector/input_connector.h"
18 
19 #include <memory>
20 #include <optional>
21 #include <utility>
22 #include <vector>
23 
24 #include "common/libs/fs/shared_fd.h"
25 #include "common/libs/utils/result.h"
26 #include "host/libs/input_connector/event_buffer.h"
27 #include "host/libs/input_connector/input_connection.h"
28 #include "host/libs/input_connector/input_devices.h"
29 
30 namespace cuttlefish {
31 
32 struct InputDevices {
33   // TODO (b/186773052): Finding strings in a map for every input event may
34   // introduce unwanted latency.
35   std::map<std::string, TouchDevice> multitouch_devices;
36   std::map<std::string, TouchDevice> touch_devices;
37 
38   std::optional<KeyboardDevice> keyboard;
39   std::optional<SwitchesDevice> switches;
40   std::optional<RotaryDevice> rotary;
41   std::optional<MouseDevice> mouse;
42 };
43 
44 class EventSinkImpl : public InputConnector::EventSink {
45  public:
46   EventSinkImpl(InputDevices&, std::atomic<int>&);
47   ~EventSinkImpl() override;
48 
49   Result<void> SendMouseMoveEvent(int x, int y) override;
50   Result<void> SendMouseButtonEvent(int button, bool down) override;
51   Result<void> SendMouseWheelEvent(int pixels) override;
52   Result<void> SendTouchEvent(const std::string& device_label, int x, int y,
53                               bool down) override;
54   Result<void> SendMultiTouchEvent(const std::string& device_label,
55                                    const std::vector<MultitouchSlot>& slots,
56                                    bool down) override;
57   Result<void> SendKeyboardEvent(uint16_t code, bool down) override;
58   Result<void> SendRotaryEvent(int pixels) override;
59   Result<void> SendSwitchesEvent(uint16_t code, bool state) override;
60 
61  private:
62   InputDevices& input_devices_;
63   std::atomic<int>& sinks_count_;
64 };
65 
EventSinkImpl(InputDevices & devices,std::atomic<int> & count)66 EventSinkImpl::EventSinkImpl(InputDevices& devices, std::atomic<int>& count)
67     : input_devices_(devices), sinks_count_(count) {
68   ++sinks_count_;
69 }
70 
~EventSinkImpl()71 EventSinkImpl::~EventSinkImpl() {
72   for (auto& it : input_devices_.multitouch_devices) {
73     it.second.OnDisconnectedSource(this);
74   }
75   for (auto& it : input_devices_.touch_devices) {
76     it.second.OnDisconnectedSource(this);
77   }
78   --sinks_count_;
79 }
80 
SendMouseMoveEvent(int x,int y)81 Result<void> EventSinkImpl::SendMouseMoveEvent(int x, int y) {
82   CF_EXPECT(input_devices_.mouse.has_value(), "No mouse device setup");
83   CF_EXPECT(input_devices_.mouse->SendMoveEvent(x, y));
84   return {};
85 }
86 
SendMouseButtonEvent(int button,bool down)87 Result<void> EventSinkImpl::SendMouseButtonEvent(int button, bool down) {
88   CF_EXPECT(input_devices_.mouse.has_value(), "No mouse device setup");
89   CF_EXPECT(input_devices_.mouse->SendButtonEvent(button, down));
90   return {};
91 }
92 
SendMouseWheelEvent(int pixels)93 Result<void> EventSinkImpl::SendMouseWheelEvent(int pixels) {
94   CF_EXPECT(input_devices_.mouse.has_value(), "No mouse device setup");
95   CF_EXPECT(input_devices_.mouse->SendWheelEvent(pixels));
96   return {};
97 }
98 
SendTouchEvent(const std::string & device_label,int x,int y,bool down)99 Result<void> EventSinkImpl::SendTouchEvent(const std::string& device_label,
100                                            int x, int y, bool down) {
101   auto ts_it = input_devices_.touch_devices.find(device_label);
102   CF_EXPECT(ts_it != input_devices_.touch_devices.end(),
103             "Unknown touch device: " << device_label);
104   auto& ts = ts_it->second;
105   CF_EXPECT(ts.SendTouchEvent(x, y, down));
106   return {};
107 }
108 
SendMultiTouchEvent(const std::string & device_label,const std::vector<MultitouchSlot> & slots,bool down)109 Result<void> EventSinkImpl::SendMultiTouchEvent(
110     const std::string& device_label, const std::vector<MultitouchSlot>& slots,
111     bool down) {
112   auto ts_it = input_devices_.multitouch_devices.find(device_label);
113   if (ts_it == input_devices_.multitouch_devices.end()) {
114     for (const auto& slot : slots) {
115       CF_EXPECT(SendTouchEvent(device_label, slot.x, slot.y, down));
116     }
117     return {};
118   }
119   auto& ts = ts_it->second;
120   CF_EXPECT(ts.SendMultiTouchEvent(slots, down));
121   return {};
122 }
123 
SendKeyboardEvent(uint16_t code,bool down)124 Result<void> EventSinkImpl::SendKeyboardEvent(uint16_t code, bool down) {
125   CF_EXPECT(input_devices_.keyboard.has_value(), "No keyboard device setup");
126   CF_EXPECT(input_devices_.keyboard->SendEvent(code, down));
127   return {};
128 }
129 
SendRotaryEvent(int pixels)130 Result<void> EventSinkImpl::SendRotaryEvent(int pixels) {
131   CF_EXPECT(input_devices_.rotary.has_value(), "No rotary device setup");
132   CF_EXPECT(input_devices_.rotary->SendEvent(pixels));
133   return {};
134 }
135 
SendSwitchesEvent(uint16_t code,bool state)136 Result<void> EventSinkImpl::SendSwitchesEvent(uint16_t code, bool state) {
137   CF_EXPECT(input_devices_.switches.has_value(), "No switches device setup");
138   CF_EXPECT(input_devices_.switches->SendEvent(code, state));
139   return {};
140 }
141 
142 class InputConnectorImpl : public InputConnector {
143  public:
144   InputConnectorImpl() = default;
145   ~InputConnectorImpl();
146 
147   std::unique_ptr<EventSink> CreateSink() override;
148 
149  private:
150   InputDevices devices_;
151   // Counts the number of events sinks to make sure the class is not destroyed
152   // while any of its sinks still exists.
153   std::atomic<int> sinks_count_ = 0;
154   friend class InputConnectorBuilder;
155 };
156 
~InputConnectorImpl()157 InputConnectorImpl::~InputConnectorImpl() {
158   CHECK(sinks_count_ == 0) << "Input connector destroyed with " << sinks_count_
159                            << " event sinks left";
160 }
161 
CreateSink()162 std::unique_ptr<InputConnector::EventSink> InputConnectorImpl::CreateSink() {
163   return std::unique_ptr<InputConnector::EventSink>(
164       new EventSinkImpl(devices_, sinks_count_));
165 }
166 
InputConnectorBuilder(InputEventType type)167 InputConnectorBuilder::InputConnectorBuilder(InputEventType type)
168     : connector_(new InputConnectorImpl()), event_type_(type) {}
169 
170 InputConnectorBuilder::~InputConnectorBuilder() = default;
171 
WithMultitouchDevice(const std::string & device_label,SharedFD server)172 void InputConnectorBuilder::WithMultitouchDevice(
173     const std::string& device_label, SharedFD server) {
174   CHECK(connector_->devices_.multitouch_devices.find(device_label) ==
175         connector_->devices_.multitouch_devices.end())
176       << "Multiple touch devices with same label: " << device_label;
177   connector_->devices_.multitouch_devices.emplace(
178       std::piecewise_construct, std::forward_as_tuple(device_label),
179       std::forward_as_tuple(NewServerInputConnection(server), event_type_));
180 }
181 
WithTouchDevice(const std::string & device_label,SharedFD server)182 void InputConnectorBuilder::WithTouchDevice(const std::string& device_label,
183                                             SharedFD server) {
184   CHECK(connector_->devices_.touch_devices.find(device_label) ==
185         connector_->devices_.touch_devices.end())
186       << "Multiple touch devices with same label: " << device_label;
187   connector_->devices_.touch_devices.emplace(
188       std::piecewise_construct, std::forward_as_tuple(device_label),
189       std::forward_as_tuple(NewServerInputConnection(server), event_type_));
190 }
191 
WithKeyboard(SharedFD server)192 void InputConnectorBuilder::WithKeyboard(SharedFD server) {
193   CHECK(!connector_->devices_.keyboard) << "Keyboard already specified";
194   connector_->devices_.keyboard.emplace(NewServerInputConnection(server),
195                                         event_type_);
196 }
197 
WithSwitches(SharedFD server)198 void InputConnectorBuilder::WithSwitches(SharedFD server) {
199   CHECK(!connector_->devices_.switches) << "Switches already specified";
200   connector_->devices_.switches.emplace(NewServerInputConnection(server),
201                                         event_type_);
202 }
203 
WithRotary(SharedFD server)204 void InputConnectorBuilder::WithRotary(SharedFD server) {
205   CHECK(!connector_->devices_.rotary) << "Rotary already specified";
206   connector_->devices_.rotary.emplace(NewServerInputConnection(server),
207                                       event_type_);
208 }
209 
WithMouse(SharedFD server)210 void InputConnectorBuilder::WithMouse(SharedFD server) {
211   CHECK(!connector_->devices_.mouse) << "Mouse already specified";
212   connector_->devices_.mouse.emplace(NewServerInputConnection(server),
213                                      event_type_);
214 }
215 
Build()216 std::unique_ptr<InputConnector> InputConnectorBuilder::Build() && {
217   return std::move(connector_);
218 }
219 
220 }  // namespace cuttlefish
221