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