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 "DebugConfig.h"
18 #include "input/Input.h"
19 #include "input/InputDevice.h"
20 #include "input/InputFlags.h"
21
22 #include "InputState.h"
23
24 #include <cinttypes>
25 #include "InputDispatcher.h"
26
27 namespace android::inputdispatcher {
28
InputState(const IdGenerator & idGenerator)29 InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {}
30
~InputState()31 InputState::~InputState() {}
32
isHovering(DeviceId deviceId,uint32_t source,ui::LogicalDisplayId displayId) const33 bool InputState::isHovering(DeviceId deviceId, uint32_t source,
34 ui::LogicalDisplayId displayId) const {
35 for (const MotionMemento& memento : mMotionMementos) {
36 if (memento.deviceId == deviceId && memento.source == source &&
37 memento.displayId == displayId && memento.hovering) {
38 return true;
39 }
40 }
41 return false;
42 }
43
trackKey(const KeyEntry & entry,int32_t flags)44 bool InputState::trackKey(const KeyEntry& entry, int32_t flags) {
45 switch (entry.action) {
46 case AKEY_EVENT_ACTION_UP: {
47 if (entry.flags & AKEY_EVENT_FLAG_FALLBACK) {
48 std::erase_if(mFallbackKeys,
49 [&entry](const auto& item) { return item.second == entry.keyCode; });
50 }
51 ssize_t index = findKeyMemento(entry);
52 if (index >= 0) {
53 mKeyMementos.erase(mKeyMementos.begin() + index);
54 return true;
55 }
56 /* FIXME: We can't just drop the key up event because that prevents creating
57 * popup windows that are automatically shown when a key is held and then
58 * dismissed when the key is released. The problem is that the popup will
59 * not have received the original key down, so the key up will be considered
60 * to be inconsistent with its observed state. We could perhaps handle this
61 * by synthesizing a key down but that will cause other problems.
62 *
63 * So for now, allow inconsistent key up events to be dispatched.
64 *
65 #if DEBUG_OUTBOUND_EVENT_DETAILS
66 ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
67 "keyCode=%d, scanCode=%d",
68 entry.deviceId, entry.source, entry.keyCode, entry.scanCode);
69 #endif
70 return false;
71 */
72 return true;
73 }
74
75 case AKEY_EVENT_ACTION_DOWN: {
76 ssize_t index = findKeyMemento(entry);
77 if (index >= 0) {
78 mKeyMementos.erase(mKeyMementos.begin() + index);
79 }
80 addKeyMemento(entry, flags);
81 return true;
82 }
83
84 default:
85 return true;
86 }
87 }
88
89 /**
90 * Return:
91 * true if the incoming event was correctly tracked,
92 * false if the incoming event should be dropped.
93 */
trackMotion(const MotionEntry & entry,int32_t flags)94 bool InputState::trackMotion(const MotionEntry& entry, int32_t flags) {
95 // Don't track non-pointer events
96 if (!isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) {
97 // This is a focus-dispatched event; we don't track its state.
98 return true;
99 }
100
101 if (!input_flags::enable_multi_device_same_window_stream()) {
102 if (!mMotionMementos.empty()) {
103 const MotionMemento& lastMemento = mMotionMementos.back();
104 if (isStylusEvent(lastMemento.source, lastMemento.pointerProperties) &&
105 !isStylusEvent(entry.source, entry.pointerProperties)) {
106 // We already have a stylus stream, and the new event is not from stylus.
107 return false;
108 }
109 }
110 }
111
112 int32_t actionMasked = entry.action & AMOTION_EVENT_ACTION_MASK;
113 switch (actionMasked) {
114 case AMOTION_EVENT_ACTION_UP:
115 case AMOTION_EVENT_ACTION_CANCEL: {
116 ssize_t index = findMotionMemento(entry, /*hovering=*/false);
117 if (index >= 0) {
118 mMotionMementos.erase(mMotionMementos.begin() + index);
119 return true;
120 }
121
122 return false;
123 }
124
125 case AMOTION_EVENT_ACTION_DOWN: {
126 ssize_t index = findMotionMemento(entry, /*hovering=*/false);
127 if (index >= 0) {
128 mMotionMementos.erase(mMotionMementos.begin() + index);
129 }
130 addMotionMemento(entry, flags, /*hovering=*/false);
131 return true;
132 }
133
134 case AMOTION_EVENT_ACTION_POINTER_UP:
135 case AMOTION_EVENT_ACTION_POINTER_DOWN:
136 case AMOTION_EVENT_ACTION_MOVE: {
137 if (entry.source & AINPUT_SOURCE_CLASS_NAVIGATION) {
138 // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
139 // to generate cancellation events for these since they're based in relative rather
140 // than absolute units.
141 return true;
142 }
143
144 ssize_t index = findMotionMemento(entry, /*hovering=*/false);
145
146 if (entry.source & AINPUT_SOURCE_CLASS_JOYSTICK) {
147 // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
148 // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
149 // Any other value and we need to track the motion so we can send cancellation
150 // events for anything generating fallback events (e.g. DPad keys for joystick
151 // movements).
152 if (index >= 0) {
153 if (entry.pointerCoords[0].isEmpty()) {
154 mMotionMementos.erase(mMotionMementos.begin() + index);
155 } else {
156 MotionMemento& memento = mMotionMementos[index];
157 memento.setPointers(entry);
158 }
159 } else if (!entry.pointerCoords[0].isEmpty()) {
160 addMotionMemento(entry, flags, /*hovering=*/false);
161 }
162
163 // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
164 return true;
165 }
166
167 if (index >= 0) {
168 MotionMemento& memento = mMotionMementos[index];
169 if (memento.firstNewPointerIdx < 0) {
170 memento.setPointers(entry);
171 return true;
172 }
173 }
174
175 return false;
176 }
177
178 case AMOTION_EVENT_ACTION_HOVER_EXIT: {
179 ssize_t index = findMotionMemento(entry, /*hovering=*/true);
180 if (index >= 0) {
181 mMotionMementos.erase(mMotionMementos.begin() + index);
182 return true;
183 }
184
185 return false;
186 }
187
188 case AMOTION_EVENT_ACTION_HOVER_ENTER:
189 case AMOTION_EVENT_ACTION_HOVER_MOVE: {
190 ssize_t index = findMotionMemento(entry, /*hovering=*/true);
191 if (index >= 0) {
192 mMotionMementos.erase(mMotionMementos.begin() + index);
193 }
194 addMotionMemento(entry, flags, /*hovering=*/true);
195 return true;
196 }
197
198 default:
199 return true;
200 }
201 }
202
203 std::optional<std::pair<std::vector<PointerProperties>, std::vector<PointerCoords>>>
getPointersOfLastEvent(const MotionEntry & entry,bool hovering) const204 InputState::getPointersOfLastEvent(const MotionEntry& entry, bool hovering) const {
205 ssize_t index = findMotionMemento(entry, hovering);
206 if (index == -1) {
207 return std::nullopt;
208 }
209 return std::make_pair(mMotionMementos[index].pointerProperties,
210 mMotionMementos[index].pointerCoords);
211 }
212
findKeyMemento(const KeyEntry & entry) const213 ssize_t InputState::findKeyMemento(const KeyEntry& entry) const {
214 for (size_t i = 0; i < mKeyMementos.size(); i++) {
215 const KeyMemento& memento = mKeyMementos[i];
216 if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
217 memento.displayId == entry.displayId && memento.keyCode == entry.keyCode &&
218 memento.scanCode == entry.scanCode) {
219 return i;
220 }
221 }
222 return -1;
223 }
224
findMotionMemento(const MotionEntry & entry,bool hovering) const225 ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const {
226 // If we have connected displays a mouse can move between displays and displayId may change
227 // while a gesture is in-progress.
228 const bool skipDisplayCheck =
229 InputFlags::connectedDisplaysCursorEnabled() && isMouseOrTouchpad(entry.source);
230 for (size_t i = 0; i < mMotionMementos.size(); i++) {
231 const MotionMemento& memento = mMotionMementos[i];
232 if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
233 memento.hovering == hovering &&
234 (skipDisplayCheck || memento.displayId == entry.displayId)) {
235 return i;
236 }
237 }
238 return -1;
239 }
240
addKeyMemento(const KeyEntry & entry,int32_t flags)241 void InputState::addKeyMemento(const KeyEntry& entry, int32_t flags) {
242 KeyMemento memento;
243 memento.deviceId = entry.deviceId;
244 memento.source = entry.source;
245 memento.displayId = entry.displayId;
246 memento.keyCode = entry.keyCode;
247 memento.scanCode = entry.scanCode;
248 memento.metaState = entry.metaState;
249 memento.flags = flags;
250 memento.downTime = entry.downTime;
251 memento.policyFlags = entry.policyFlags;
252 mKeyMementos.push_back(memento);
253 }
254
addMotionMemento(const MotionEntry & entry,int32_t flags,bool hovering)255 void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool hovering) {
256 MotionMemento memento;
257 memento.deviceId = entry.deviceId;
258 memento.source = entry.source;
259 memento.displayId = entry.displayId;
260 memento.flags = flags;
261 memento.xPrecision = entry.xPrecision;
262 memento.yPrecision = entry.yPrecision;
263 memento.xCursorPosition = entry.xCursorPosition;
264 memento.yCursorPosition = entry.yCursorPosition;
265 memento.downTime = entry.downTime;
266 memento.setPointers(entry);
267 memento.hovering = hovering;
268 memento.policyFlags = entry.policyFlags;
269 mMotionMementos.push_back(memento);
270 }
271
setPointers(const MotionEntry & entry)272 void InputState::MotionMemento::setPointers(const MotionEntry& entry) {
273 pointerProperties.clear();
274 pointerCoords.clear();
275
276 for (uint32_t i = 0; i < entry.getPointerCount(); i++) {
277 if (MotionEvent::getActionMasked(entry.action) == AMOTION_EVENT_ACTION_POINTER_UP) {
278 // In POINTER_UP events, the pointer is leaving. Since the action is not stored,
279 // this departing pointer should not be recorded.
280 const uint8_t actionIndex = MotionEvent::getActionIndex(entry.action);
281 if (i == actionIndex) {
282 continue;
283 }
284 }
285 pointerProperties.push_back(entry.pointerProperties[i]);
286 pointerCoords.push_back(entry.pointerCoords[i]);
287 }
288 }
289
mergePointerStateTo(MotionMemento & other) const290 void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const {
291 for (uint32_t i = 0; i < getPointerCount(); i++) {
292 if (other.firstNewPointerIdx < 0) {
293 other.firstNewPointerIdx = other.getPointerCount();
294 }
295 other.pointerProperties.push_back(pointerProperties[i]);
296 other.pointerCoords.push_back(pointerCoords[i]);
297 }
298 }
299
getPointerCount() const300 size_t InputState::MotionMemento::getPointerCount() const {
301 return pointerProperties.size();
302 }
303
shouldCancelPreviousStream(const MotionEntry & motionEntry) const304 bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry) const {
305 if (!isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER)) {
306 // This is a focus-dispatched event that should not affect the previous stream.
307 return false;
308 }
309
310 // New MotionEntry pointer event is coming in.
311
312 // If this is a new gesture, and it's from a different device, then, in general, we will cancel
313 // the current gesture.
314 // However, because stylus should be preferred over touch, we need to treat some cases in a
315 // special way.
316 if (mMotionMementos.empty()) {
317 // There is no ongoing pointer gesture, so there is nothing to cancel
318 return false;
319 }
320
321 const MotionMemento& lastMemento = mMotionMementos.back();
322 const int32_t actionMasked = MotionEvent::getActionMasked(motionEntry.action);
323
324 // For compatibility, only one input device can be active at a time in the same window.
325 if (lastMemento.deviceId == motionEntry.deviceId) {
326 // In general, the same device should produce self-consistent streams so nothing needs to
327 // be canceled. But there is one exception:
328 // Sometimes ACTION_DOWN is received without a corresponding HOVER_EXIT. To account for
329 // that, cancel the previous hovering stream
330 if (actionMasked == AMOTION_EVENT_ACTION_DOWN && lastMemento.hovering) {
331 return true;
332 }
333
334 // If the stream changes its source, just cancel the current gesture to be safe. It's
335 // possible that the app isn't handling source changes properly
336 if (motionEntry.source != lastMemento.source) {
337 LOG(INFO) << "Canceling stream: last source was "
338 << inputEventSourceToString(lastMemento.source) << " and new event is "
339 << motionEntry;
340 return true;
341 }
342
343 // If the injection is happening into two different displays, the same injected device id
344 // could be going into both. And at this time, if mirroring is active, the same connection
345 // would receive different events from each display. Since the TouchStates are per-display,
346 // it's unlikely that those two streams would be consistent with each other. Therefore,
347 // cancel the previous gesture if the display id changes.
348 // Except when we have connected-displays where a mouse may move across display boundaries.
349 const bool skipDisplayCheck = (InputFlags::connectedDisplaysCursorEnabled() &&
350 isMouseOrTouchpad(motionEntry.source));
351 if (!skipDisplayCheck && motionEntry.displayId != lastMemento.displayId) {
352 LOG(INFO) << "Canceling stream: last displayId was " << lastMemento.displayId
353 << " and new event is " << motionEntry;
354 return true;
355 }
356
357 return false;
358 }
359
360 if (!input_flags::enable_multi_device_same_window_stream()) {
361 if (isStylusEvent(lastMemento.source, lastMemento.pointerProperties)) {
362 // A stylus is already active.
363 if (isStylusEvent(motionEntry.source, motionEntry.pointerProperties) &&
364 actionMasked == AMOTION_EVENT_ACTION_DOWN) {
365 // If this new event is from a different device, then cancel the old
366 // stylus and allow the new stylus to take over, but only if it's going down.
367 // Otherwise, they will start to race each other.
368 return true;
369 }
370
371 // Keep the current stylus gesture.
372 return false;
373 }
374
375 // Cancel the current gesture if this is a start of a new gesture from a new device.
376 if (actionMasked == AMOTION_EVENT_ACTION_DOWN ||
377 actionMasked == AMOTION_EVENT_ACTION_HOVER_ENTER) {
378 return true;
379 }
380 }
381 // By default, don't cancel any events.
382 return false;
383 }
384
cancelConflictingInputStream(const MotionEntry & motionEntry)385 std::unique_ptr<EventEntry> InputState::cancelConflictingInputStream(
386 const MotionEntry& motionEntry) {
387 if (!shouldCancelPreviousStream(motionEntry)) {
388 return {};
389 }
390
391 const MotionMemento& memento = mMotionMementos.back();
392
393 // Cancel the last device stream
394 std::unique_ptr<MotionEntry> cancelEntry =
395 createCancelEntryForMemento(memento, motionEntry.eventTime);
396
397 if (!trackMotion(*cancelEntry, cancelEntry->flags)) {
398 LOG(FATAL) << "Generated inconsistent cancel event!";
399 }
400 return cancelEntry;
401 }
402
createCancelEntryForMemento(const MotionMemento & memento,nsecs_t eventTime) const403 std::unique_ptr<MotionEntry> InputState::createCancelEntryForMemento(const MotionMemento& memento,
404 nsecs_t eventTime) const {
405 const int32_t action =
406 memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
407 int32_t flags = memento.flags;
408 if (action == AMOTION_EVENT_ACTION_CANCEL) {
409 flags |= AMOTION_EVENT_FLAG_CANCELED;
410 }
411 return std::make_unique<MotionEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
412 eventTime, memento.deviceId, memento.source,
413 memento.displayId, memento.policyFlags, action,
414 /*actionButton=*/0, flags, AMETA_NONE,
415 /*buttonState=*/0, MotionClassification::NONE,
416 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
417 memento.yPrecision, memento.xCursorPosition,
418 memento.yCursorPosition, memento.downTime,
419 memento.pointerProperties, memento.pointerCoords);
420 }
421
synthesizeCancelationEvents(nsecs_t currentTime,const CancelationOptions & options)422 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents(
423 nsecs_t currentTime, const CancelationOptions& options) {
424 std::vector<std::unique_ptr<EventEntry>> events;
425 for (KeyMemento& memento : mKeyMementos) {
426 if (shouldCancelKey(memento, options)) {
427 events.push_back(
428 std::make_unique<KeyEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
429 currentTime, memento.deviceId, memento.source,
430 memento.displayId, memento.policyFlags,
431 AKEY_EVENT_ACTION_UP,
432 memento.flags | AKEY_EVENT_FLAG_CANCELED,
433 memento.keyCode, memento.scanCode, memento.metaState,
434 /*repeatCount=*/0, memento.downTime));
435 }
436 }
437
438 for (const MotionMemento& memento : mMotionMementos) {
439 if (shouldCancelMotion(memento, options)) {
440 if (options.pointerIds == std::nullopt) {
441 events.push_back(createCancelEntryForMemento(memento, currentTime));
442 } else {
443 std::vector<std::unique_ptr<MotionEntry>> pointerCancelEvents =
444 synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(),
445 currentTime);
446 events.insert(events.end(), std::make_move_iterator(pointerCancelEvents.begin()),
447 std::make_move_iterator(pointerCancelEvents.end()));
448 }
449 }
450 }
451 return events;
452 }
453
synthesizePointerDownEvents(nsecs_t currentTime)454 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents(
455 nsecs_t currentTime) {
456 std::vector<std::unique_ptr<EventEntry>> events;
457 for (MotionMemento& memento : mMotionMementos) {
458 if (!isFromSource(memento.source, AINPUT_SOURCE_CLASS_POINTER)) {
459 continue;
460 }
461
462 if (memento.firstNewPointerIdx < 0) {
463 continue;
464 }
465
466 std::vector<PointerProperties> pointerProperties;
467 std::vector<PointerCoords> pointerCoords;
468
469 // We will deliver all pointers the target already knows about
470 for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
471 pointerProperties.push_back(memento.pointerProperties[i]);
472 pointerCoords.push_back(memento.pointerCoords[i]);
473 }
474
475 // We will send explicit events for all pointers the target doesn't know about
476 for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
477 i < memento.getPointerCount(); i++) {
478 pointerProperties.push_back(memento.pointerProperties[i]);
479 pointerCoords.push_back(memento.pointerCoords[i]);
480
481 const size_t pointerCount = pointerProperties.size();
482
483 // Down only if the first pointer, pointer down otherwise
484 const int32_t action = (pointerCount <= 1)
485 ? AMOTION_EVENT_ACTION_DOWN
486 : AMOTION_EVENT_ACTION_POINTER_DOWN
487 | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
488
489 events.push_back(
490 std::make_unique<MotionEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
491 currentTime, memento.deviceId, memento.source,
492 memento.displayId, memento.policyFlags, action,
493 /*actionButton=*/0, memento.flags, AMETA_NONE,
494 /*buttonState=*/0, MotionClassification::NONE,
495 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
496 memento.yPrecision, memento.xCursorPosition,
497 memento.yCursorPosition, memento.downTime,
498 pointerProperties, pointerCoords));
499 }
500
501 memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
502 }
503
504 return events;
505 }
506
synthesizeCancelationEventsForPointers(const MotionMemento & memento,std::bitset<MAX_POINTER_ID+1> pointerIds,nsecs_t currentTime)507 std::vector<std::unique_ptr<MotionEntry>> InputState::synthesizeCancelationEventsForPointers(
508 const MotionMemento& memento, std::bitset<MAX_POINTER_ID + 1> pointerIds,
509 nsecs_t currentTime) {
510 std::vector<std::unique_ptr<MotionEntry>> events;
511 std::vector<uint32_t> canceledPointerIndices;
512
513 for (uint32_t pointerIdx = 0; pointerIdx < memento.getPointerCount(); pointerIdx++) {
514 uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id);
515 if (pointerIds.test(pointerId)) {
516 canceledPointerIndices.push_back(pointerIdx);
517 }
518 }
519
520 if (canceledPointerIndices.size() == memento.getPointerCount()) {
521 // We are cancelling all pointers.
522 events.emplace_back(createCancelEntryForMemento(memento, currentTime));
523 return events;
524 }
525
526 // If we aren't canceling all pointers, we need to generate ACTION_POINTER_UP with
527 // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the
528 // previously canceled pointers from PointerProperties and PointerCoords, and update
529 // pointerCount appropriately. For convenience, sort the canceled pointer indices in
530 // descending order so that we can just slide the remaining pointers to the beginning of
531 // the array when a pointer is canceled.
532 std::sort(canceledPointerIndices.begin(), canceledPointerIndices.end(),
533 std::greater<uint32_t>());
534
535 std::vector<PointerProperties> pointerProperties = memento.pointerProperties;
536 std::vector<PointerCoords> pointerCoords = memento.pointerCoords;
537 for (const uint32_t pointerIdx : canceledPointerIndices) {
538 if (pointerProperties.size() <= 1) {
539 LOG(FATAL) << "Unexpected code path for canceling all pointers!";
540 }
541 const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
542 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
543 events.push_back(
544 std::make_unique<MotionEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
545 currentTime, memento.deviceId, memento.source,
546 memento.displayId, memento.policyFlags, action,
547 /*actionButton=*/0,
548 memento.flags | AMOTION_EVENT_FLAG_CANCELED,
549 AMETA_NONE, /*buttonState=*/0,
550 MotionClassification::NONE,
551 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
552 memento.yPrecision, memento.xCursorPosition,
553 memento.yCursorPosition, memento.downTime,
554 pointerProperties, pointerCoords));
555
556 // Cleanup pointer information
557 pointerProperties.erase(pointerProperties.begin() + pointerIdx);
558 pointerCoords.erase(pointerCoords.begin() + pointerIdx);
559 }
560 return events;
561 }
562
clear()563 void InputState::clear() {
564 mKeyMementos.clear();
565 mMotionMementos.clear();
566 mFallbackKeys.clear();
567 }
568
mergePointerStateTo(InputState & other)569 void InputState::mergePointerStateTo(InputState& other) {
570 for (size_t i = 0; i < mMotionMementos.size(); i++) {
571 MotionMemento& memento = mMotionMementos[i];
572 // Since we support split pointers we need to merge touch events
573 // from the same source + device + screen.
574 if (isFromSource(memento.source, AINPUT_SOURCE_CLASS_POINTER)) {
575 bool merged = false;
576 for (size_t j = 0; j < other.mMotionMementos.size(); j++) {
577 MotionMemento& otherMemento = other.mMotionMementos[j];
578 if (memento.deviceId == otherMemento.deviceId &&
579 memento.source == otherMemento.source &&
580 memento.displayId == otherMemento.displayId) {
581 memento.mergePointerStateTo(otherMemento);
582 merged = true;
583 break;
584 }
585 }
586 if (!merged) {
587 memento.firstNewPointerIdx = 0;
588 other.mMotionMementos.push_back(memento);
589 }
590 }
591 }
592 }
593
getFallbackKey(int32_t originalKeyCode)594 std::optional<int32_t> InputState::getFallbackKey(int32_t originalKeyCode) {
595 auto it = mFallbackKeys.find(originalKeyCode);
596 if (it == mFallbackKeys.end()) {
597 return {};
598 }
599 return it->second;
600 }
601
setFallbackKey(int32_t originalKeyCode,int32_t fallbackKeyCode)602 void InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) {
603 mFallbackKeys.insert_or_assign(originalKeyCode, fallbackKeyCode);
604 }
605
removeFallbackKey(int32_t originalKeyCode)606 void InputState::removeFallbackKey(int32_t originalKeyCode) {
607 mFallbackKeys.erase(originalKeyCode);
608 }
609
shouldCancelKey(const KeyMemento & memento,const CancelationOptions & options)610 bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) {
611 if (options.keyCode && memento.keyCode != options.keyCode.value()) {
612 return false;
613 }
614
615 if (options.deviceId && memento.deviceId != options.deviceId.value()) {
616 return false;
617 }
618
619 if (options.displayId && memento.displayId != options.displayId.value()) {
620 return false;
621 }
622
623 switch (options.mode) {
624 case CancelationOptions::Mode::CANCEL_ALL_EVENTS:
625 case CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS:
626 return true;
627 case CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS:
628 return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
629 default:
630 return false;
631 }
632 }
633
shouldCancelMotion(const MotionMemento & memento,const CancelationOptions & options)634 bool InputState::shouldCancelMotion(const MotionMemento& memento,
635 const CancelationOptions& options) {
636 if (options.deviceId && memento.deviceId != options.deviceId.value()) {
637 return false;
638 }
639
640 if (options.displayId && memento.displayId != options.displayId.value()) {
641 return false;
642 }
643
644 switch (options.mode) {
645 case CancelationOptions::Mode::CANCEL_ALL_EVENTS:
646 return true;
647 case CancelationOptions::Mode::CANCEL_POINTER_EVENTS:
648 return memento.source & AINPUT_SOURCE_CLASS_POINTER;
649 case CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS:
650 return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
651 case CancelationOptions::Mode::CANCEL_HOVER_EVENTS:
652 return memento.hovering;
653 default:
654 return false;
655 }
656 }
657
operator <<(std::ostream & out,const InputState & state)658 std::ostream& operator<<(std::ostream& out, const InputState& state) {
659 if (!state.mMotionMementos.empty()) {
660 out << "mMotionMementos: ";
661 for (const InputState::MotionMemento& memento : state.mMotionMementos) {
662 out << "{deviceId=" << memento.deviceId
663 << ", hovering=" << std::to_string(memento.hovering)
664 << ", downTime=" << memento.downTime << "}, ";
665 }
666 }
667 return out;
668 }
669
670 } // namespace android::inputdispatcher
671