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