1 /*
2 * Copyright (C) 2019 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 "input/InputDevice.h"
18
19 #include "InputState.h"
20
21 #include "InputDispatcher.h"
22
23 namespace android::inputdispatcher {
24
InputState(const IdGenerator & idGenerator)25 InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {}
26
~InputState()27 InputState::~InputState() {}
28
isNeutral() const29 bool InputState::isNeutral() const {
30 return mKeyMementos.empty() && mMotionMementos.empty();
31 }
32
isHovering(int32_t deviceId,uint32_t source,int32_t displayId) const33 bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const {
34 for (const MotionMemento& memento : mMotionMementos) {
35 if (memento.deviceId == deviceId && memento.source == source &&
36 memento.displayId == displayId && memento.hovering) {
37 return true;
38 }
39 }
40 return false;
41 }
42
trackKey(const KeyEntry & entry,int32_t action,int32_t flags)43 bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags) {
44 switch (action) {
45 case AKEY_EVENT_ACTION_UP: {
46 if (entry.flags & AKEY_EVENT_FLAG_FALLBACK) {
47 for (size_t i = 0; i < mFallbackKeys.size();) {
48 if (mFallbackKeys.valueAt(i) == entry.keyCode) {
49 mFallbackKeys.removeItemsAt(i);
50 } else {
51 i += 1;
52 }
53 }
54 }
55 ssize_t index = findKeyMemento(entry);
56 if (index >= 0) {
57 mKeyMementos.erase(mKeyMementos.begin() + index);
58 return true;
59 }
60 /* FIXME: We can't just drop the key up event because that prevents creating
61 * popup windows that are automatically shown when a key is held and then
62 * dismissed when the key is released. The problem is that the popup will
63 * not have received the original key down, so the key up will be considered
64 * to be inconsistent with its observed state. We could perhaps handle this
65 * by synthesizing a key down but that will cause other problems.
66 *
67 * So for now, allow inconsistent key up events to be dispatched.
68 *
69 #if DEBUG_OUTBOUND_EVENT_DETAILS
70 ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
71 "keyCode=%d, scanCode=%d",
72 entry.deviceId, entry.source, entry.keyCode, entry.scanCode);
73 #endif
74 return false;
75 */
76 return true;
77 }
78
79 case AKEY_EVENT_ACTION_DOWN: {
80 ssize_t index = findKeyMemento(entry);
81 if (index >= 0) {
82 mKeyMementos.erase(mKeyMementos.begin() + index);
83 }
84 addKeyMemento(entry, flags);
85 return true;
86 }
87
88 default:
89 return true;
90 }
91 }
92
trackMotion(const MotionEntry & entry,int32_t action,int32_t flags)93 bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t flags) {
94 int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
95 switch (actionMasked) {
96 case AMOTION_EVENT_ACTION_UP:
97 case AMOTION_EVENT_ACTION_CANCEL: {
98 ssize_t index = findMotionMemento(entry, false /*hovering*/);
99 if (index >= 0) {
100 mMotionMementos.erase(mMotionMementos.begin() + index);
101 return true;
102 }
103 #if DEBUG_OUTBOUND_EVENT_DETAILS
104 ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
105 "displayId=%" PRId32 ", actionMasked=%d",
106 entry.deviceId, entry.source, entry.displayId, actionMasked);
107 #endif
108 return false;
109 }
110
111 case AMOTION_EVENT_ACTION_DOWN: {
112 ssize_t index = findMotionMemento(entry, false /*hovering*/);
113 if (index >= 0) {
114 mMotionMementos.erase(mMotionMementos.begin() + index);
115 }
116 addMotionMemento(entry, flags, false /*hovering*/);
117 return true;
118 }
119
120 case AMOTION_EVENT_ACTION_POINTER_UP:
121 case AMOTION_EVENT_ACTION_POINTER_DOWN:
122 case AMOTION_EVENT_ACTION_MOVE: {
123 if (entry.source & AINPUT_SOURCE_CLASS_NAVIGATION) {
124 // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
125 // to generate cancellation events for these since they're based in relative rather
126 // than absolute units.
127 return true;
128 }
129
130 ssize_t index = findMotionMemento(entry, false /*hovering*/);
131
132 if (entry.source & AINPUT_SOURCE_CLASS_JOYSTICK) {
133 // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
134 // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
135 // Any other value and we need to track the motion so we can send cancellation
136 // events for anything generating fallback events (e.g. DPad keys for joystick
137 // movements).
138 if (index >= 0) {
139 if (entry.pointerCoords[0].isEmpty()) {
140 mMotionMementos.erase(mMotionMementos.begin() + index);
141 } else {
142 MotionMemento& memento = mMotionMementos[index];
143 memento.setPointers(entry);
144 }
145 } else if (!entry.pointerCoords[0].isEmpty()) {
146 addMotionMemento(entry, flags, false /*hovering*/);
147 }
148
149 // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
150 return true;
151 }
152
153 if (index >= 0) {
154 MotionMemento& memento = mMotionMementos[index];
155 if (memento.firstNewPointerIdx < 0) {
156 memento.setPointers(entry);
157 return true;
158 }
159 }
160 #if DEBUG_OUTBOUND_EVENT_DETAILS
161 ALOGD("Dropping inconsistent motion pointer up/down or move event: "
162 "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
163 entry.deviceId, entry.source, entry.displayId, actionMasked);
164 #endif
165 return false;
166 }
167
168 case AMOTION_EVENT_ACTION_HOVER_EXIT: {
169 ssize_t index = findMotionMemento(entry, true /*hovering*/);
170 if (index >= 0) {
171 mMotionMementos.erase(mMotionMementos.begin() + index);
172 return true;
173 }
174 #if DEBUG_OUTBOUND_EVENT_DETAILS
175 ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
176 "displayId=%" PRId32,
177 entry.deviceId, entry.source, entry.displayId);
178 #endif
179 return false;
180 }
181
182 case AMOTION_EVENT_ACTION_HOVER_ENTER:
183 case AMOTION_EVENT_ACTION_HOVER_MOVE: {
184 ssize_t index = findMotionMemento(entry, true /*hovering*/);
185 if (index >= 0) {
186 mMotionMementos.erase(mMotionMementos.begin() + index);
187 }
188 addMotionMemento(entry, flags, true /*hovering*/);
189 return true;
190 }
191
192 default:
193 return true;
194 }
195 }
196
findKeyMemento(const KeyEntry & entry) const197 ssize_t InputState::findKeyMemento(const KeyEntry& entry) const {
198 for (size_t i = 0; i < mKeyMementos.size(); i++) {
199 const KeyMemento& memento = mKeyMementos[i];
200 if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
201 memento.displayId == entry.displayId && memento.keyCode == entry.keyCode &&
202 memento.scanCode == entry.scanCode) {
203 return i;
204 }
205 }
206 return -1;
207 }
208
findMotionMemento(const MotionEntry & entry,bool hovering) const209 ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const {
210 for (size_t i = 0; i < mMotionMementos.size(); i++) {
211 const MotionMemento& memento = mMotionMementos[i];
212 if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
213 memento.displayId == entry.displayId && memento.hovering == hovering) {
214 return i;
215 }
216 }
217 return -1;
218 }
219
addKeyMemento(const KeyEntry & entry,int32_t flags)220 void InputState::addKeyMemento(const KeyEntry& entry, int32_t flags) {
221 KeyMemento memento;
222 memento.deviceId = entry.deviceId;
223 memento.source = entry.source;
224 memento.displayId = entry.displayId;
225 memento.keyCode = entry.keyCode;
226 memento.scanCode = entry.scanCode;
227 memento.metaState = entry.metaState;
228 memento.flags = flags;
229 memento.downTime = entry.downTime;
230 memento.policyFlags = entry.policyFlags;
231 mKeyMementos.push_back(memento);
232 }
233
addMotionMemento(const MotionEntry & entry,int32_t flags,bool hovering)234 void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool hovering) {
235 MotionMemento memento;
236 memento.deviceId = entry.deviceId;
237 memento.source = entry.source;
238 memento.displayId = entry.displayId;
239 memento.flags = flags;
240 memento.xPrecision = entry.xPrecision;
241 memento.yPrecision = entry.yPrecision;
242 memento.xCursorPosition = entry.xCursorPosition;
243 memento.yCursorPosition = entry.yCursorPosition;
244 memento.downTime = entry.downTime;
245 memento.setPointers(entry);
246 memento.hovering = hovering;
247 memento.policyFlags = entry.policyFlags;
248 mMotionMementos.push_back(memento);
249 }
250
setPointers(const MotionEntry & entry)251 void InputState::MotionMemento::setPointers(const MotionEntry& entry) {
252 pointerCount = entry.pointerCount;
253 for (uint32_t i = 0; i < entry.pointerCount; i++) {
254 pointerProperties[i].copyFrom(entry.pointerProperties[i]);
255 pointerCoords[i].copyFrom(entry.pointerCoords[i]);
256 }
257 }
258
mergePointerStateTo(MotionMemento & other) const259 void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const {
260 for (uint32_t i = 0; i < pointerCount; i++) {
261 if (other.firstNewPointerIdx < 0) {
262 other.firstNewPointerIdx = other.pointerCount;
263 }
264 other.pointerProperties[other.pointerCount].copyFrom(pointerProperties[i]);
265 other.pointerCoords[other.pointerCount].copyFrom(pointerCoords[i]);
266 other.pointerCount++;
267 }
268 }
269
synthesizeCancelationEvents(nsecs_t currentTime,const CancelationOptions & options)270 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents(
271 nsecs_t currentTime, const CancelationOptions& options) {
272 std::vector<std::unique_ptr<EventEntry>> events;
273 for (KeyMemento& memento : mKeyMementos) {
274 if (shouldCancelKey(memento, options)) {
275 events.push_back(
276 std::make_unique<KeyEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId,
277 memento.source, memento.displayId,
278 memento.policyFlags, AKEY_EVENT_ACTION_UP,
279 memento.flags | AKEY_EVENT_FLAG_CANCELED,
280 memento.keyCode, memento.scanCode, memento.metaState,
281 0 /*repeatCount*/, memento.downTime));
282 }
283 }
284
285 for (const MotionMemento& memento : mMotionMementos) {
286 if (shouldCancelMotion(memento, options)) {
287 const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
288 : AMOTION_EVENT_ACTION_CANCEL;
289 events.push_back(
290 std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
291 memento.deviceId, memento.source,
292 memento.displayId, memento.policyFlags, action,
293 0 /*actionButton*/, memento.flags, AMETA_NONE,
294 0 /*buttonState*/, MotionClassification::NONE,
295 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
296 memento.yPrecision, memento.xCursorPosition,
297 memento.yCursorPosition, memento.downTime,
298 memento.pointerCount, memento.pointerProperties,
299 memento.pointerCoords, 0 /*xOffset*/,
300 0 /*yOffset*/));
301 }
302 }
303 return events;
304 }
305
synthesizePointerDownEvents(nsecs_t currentTime)306 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents(
307 nsecs_t currentTime) {
308 std::vector<std::unique_ptr<EventEntry>> events;
309 for (MotionMemento& memento : mMotionMementos) {
310 if (!(memento.source & AINPUT_SOURCE_CLASS_POINTER)) {
311 continue;
312 }
313
314 if (memento.firstNewPointerIdx < 0) {
315 continue;
316 }
317
318 uint32_t pointerCount = 0;
319 PointerProperties pointerProperties[MAX_POINTERS];
320 PointerCoords pointerCoords[MAX_POINTERS];
321
322 // We will deliver all pointers the target already knows about
323 for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
324 pointerProperties[i].copyFrom(memento.pointerProperties[i]);
325 pointerCoords[i].copyFrom(memento.pointerCoords[i]);
326 pointerCount++;
327 }
328
329 // We will send explicit events for all pointers the target doesn't know about
330 for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
331 i < memento.pointerCount; i++) {
332
333 pointerProperties[i].copyFrom(memento.pointerProperties[i]);
334 pointerCoords[i].copyFrom(memento.pointerCoords[i]);
335 pointerCount++;
336
337 // Down only if the first pointer, pointer down otherwise
338 const int32_t action = (pointerCount <= 1)
339 ? AMOTION_EVENT_ACTION_DOWN
340 : AMOTION_EVENT_ACTION_POINTER_DOWN
341 | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
342
343 events.push_back(
344 std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
345 memento.deviceId, memento.source,
346 memento.displayId, memento.policyFlags, action,
347 0 /*actionButton*/, memento.flags, AMETA_NONE,
348 0 /*buttonState*/, MotionClassification::NONE,
349 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
350 memento.yPrecision, memento.xCursorPosition,
351 memento.yCursorPosition, memento.downTime,
352 pointerCount, pointerProperties, pointerCoords,
353 0 /*xOffset*/, 0 /*yOffset*/));
354 }
355
356 memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
357 }
358
359 return events;
360 }
361
clear()362 void InputState::clear() {
363 mKeyMementos.clear();
364 mMotionMementos.clear();
365 mFallbackKeys.clear();
366 }
367
mergePointerStateTo(InputState & other)368 void InputState::mergePointerStateTo(InputState& other) {
369 for (size_t i = 0; i < mMotionMementos.size(); i++) {
370 MotionMemento& memento = mMotionMementos[i];
371 // Since we support split pointers we need to merge touch events
372 // from the same source + device + screen.
373 if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
374 bool merged = false;
375 for (size_t j = 0; j < other.mMotionMementos.size(); j++) {
376 MotionMemento& otherMemento = other.mMotionMementos[j];
377 if (memento.deviceId == otherMemento.deviceId &&
378 memento.source == otherMemento.source &&
379 memento.displayId == otherMemento.displayId) {
380 memento.mergePointerStateTo(otherMemento);
381 merged = true;
382 break;
383 }
384 }
385 if (!merged) {
386 memento.firstNewPointerIdx = 0;
387 other.mMotionMementos.push_back(memento);
388 }
389 }
390 }
391 }
392
getFallbackKey(int32_t originalKeyCode)393 int32_t InputState::getFallbackKey(int32_t originalKeyCode) {
394 ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
395 return index >= 0 ? mFallbackKeys.valueAt(index) : -1;
396 }
397
setFallbackKey(int32_t originalKeyCode,int32_t fallbackKeyCode)398 void InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) {
399 ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
400 if (index >= 0) {
401 mFallbackKeys.replaceValueAt(index, fallbackKeyCode);
402 } else {
403 mFallbackKeys.add(originalKeyCode, fallbackKeyCode);
404 }
405 }
406
removeFallbackKey(int32_t originalKeyCode)407 void InputState::removeFallbackKey(int32_t originalKeyCode) {
408 mFallbackKeys.removeItem(originalKeyCode);
409 }
410
shouldCancelKey(const KeyMemento & memento,const CancelationOptions & options)411 bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) {
412 if (options.keyCode && memento.keyCode != options.keyCode.value()) {
413 return false;
414 }
415
416 if (options.deviceId && memento.deviceId != options.deviceId.value()) {
417 return false;
418 }
419
420 if (options.displayId && memento.displayId != options.displayId.value()) {
421 return false;
422 }
423
424 switch (options.mode) {
425 case CancelationOptions::CANCEL_ALL_EVENTS:
426 case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
427 return true;
428 case CancelationOptions::CANCEL_FALLBACK_EVENTS:
429 return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
430 default:
431 return false;
432 }
433 }
434
shouldCancelMotion(const MotionMemento & memento,const CancelationOptions & options)435 bool InputState::shouldCancelMotion(const MotionMemento& memento,
436 const CancelationOptions& options) {
437 if (options.deviceId && memento.deviceId != options.deviceId.value()) {
438 return false;
439 }
440
441 if (options.displayId && memento.displayId != options.displayId.value()) {
442 return false;
443 }
444
445 switch (options.mode) {
446 case CancelationOptions::CANCEL_ALL_EVENTS:
447 return true;
448 case CancelationOptions::CANCEL_POINTER_EVENTS:
449 return memento.source & AINPUT_SOURCE_CLASS_POINTER;
450 case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
451 return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
452 default:
453 return false;
454 }
455 }
456
457 } // namespace android::inputdispatcher
458