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_devices.h"
18
19 #include <linux/input.h>
20
21 #include "host/libs/input_connector/event_buffer.h"
22
23 namespace cuttlefish {
24
SendTouchEvent(int x,int y,bool down)25 Result<void> TouchDevice::SendTouchEvent(int x, int y, bool down) {
26 auto buffer = CreateBuffer(event_type(), 4);
27 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
28 buffer->AddEvent(EV_ABS, ABS_X, x);
29 buffer->AddEvent(EV_ABS, ABS_Y, y);
30 buffer->AddEvent(EV_KEY, BTN_TOUCH, down);
31 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
32 CF_EXPECT(WriteEvents(*buffer));
33 return {};
34 }
35
SendMultiTouchEvent(const std::vector<MultitouchSlot> & slots,bool down)36 Result<void> TouchDevice::SendMultiTouchEvent(
37 const std::vector<MultitouchSlot>& slots, bool down) {
38 auto buffer = CreateBuffer(event_type(), 1 + 7 * slots.size());
39 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
40
41 for (auto& f : slots) {
42 auto this_id = f.id;
43 auto this_x = f.x;
44 auto this_y = f.y;
45
46 auto is_new_contact = !HasSlot(this, this_id);
47
48 // Make sure to call HasSlot before this line or it will always return true
49 auto this_slot = GetOrAcquireSlot(this, this_id);
50
51 // BTN_TOUCH DOWN must be the first event in a series
52 if (down && is_new_contact) {
53 buffer->AddEvent(EV_KEY, BTN_TOUCH, 1);
54 }
55
56 buffer->AddEvent(EV_ABS, ABS_MT_SLOT, this_slot);
57 if (down) {
58 if (is_new_contact) {
59 // We already assigned this slot to this source and id combination, we
60 // could use any tracking id for the slot as long as it's greater than 0
61 buffer->AddEvent(EV_ABS, ABS_MT_TRACKING_ID, NewTrackingId());
62 }
63 buffer->AddEvent(EV_ABS, ABS_MT_POSITION_X, this_x);
64 buffer->AddEvent(EV_ABS, ABS_MT_POSITION_Y, this_y);
65 } else {
66 // released touch
67 buffer->AddEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
68 ReleaseSlot(this, this_id);
69 buffer->AddEvent(EV_KEY, BTN_TOUCH, 0);
70 }
71 }
72
73 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
74 CF_EXPECT(WriteEvents(*buffer));
75 return {};
76 }
77
HasSlot(void * source,int32_t id)78 bool TouchDevice::HasSlot(void* source, int32_t id) {
79 std::lock_guard<std::mutex> lock(slots_mtx_);
80 return slots_by_source_and_id_.find({source, id}) !=
81 slots_by_source_and_id_.end();
82 }
83
GetOrAcquireSlot(void * source,int32_t id)84 int32_t TouchDevice::GetOrAcquireSlot(void* source, int32_t id) {
85 std::lock_guard<std::mutex> lock(slots_mtx_);
86 auto slot_it = slots_by_source_and_id_.find({source, id});
87 if (slot_it != slots_by_source_and_id_.end()) {
88 return slot_it->second;
89 }
90 return slots_by_source_and_id_[std::make_pair(source, id)] = UseNewSlot();
91 }
92
ReleaseSlot(void * source,int32_t id)93 void TouchDevice::ReleaseSlot(void* source, int32_t id) {
94 std::lock_guard<std::mutex> lock(slots_mtx_);
95 auto slot_it = slots_by_source_and_id_.find({source, id});
96 if (slot_it == slots_by_source_and_id_.end()) {
97 return;
98 }
99 active_slots_[slot_it->second] = false;
100 slots_by_source_and_id_.erase(slot_it);
101 }
102
OnDisconnectedSource(void * source)103 void TouchDevice::OnDisconnectedSource(void* source) {
104 std::lock_guard<std::mutex> lock(slots_mtx_);
105 auto it = slots_by_source_and_id_.begin();
106 while (it != slots_by_source_and_id_.end()) {
107 if (it->first.first == source) {
108 active_slots_[it->second] = false;
109 it = slots_by_source_and_id_.erase(it);
110 } else {
111 ++it;
112 }
113 }
114 }
115
UseNewSlot()116 int32_t TouchDevice::UseNewSlot() {
117 // This is not the most efficient implementation for a large number of
118 // slots, but that case should be extremely rare. For the typical number of
119 // slots iterating over a vector is likely faster than using other data
120 // structures.
121 for (auto slot = 0; slot < active_slots_.size(); ++slot) {
122 if (!active_slots_[slot]) {
123 active_slots_[slot] = true;
124 return slot;
125 }
126 }
127 active_slots_.push_back(true);
128 return active_slots_.size() - 1;
129 }
130
SendMoveEvent(int x,int y)131 Result<void> MouseDevice::SendMoveEvent(int x, int y) {
132 auto buffer = CreateBuffer(event_type(), 2);
133 CF_EXPECT(buffer != nullptr,
134 "Failed to allocate input events buffer for mouse move event !");
135 buffer->AddEvent(EV_REL, REL_X, x);
136 buffer->AddEvent(EV_REL, REL_Y, y);
137 CF_EXPECT(conn().WriteEvents(buffer->data(), buffer->size()));
138 return {};
139 }
140
SendButtonEvent(int button,bool down)141 Result<void> MouseDevice::SendButtonEvent(int button, bool down) {
142 auto buffer = CreateBuffer(event_type(), 2);
143 CF_EXPECT(buffer != nullptr,
144 "Failed to allocate input events buffer for mouse button event !");
145 std::vector<int> buttons = {BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, BTN_BACK,
146 BTN_FORWARD};
147 CF_EXPECT(button < (int)buttons.size(),
148 "Unknown mouse event button: " << button);
149 buffer->AddEvent(EV_KEY, buttons[button], down);
150 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
151 CF_EXPECT(conn().WriteEvents(buffer->data(), buffer->size()));
152 return {};
153 }
154
SendWheelEvent(int pixels)155 Result<void> MouseDevice::SendWheelEvent(int pixels) {
156 auto buffer = CreateBuffer(event_type(), 2);
157 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
158 buffer->AddEvent(EV_REL, REL_WHEEL, pixels);
159 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
160 CF_EXPECT(conn().WriteEvents(buffer->data(), buffer->size()));
161 return {};
162 }
163
SendEvent(uint16_t code,bool down)164 Result<void> KeyboardDevice::SendEvent(uint16_t code, bool down) {
165 auto buffer = CreateBuffer(event_type(), 2);
166 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
167 buffer->AddEvent(EV_KEY, code, down);
168 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
169 CF_EXPECT(conn().WriteEvents(buffer->data(), buffer->size()));
170 return {};
171 }
172
SendEvent(int pixels)173 Result<void> RotaryDevice::SendEvent(int pixels) {
174 auto buffer = CreateBuffer(event_type(), 2);
175 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
176 buffer->AddEvent(EV_REL, REL_WHEEL, pixels);
177 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
178 CF_EXPECT(conn().WriteEvents(buffer->data(), buffer->size()));
179 return {};
180 }
181
SendEvent(uint16_t code,bool state)182 Result<void> SwitchesDevice::SendEvent(uint16_t code, bool state) {
183 auto buffer = CreateBuffer(event_type(), 2);
184 CF_EXPECT(buffer != nullptr, "Failed to allocate input events buffer");
185 buffer->AddEvent(EV_SW, code, state);
186 buffer->AddEvent(EV_SYN, SYN_REPORT, 0);
187 CF_EXPECT(conn().WriteEvents(buffer->data(), buffer->size()));
188 return {};
189 }
190
191 } // namespace cuttlefish
192