blob: 7fa9e09aaddaca4feea1b16d544d143a8e5e0d7a [file] [log] [blame]
Garfield Tane84e6f92019-08-29 17:28:41 -07001/*
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 "InputState.h"
18
19namespace android::inputdispatcher {
20
21InputState::InputState() {}
22
23InputState::~InputState() {}
24
25bool InputState::isNeutral() const {
26 return mKeyMementos.empty() && mMotionMementos.empty();
27}
28
29bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const {
30 for (const MotionMemento& memento : mMotionMementos) {
31 if (memento.deviceId == deviceId && memento.source == source &&
32 memento.displayId == displayId && memento.hovering) {
33 return true;
34 }
35 }
36 return false;
37}
38
Siarhei Vishniakoud2770042019-10-29 11:08:14 -070039bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags) {
Garfield Tane84e6f92019-08-29 17:28:41 -070040 switch (action) {
41 case AKEY_EVENT_ACTION_UP: {
Siarhei Vishniakoud2770042019-10-29 11:08:14 -070042 if (entry.flags & AKEY_EVENT_FLAG_FALLBACK) {
Garfield Tane84e6f92019-08-29 17:28:41 -070043 for (size_t i = 0; i < mFallbackKeys.size();) {
Siarhei Vishniakoud2770042019-10-29 11:08:14 -070044 if (mFallbackKeys.valueAt(i) == entry.keyCode) {
Garfield Tane84e6f92019-08-29 17:28:41 -070045 mFallbackKeys.removeItemsAt(i);
46 } else {
47 i += 1;
48 }
49 }
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",
Siarhei Vishniakoud2770042019-10-29 11:08:14 -070068 entry.deviceId, entry.source, entry.keyCode, entry.scanCode);
Garfield Tane84e6f92019-08-29 17:28:41 -070069 #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
Siarhei Vishniakoud2770042019-10-29 11:08:14 -070089bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t flags) {
Garfield Tane84e6f92019-08-29 17:28:41 -070090 int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
91 switch (actionMasked) {
92 case AMOTION_EVENT_ACTION_UP:
93 case AMOTION_EVENT_ACTION_CANCEL: {
94 ssize_t index = findMotionMemento(entry, false /*hovering*/);
95 if (index >= 0) {
96 mMotionMementos.erase(mMotionMementos.begin() + index);
97 return true;
98 }
99#if DEBUG_OUTBOUND_EVENT_DETAILS
100 ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
101 "displayId=%" PRId32 ", actionMasked=%d",
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700102 entry.deviceId, entry.source, entry.displayId, actionMasked);
Garfield Tane84e6f92019-08-29 17:28:41 -0700103#endif
104 return false;
105 }
106
107 case AMOTION_EVENT_ACTION_DOWN: {
108 ssize_t index = findMotionMemento(entry, false /*hovering*/);
109 if (index >= 0) {
110 mMotionMementos.erase(mMotionMementos.begin() + index);
111 }
112 addMotionMemento(entry, flags, false /*hovering*/);
113 return true;
114 }
115
116 case AMOTION_EVENT_ACTION_POINTER_UP:
117 case AMOTION_EVENT_ACTION_POINTER_DOWN:
118 case AMOTION_EVENT_ACTION_MOVE: {
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700119 if (entry.source & AINPUT_SOURCE_CLASS_NAVIGATION) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700120 // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
121 // to generate cancellation events for these since they're based in relative rather
122 // than absolute units.
123 return true;
124 }
125
126 ssize_t index = findMotionMemento(entry, false /*hovering*/);
127
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700128 if (entry.source & AINPUT_SOURCE_CLASS_JOYSTICK) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700129 // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
130 // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
131 // Any other value and we need to track the motion so we can send cancellation
132 // events for anything generating fallback events (e.g. DPad keys for joystick
133 // movements).
134 if (index >= 0) {
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700135 if (entry.pointerCoords[0].isEmpty()) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700136 mMotionMementos.erase(mMotionMementos.begin() + index);
137 } else {
138 MotionMemento& memento = mMotionMementos[index];
139 memento.setPointers(entry);
140 }
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700141 } else if (!entry.pointerCoords[0].isEmpty()) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700142 addMotionMemento(entry, flags, false /*hovering*/);
143 }
144
145 // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
146 return true;
147 }
Svet Ganov5d3bc372020-01-26 23:11:07 -0800148
Garfield Tane84e6f92019-08-29 17:28:41 -0700149 if (index >= 0) {
150 MotionMemento& memento = mMotionMementos[index];
Svet Ganov5d3bc372020-01-26 23:11:07 -0800151 if (memento.firstNewPointerIdx < 0) {
152 memento.setPointers(entry);
153 return true;
154 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700155 }
156#if DEBUG_OUTBOUND_EVENT_DETAILS
157 ALOGD("Dropping inconsistent motion pointer up/down or move event: "
158 "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700159 entry.deviceId, entry.source, entry.displayId, actionMasked);
Garfield Tane84e6f92019-08-29 17:28:41 -0700160#endif
161 return false;
162 }
163
164 case AMOTION_EVENT_ACTION_HOVER_EXIT: {
165 ssize_t index = findMotionMemento(entry, true /*hovering*/);
166 if (index >= 0) {
167 mMotionMementos.erase(mMotionMementos.begin() + index);
168 return true;
169 }
170#if DEBUG_OUTBOUND_EVENT_DETAILS
171 ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
172 "displayId=%" PRId32,
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700173 entry.deviceId, entry.source, entry.displayId);
Garfield Tane84e6f92019-08-29 17:28:41 -0700174#endif
175 return false;
176 }
177
178 case AMOTION_EVENT_ACTION_HOVER_ENTER:
179 case AMOTION_EVENT_ACTION_HOVER_MOVE: {
180 ssize_t index = findMotionMemento(entry, true /*hovering*/);
181 if (index >= 0) {
182 mMotionMementos.erase(mMotionMementos.begin() + index);
183 }
184 addMotionMemento(entry, flags, true /*hovering*/);
185 return true;
186 }
187
188 default:
189 return true;
190 }
191}
192
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700193ssize_t InputState::findKeyMemento(const KeyEntry& entry) const {
Garfield Tane84e6f92019-08-29 17:28:41 -0700194 for (size_t i = 0; i < mKeyMementos.size(); i++) {
195 const KeyMemento& memento = mKeyMementos[i];
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700196 if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
197 memento.displayId == entry.displayId && memento.keyCode == entry.keyCode &&
198 memento.scanCode == entry.scanCode) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700199 return i;
200 }
201 }
202 return -1;
203}
204
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700205ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const {
Garfield Tane84e6f92019-08-29 17:28:41 -0700206 for (size_t i = 0; i < mMotionMementos.size(); i++) {
207 const MotionMemento& memento = mMotionMementos[i];
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700208 if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
209 memento.displayId == entry.displayId && memento.hovering == hovering) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700210 return i;
211 }
212 }
213 return -1;
214}
215
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700216void InputState::addKeyMemento(const KeyEntry& entry, int32_t flags) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700217 KeyMemento memento;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700218 memento.deviceId = entry.deviceId;
219 memento.source = entry.source;
220 memento.displayId = entry.displayId;
221 memento.keyCode = entry.keyCode;
222 memento.scanCode = entry.scanCode;
223 memento.metaState = entry.metaState;
Garfield Tane84e6f92019-08-29 17:28:41 -0700224 memento.flags = flags;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700225 memento.downTime = entry.downTime;
226 memento.policyFlags = entry.policyFlags;
Garfield Tane84e6f92019-08-29 17:28:41 -0700227 mKeyMementos.push_back(memento);
228}
229
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700230void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool hovering) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700231 MotionMemento memento;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700232 memento.deviceId = entry.deviceId;
233 memento.source = entry.source;
234 memento.displayId = entry.displayId;
Garfield Tane84e6f92019-08-29 17:28:41 -0700235 memento.flags = flags;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700236 memento.xPrecision = entry.xPrecision;
237 memento.yPrecision = entry.yPrecision;
238 memento.xCursorPosition = entry.xCursorPosition;
239 memento.yCursorPosition = entry.yCursorPosition;
240 memento.downTime = entry.downTime;
Garfield Tane84e6f92019-08-29 17:28:41 -0700241 memento.setPointers(entry);
242 memento.hovering = hovering;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700243 memento.policyFlags = entry.policyFlags;
Garfield Tane84e6f92019-08-29 17:28:41 -0700244 mMotionMementos.push_back(memento);
245}
246
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700247void InputState::MotionMemento::setPointers(const MotionEntry& entry) {
248 pointerCount = entry.pointerCount;
249 for (uint32_t i = 0; i < entry.pointerCount; i++) {
250 pointerProperties[i].copyFrom(entry.pointerProperties[i]);
251 pointerCoords[i].copyFrom(entry.pointerCoords[i]);
Garfield Tane84e6f92019-08-29 17:28:41 -0700252 }
253}
254
Svet Ganov5d3bc372020-01-26 23:11:07 -0800255void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const {
256 for (uint32_t i = 0; i < pointerCount; i++) {
257 if (other.firstNewPointerIdx < 0) {
258 other.firstNewPointerIdx = other.pointerCount;
259 }
260 other.pointerProperties[other.pointerCount].copyFrom(pointerProperties[i]);
261 other.pointerCoords[other.pointerCount].copyFrom(pointerCoords[i]);
262 other.pointerCount++;
263 }
264}
265
Siarhei Vishniakou00fca7c2019-10-29 13:05:57 -0700266std::vector<EventEntry*> InputState::synthesizeCancelationEvents(
267 nsecs_t currentTime, const CancelationOptions& options) {
268 std::vector<EventEntry*> events;
Garfield Tane84e6f92019-08-29 17:28:41 -0700269 for (KeyMemento& memento : mKeyMementos) {
270 if (shouldCancelKey(memento, options)) {
Garfield Tan6a5a14e2020-01-28 13:24:04 -0800271 events.push_back(new KeyEntry(SYNTHESIZED_EVENT_ID, currentTime, memento.deviceId,
272 memento.source, memento.displayId, memento.policyFlags,
273 AKEY_EVENT_ACTION_UP,
Siarhei Vishniakou00fca7c2019-10-29 13:05:57 -0700274 memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode,
275 memento.scanCode, memento.metaState, 0 /*repeatCount*/,
276 memento.downTime));
Garfield Tane84e6f92019-08-29 17:28:41 -0700277 }
278 }
279
280 for (const MotionMemento& memento : mMotionMementos) {
281 if (shouldCancelMotion(memento, options)) {
282 const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
283 : AMOTION_EVENT_ACTION_CANCEL;
Garfield Tan6a5a14e2020-01-28 13:24:04 -0800284 events.push_back(new MotionEntry(SYNTHESIZED_EVENT_ID, currentTime, memento.deviceId,
285 memento.source, memento.displayId, memento.policyFlags,
286 action, 0 /*actionButton*/, memento.flags, AMETA_NONE,
287 0 /*buttonState*/, MotionClassification::NONE,
Siarhei Vishniakou00fca7c2019-10-29 13:05:57 -0700288 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
289 memento.yPrecision, memento.xCursorPosition,
290 memento.yCursorPosition, memento.downTime,
291 memento.pointerCount, memento.pointerProperties,
292 memento.pointerCoords, 0 /*xOffset*/, 0 /*yOffset*/));
Garfield Tane84e6f92019-08-29 17:28:41 -0700293 }
294 }
Siarhei Vishniakou00fca7c2019-10-29 13:05:57 -0700295 return events;
Garfield Tane84e6f92019-08-29 17:28:41 -0700296}
297
Svet Ganov5d3bc372020-01-26 23:11:07 -0800298std::vector<EventEntry*> InputState::synthesizePointerDownEvents(nsecs_t currentTime) {
299 std::vector<EventEntry*> events;
300 for (MotionMemento& memento : mMotionMementos) {
301 if (!(memento.source & AINPUT_SOURCE_CLASS_POINTER)) {
302 continue;
303 }
304
305 if (memento.firstNewPointerIdx < 0) {
306 continue;
307 }
308
309 uint32_t pointerCount = 0;
310 PointerProperties pointerProperties[MAX_POINTERS];
311 PointerCoords pointerCoords[MAX_POINTERS];
312
313 // We will deliver all pointers the target already knows about
314 for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
315 pointerProperties[i].copyFrom(memento.pointerProperties[i]);
316 pointerCoords[i].copyFrom(memento.pointerCoords[i]);
317 pointerCount++;
318 }
319
320 // We will send explicit events for all pointers the target doesn't know about
321 for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
322 i < memento.pointerCount; i++) {
323
324 pointerProperties[i].copyFrom(memento.pointerProperties[i]);
325 pointerCoords[i].copyFrom(memento.pointerCoords[i]);
326 pointerCount++;
327
328 // Down only if the first pointer, pointer down otherwise
329 const int32_t action = (pointerCount <= 1)
330 ? AMOTION_EVENT_ACTION_DOWN
331 : AMOTION_EVENT_ACTION_POINTER_DOWN
332 | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
333
Garfield Tan6a5a14e2020-01-28 13:24:04 -0800334 events.push_back(new MotionEntry(SYNTHESIZED_EVENT_ID, currentTime, memento.deviceId,
335 memento.source, memento.displayId, memento.policyFlags,
336 action, 0 /*actionButton*/, memento.flags, AMETA_NONE,
337 0 /*buttonState*/, MotionClassification::NONE,
Svet Ganov5d3bc372020-01-26 23:11:07 -0800338 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
339 memento.yPrecision, memento.xCursorPosition,
340 memento.yCursorPosition, memento.downTime,
Garfield Tan6a5a14e2020-01-28 13:24:04 -0800341 pointerCount, pointerProperties, pointerCoords,
342 0 /*xOffset*/, 0 /*yOffset*/));
Svet Ganov5d3bc372020-01-26 23:11:07 -0800343 }
344
345 memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
346 }
347
348 return events;
349}
350
Garfield Tane84e6f92019-08-29 17:28:41 -0700351void InputState::clear() {
352 mKeyMementos.clear();
353 mMotionMementos.clear();
354 mFallbackKeys.clear();
355}
356
Svet Ganov5d3bc372020-01-26 23:11:07 -0800357void InputState::mergePointerStateTo(InputState& other) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700358 for (size_t i = 0; i < mMotionMementos.size(); i++) {
Svet Ganov5d3bc372020-01-26 23:11:07 -0800359 MotionMemento& memento = mMotionMementos[i];
360 // Since we support split pointers we need to merge touch events
361 // from the same source + device + screen.
Garfield Tane84e6f92019-08-29 17:28:41 -0700362 if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
Svet Ganov5d3bc372020-01-26 23:11:07 -0800363 bool merged = false;
364 for (size_t j = 0; j < other.mMotionMementos.size(); j++) {
365 MotionMemento& otherMemento = other.mMotionMementos[j];
Garfield Tane84e6f92019-08-29 17:28:41 -0700366 if (memento.deviceId == otherMemento.deviceId &&
367 memento.source == otherMemento.source &&
368 memento.displayId == otherMemento.displayId) {
Svet Ganov5d3bc372020-01-26 23:11:07 -0800369 memento.mergePointerStateTo(otherMemento);
370 merged = true;
371 break;
Garfield Tane84e6f92019-08-29 17:28:41 -0700372 }
373 }
Svet Ganov5d3bc372020-01-26 23:11:07 -0800374 if (!merged) {
375 memento.firstNewPointerIdx = 0;
376 other.mMotionMementos.push_back(memento);
377 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700378 }
379 }
380}
381
382int32_t InputState::getFallbackKey(int32_t originalKeyCode) {
383 ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
384 return index >= 0 ? mFallbackKeys.valueAt(index) : -1;
385}
386
387void InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) {
388 ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
389 if (index >= 0) {
390 mFallbackKeys.replaceValueAt(index, fallbackKeyCode);
391 } else {
392 mFallbackKeys.add(originalKeyCode, fallbackKeyCode);
393 }
394}
395
396void InputState::removeFallbackKey(int32_t originalKeyCode) {
397 mFallbackKeys.removeItem(originalKeyCode);
398}
399
400bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) {
401 if (options.keyCode && memento.keyCode != options.keyCode.value()) {
402 return false;
403 }
404
405 if (options.deviceId && memento.deviceId != options.deviceId.value()) {
406 return false;
407 }
408
409 if (options.displayId && memento.displayId != options.displayId.value()) {
410 return false;
411 }
412
413 switch (options.mode) {
414 case CancelationOptions::CANCEL_ALL_EVENTS:
415 case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
416 return true;
417 case CancelationOptions::CANCEL_FALLBACK_EVENTS:
418 return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
419 default:
420 return false;
421 }
422}
423
424bool InputState::shouldCancelMotion(const MotionMemento& memento,
425 const CancelationOptions& options) {
426 if (options.deviceId && memento.deviceId != options.deviceId.value()) {
427 return false;
428 }
429
430 if (options.displayId && memento.displayId != options.displayId.value()) {
431 return false;
432 }
433
434 switch (options.mode) {
435 case CancelationOptions::CANCEL_ALL_EVENTS:
436 return true;
437 case CancelationOptions::CANCEL_POINTER_EVENTS:
438 return memento.source & AINPUT_SOURCE_CLASS_POINTER;
439 case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
440 return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
441 default:
442 return false;
443 }
444}
445
446} // namespace android::inputdispatcher