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