• 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 
isNeutral() const31 bool InputState::isNeutral() const {
32     return mKeyMementos.empty() && mMotionMementos.empty();
33 }
34 
isHovering(int32_t deviceId,uint32_t source,int32_t displayId) const35 bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const {
36     for (const MotionMemento& memento : mMotionMementos) {
37         if (memento.deviceId == deviceId && memento.source == source &&
38             memento.displayId == displayId && memento.hovering) {
39             return true;
40         }
41     }
42     return false;
43 }
44 
trackKey(const KeyEntry & entry,int32_t action,int32_t flags)45 bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags) {
46     switch (action) {
47         case AKEY_EVENT_ACTION_UP: {
48             if (entry.flags & AKEY_EVENT_FLAG_FALLBACK) {
49                 for (size_t i = 0; i < mFallbackKeys.size();) {
50                     if (mFallbackKeys.valueAt(i) == entry.keyCode) {
51                         mFallbackKeys.removeItemsAt(i);
52                     } else {
53                         i += 1;
54                     }
55                 }
56             }
57             ssize_t index = findKeyMemento(entry);
58             if (index >= 0) {
59                 mKeyMementos.erase(mKeyMementos.begin() + index);
60                 return true;
61             }
62             /* FIXME: We can't just drop the key up event because that prevents creating
63              * popup windows that are automatically shown when a key is held and then
64              * dismissed when the key is released.  The problem is that the popup will
65              * not have received the original key down, so the key up will be considered
66              * to be inconsistent with its observed state.  We could perhaps handle this
67              * by synthesizing a key down but that will cause other problems.
68              *
69              * So for now, allow inconsistent key up events to be dispatched.
70              *
71     #if DEBUG_OUTBOUND_EVENT_DETAILS
72             ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
73                     "keyCode=%d, scanCode=%d",
74                     entry.deviceId, entry.source, entry.keyCode, entry.scanCode);
75     #endif
76             return false;
77             */
78             return true;
79         }
80 
81         case AKEY_EVENT_ACTION_DOWN: {
82             ssize_t index = findKeyMemento(entry);
83             if (index >= 0) {
84                 mKeyMementos.erase(mKeyMementos.begin() + index);
85             }
86             addKeyMemento(entry, flags);
87             return true;
88         }
89 
90         default:
91             return true;
92     }
93 }
94 
trackMotion(const MotionEntry & entry,int32_t action,int32_t flags)95 bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t flags) {
96     int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
97     switch (actionMasked) {
98         case AMOTION_EVENT_ACTION_UP:
99         case AMOTION_EVENT_ACTION_CANCEL: {
100             ssize_t index = findMotionMemento(entry, false /*hovering*/);
101             if (index >= 0) {
102                 mMotionMementos.erase(mMotionMementos.begin() + index);
103                 return true;
104             }
105             if (DEBUG_OUTBOUND_EVENT_DETAILS) {
106                 ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
107                       "displayId=%" PRId32 ", actionMasked=%d",
108                       entry.deviceId, entry.source, entry.displayId, actionMasked);
109             }
110             return false;
111         }
112 
113         case AMOTION_EVENT_ACTION_DOWN: {
114             ssize_t index = findMotionMemento(entry, false /*hovering*/);
115             if (index >= 0) {
116                 mMotionMementos.erase(mMotionMementos.begin() + index);
117             }
118             addMotionMemento(entry, flags, false /*hovering*/);
119             return true;
120         }
121 
122         case AMOTION_EVENT_ACTION_POINTER_UP:
123         case AMOTION_EVENT_ACTION_POINTER_DOWN:
124         case AMOTION_EVENT_ACTION_MOVE: {
125             if (entry.source & AINPUT_SOURCE_CLASS_NAVIGATION) {
126                 // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
127                 // to generate cancellation events for these since they're based in relative rather
128                 // than absolute units.
129                 return true;
130             }
131 
132             ssize_t index = findMotionMemento(entry, false /*hovering*/);
133 
134             if (entry.source & AINPUT_SOURCE_CLASS_JOYSTICK) {
135                 // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
136                 // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
137                 // Any other value and we need to track the motion so we can send cancellation
138                 // events for anything generating fallback events (e.g. DPad keys for joystick
139                 // movements).
140                 if (index >= 0) {
141                     if (entry.pointerCoords[0].isEmpty()) {
142                         mMotionMementos.erase(mMotionMementos.begin() + index);
143                     } else {
144                         MotionMemento& memento = mMotionMementos[index];
145                         memento.setPointers(entry);
146                     }
147                 } else if (!entry.pointerCoords[0].isEmpty()) {
148                     addMotionMemento(entry, flags, false /*hovering*/);
149                 }
150 
151                 // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
152                 return true;
153             }
154 
155             if (index >= 0) {
156                 MotionMemento& memento = mMotionMementos[index];
157                 if (memento.firstNewPointerIdx < 0) {
158                     memento.setPointers(entry);
159                     return true;
160                 }
161             }
162             if (DEBUG_OUTBOUND_EVENT_DETAILS) {
163                 ALOGD("Dropping inconsistent motion pointer up/down or move event: "
164                       "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
165                       entry.deviceId, entry.source, entry.displayId, actionMasked);
166             }
167             return false;
168         }
169 
170         case AMOTION_EVENT_ACTION_HOVER_EXIT: {
171             ssize_t index = findMotionMemento(entry, true /*hovering*/);
172             if (index >= 0) {
173                 mMotionMementos.erase(mMotionMementos.begin() + index);
174                 return true;
175             }
176             if (DEBUG_OUTBOUND_EVENT_DETAILS) {
177                 ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
178                       "displayId=%" PRId32,
179                       entry.deviceId, entry.source, entry.displayId);
180             }
181             return false;
182         }
183 
184         case AMOTION_EVENT_ACTION_HOVER_ENTER:
185         case AMOTION_EVENT_ACTION_HOVER_MOVE: {
186             ssize_t index = findMotionMemento(entry, true /*hovering*/);
187             if (index >= 0) {
188                 mMotionMementos.erase(mMotionMementos.begin() + index);
189             }
190             addMotionMemento(entry, flags, true /*hovering*/);
191             return true;
192         }
193 
194         default:
195             return true;
196     }
197 }
198 
findKeyMemento(const KeyEntry & entry) const199 ssize_t InputState::findKeyMemento(const KeyEntry& entry) const {
200     for (size_t i = 0; i < mKeyMementos.size(); i++) {
201         const KeyMemento& memento = mKeyMementos[i];
202         if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
203             memento.displayId == entry.displayId && memento.keyCode == entry.keyCode &&
204             memento.scanCode == entry.scanCode) {
205             return i;
206         }
207     }
208     return -1;
209 }
210 
findMotionMemento(const MotionEntry & entry,bool hovering) const211 ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const {
212     for (size_t i = 0; i < mMotionMementos.size(); i++) {
213         const MotionMemento& memento = mMotionMementos[i];
214         if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
215             memento.displayId == entry.displayId && memento.hovering == hovering) {
216             return i;
217         }
218     }
219     return -1;
220 }
221 
addKeyMemento(const KeyEntry & entry,int32_t flags)222 void InputState::addKeyMemento(const KeyEntry& entry, int32_t flags) {
223     KeyMemento memento;
224     memento.deviceId = entry.deviceId;
225     memento.source = entry.source;
226     memento.displayId = entry.displayId;
227     memento.keyCode = entry.keyCode;
228     memento.scanCode = entry.scanCode;
229     memento.metaState = entry.metaState;
230     memento.flags = flags;
231     memento.downTime = entry.downTime;
232     memento.policyFlags = entry.policyFlags;
233     mKeyMementos.push_back(memento);
234 }
235 
addMotionMemento(const MotionEntry & entry,int32_t flags,bool hovering)236 void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool hovering) {
237     MotionMemento memento;
238     memento.deviceId = entry.deviceId;
239     memento.source = entry.source;
240     memento.displayId = entry.displayId;
241     memento.flags = flags;
242     memento.xPrecision = entry.xPrecision;
243     memento.yPrecision = entry.yPrecision;
244     memento.xCursorPosition = entry.xCursorPosition;
245     memento.yCursorPosition = entry.yCursorPosition;
246     memento.downTime = entry.downTime;
247     memento.setPointers(entry);
248     memento.hovering = hovering;
249     memento.policyFlags = entry.policyFlags;
250     mMotionMementos.push_back(memento);
251 }
252 
setPointers(const MotionEntry & entry)253 void InputState::MotionMemento::setPointers(const MotionEntry& entry) {
254     pointerCount = entry.pointerCount;
255     for (uint32_t i = 0; i < entry.pointerCount; i++) {
256         pointerProperties[i].copyFrom(entry.pointerProperties[i]);
257         pointerCoords[i].copyFrom(entry.pointerCoords[i]);
258     }
259 }
260 
mergePointerStateTo(MotionMemento & other) const261 void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const {
262     for (uint32_t i = 0; i < pointerCount; i++) {
263         if (other.firstNewPointerIdx < 0) {
264             other.firstNewPointerIdx = other.pointerCount;
265         }
266         other.pointerProperties[other.pointerCount].copyFrom(pointerProperties[i]);
267         other.pointerCoords[other.pointerCount].copyFrom(pointerCoords[i]);
268         other.pointerCount++;
269     }
270 }
271 
synthesizeCancelationEvents(nsecs_t currentTime,const CancelationOptions & options)272 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents(
273         nsecs_t currentTime, const CancelationOptions& options) {
274     std::vector<std::unique_ptr<EventEntry>> events;
275     for (KeyMemento& memento : mKeyMementos) {
276         if (shouldCancelKey(memento, options)) {
277             events.push_back(
278                     std::make_unique<KeyEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId,
279                                                memento.source, memento.displayId,
280                                                memento.policyFlags, AKEY_EVENT_ACTION_UP,
281                                                memento.flags | AKEY_EVENT_FLAG_CANCELED,
282                                                memento.keyCode, memento.scanCode, memento.metaState,
283                                                0 /*repeatCount*/, memento.downTime));
284         }
285     }
286 
287     for (const MotionMemento& memento : mMotionMementos) {
288         if (shouldCancelMotion(memento, options)) {
289             const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
290                                                     : AMOTION_EVENT_ACTION_CANCEL;
291             events.push_back(
292                     std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
293                                                   memento.deviceId, memento.source,
294                                                   memento.displayId, memento.policyFlags, action,
295                                                   0 /*actionButton*/, memento.flags, AMETA_NONE,
296                                                   0 /*buttonState*/, MotionClassification::NONE,
297                                                   AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
298                                                   memento.yPrecision, memento.xCursorPosition,
299                                                   memento.yCursorPosition, memento.downTime,
300                                                   memento.pointerCount, memento.pointerProperties,
301                                                   memento.pointerCoords));
302         }
303     }
304     return events;
305 }
306 
synthesizePointerDownEvents(nsecs_t currentTime)307 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents(
308         nsecs_t currentTime) {
309     std::vector<std::unique_ptr<EventEntry>> events;
310     for (MotionMemento& memento : mMotionMementos) {
311         if (!(memento.source & AINPUT_SOURCE_CLASS_POINTER)) {
312             continue;
313         }
314 
315         if (memento.firstNewPointerIdx < 0) {
316             continue;
317         }
318 
319         uint32_t pointerCount = 0;
320         PointerProperties pointerProperties[MAX_POINTERS];
321         PointerCoords pointerCoords[MAX_POINTERS];
322 
323         // We will deliver all pointers the target already knows about
324         for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
325             pointerProperties[i].copyFrom(memento.pointerProperties[i]);
326             pointerCoords[i].copyFrom(memento.pointerCoords[i]);
327             pointerCount++;
328         }
329 
330         // We will send explicit events for all pointers the target doesn't know about
331         for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
332                 i < memento.pointerCount; i++) {
333 
334             pointerProperties[i].copyFrom(memento.pointerProperties[i]);
335             pointerCoords[i].copyFrom(memento.pointerCoords[i]);
336             pointerCount++;
337 
338             // Down only if the first pointer, pointer down otherwise
339             const int32_t action = (pointerCount <= 1)
340                     ? AMOTION_EVENT_ACTION_DOWN
341                     : AMOTION_EVENT_ACTION_POINTER_DOWN
342                             | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
343 
344             events.push_back(
345                     std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
346                                                   memento.deviceId, memento.source,
347                                                   memento.displayId, memento.policyFlags, action,
348                                                   0 /*actionButton*/, memento.flags, AMETA_NONE,
349                                                   0 /*buttonState*/, MotionClassification::NONE,
350                                                   AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
351                                                   memento.yPrecision, memento.xCursorPosition,
352                                                   memento.yCursorPosition, memento.downTime,
353                                                   pointerCount, pointerProperties, pointerCoords));
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