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