blob: b2a4d6c8fdd5a2f671b05301ffc0e3aa8d71bbea [file] [log] [blame]
Jeff Brownfd0358292010-06-30 16:10:35 -07001//
2// Copyright 2010 The Android Open Source Project
3//
4// The input reader.
5//
6#define LOG_TAG "InputDevice"
7
8//#define LOG_NDEBUG 0
9
10// Log debug messages for each raw event received from the EventHub.
11#define DEBUG_RAW_EVENTS 0
12
13// Log debug messages about touch screen filtering hacks.
14#define DEBUG_HACKS 0
15
16// Log debug messages about virtual key processing.
17#define DEBUG_VIRTUAL_KEYS 0
18
19// Log debug messages about pointers.
20#define DEBUG_POINTERS 0
21
22// Log debug messages about pointer assignment calculations.
23#define DEBUG_POINTER_ASSIGNMENT 0
24
25#include <cutils/log.h>
26#include <ui/InputDevice.h>
27
28#include <stddef.h>
29#include <unistd.h>
30#include <errno.h>
31#include <limits.h>
32
33/* Slop distance for jumpy pointer detection.
34 * The vertical range of the screen divided by this is our epsilon value. */
35#define JUMPY_EPSILON_DIVISOR 212
36
37/* Number of jumpy points to drop for touchscreens that need it. */
38#define JUMPY_TRANSITION_DROPS 3
39#define JUMPY_DROP_LIMIT 3
40
41/* Maximum squared distance for averaging.
42 * If moving farther than this, turn of averaging to avoid lag in response. */
43#define AVERAGING_DISTANCE_LIMIT (75 * 75)
44
45
46namespace android {
47
48// --- Static Functions ---
49
50template<typename T>
51inline static T abs(const T& value) {
52 return value < 0 ? - value : value;
53}
54
55template<typename T>
56inline static T min(const T& a, const T& b) {
57 return a < b ? a : b;
58}
59
60template<typename T>
61inline static void swap(T& a, T& b) {
62 T temp = a;
63 a = b;
64 b = temp;
65}
66
67
68// --- InputDevice ---
69
70InputDevice::InputDevice(int32_t id, uint32_t classes, String8 name) :
71 id(id), classes(classes), name(name), ignored(false) {
72}
73
74void InputDevice::reset() {
75 if (isKeyboard()) {
76 keyboard.reset();
77 }
78
79 if (isTrackball()) {
80 trackball.reset();
81 }
82
83 if (isMultiTouchScreen()) {
84 multiTouchScreen.reset();
85 } else if (isSingleTouchScreen()) {
86 singleTouchScreen.reset();
87 }
88
89 if (isTouchScreen()) {
90 touchScreen.reset();
91 }
92}
93
94
95// --- InputDevice::TouchData ---
96
97void InputDevice::TouchData::copyFrom(const TouchData& other) {
98 pointerCount = other.pointerCount;
99 idBits = other.idBits;
100
101 for (uint32_t i = 0; i < pointerCount; i++) {
102 pointers[i] = other.pointers[i];
103 idToIndex[i] = other.idToIndex[i];
104 }
105}
106
107
108// --- InputDevice::KeyboardState ---
109
110void InputDevice::KeyboardState::reset() {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700111 current.metaState = AMETA_NONE;
Jeff Brownfd0358292010-06-30 16:10:35 -0700112 current.downTime = 0;
113}
114
115
116// --- InputDevice::TrackballState ---
117
118void InputDevice::TrackballState::reset() {
119 accumulator.clear();
120 current.down = false;
121 current.downTime = 0;
122}
123
124
125// --- InputDevice::TouchScreenState ---
126
127void InputDevice::TouchScreenState::reset() {
128 lastTouch.clear();
129 downTime = 0;
130 currentVirtualKey.status = CurrentVirtualKeyState::STATUS_UP;
131
132 for (uint32_t i = 0; i < MAX_POINTERS; i++) {
133 averagingTouchFilter.historyStart[i] = 0;
134 averagingTouchFilter.historyEnd[i] = 0;
135 }
136
137 jumpyTouchFilter.jumpyPointsDropped = 0;
138}
139
140struct PointerDistanceHeapElement {
141 uint32_t currentPointerIndex : 8;
142 uint32_t lastPointerIndex : 8;
143 uint64_t distance : 48; // squared distance
144};
145
146void InputDevice::TouchScreenState::calculatePointerIds() {
147 uint32_t currentPointerCount = currentTouch.pointerCount;
148 uint32_t lastPointerCount = lastTouch.pointerCount;
149
150 if (currentPointerCount == 0) {
151 // No pointers to assign.
152 currentTouch.idBits.clear();
153 } else if (lastPointerCount == 0) {
154 // All pointers are new.
155 currentTouch.idBits.clear();
156 for (uint32_t i = 0; i < currentPointerCount; i++) {
157 currentTouch.pointers[i].id = i;
158 currentTouch.idToIndex[i] = i;
159 currentTouch.idBits.markBit(i);
160 }
161 } else if (currentPointerCount == 1 && lastPointerCount == 1) {
162 // Only one pointer and no change in count so it must have the same id as before.
163 uint32_t id = lastTouch.pointers[0].id;
164 currentTouch.pointers[0].id = id;
165 currentTouch.idToIndex[id] = 0;
166 currentTouch.idBits.value = BitSet32::valueForBit(id);
167 } else {
168 // General case.
169 // We build a heap of squared euclidean distances between current and last pointers
170 // associated with the current and last pointer indices. Then, we find the best
171 // match (by distance) for each current pointer.
172 PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
173
174 uint32_t heapSize = 0;
175 for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
176 currentPointerIndex++) {
177 for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
178 lastPointerIndex++) {
179 int64_t deltaX = currentTouch.pointers[currentPointerIndex].x
180 - lastTouch.pointers[lastPointerIndex].x;
181 int64_t deltaY = currentTouch.pointers[currentPointerIndex].y
182 - lastTouch.pointers[lastPointerIndex].y;
183
184 uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
185
186 // Insert new element into the heap (sift up).
187 heap[heapSize].currentPointerIndex = currentPointerIndex;
188 heap[heapSize].lastPointerIndex = lastPointerIndex;
189 heap[heapSize].distance = distance;
190 heapSize += 1;
191 }
192 }
193
194 // Heapify
195 for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
196 startIndex -= 1;
197 for (uint32_t parentIndex = startIndex; ;) {
198 uint32_t childIndex = parentIndex * 2 + 1;
199 if (childIndex >= heapSize) {
200 break;
201 }
202
203 if (childIndex + 1 < heapSize
204 && heap[childIndex + 1].distance < heap[childIndex].distance) {
205 childIndex += 1;
206 }
207
208 if (heap[parentIndex].distance <= heap[childIndex].distance) {
209 break;
210 }
211
212 swap(heap[parentIndex], heap[childIndex]);
213 parentIndex = childIndex;
214 }
215 }
216
217#if DEBUG_POINTER_ASSIGNMENT
218 LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
219 for (size_t i = 0; i < heapSize; i++) {
220 LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
221 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
222 heap[i].distance);
223 }
224#endif
225
226 // Pull matches out by increasing order of distance.
227 // To avoid reassigning pointers that have already been matched, the loop keeps track
228 // of which last and current pointers have been matched using the matchedXXXBits variables.
229 // It also tracks the used pointer id bits.
230 BitSet32 matchedLastBits(0);
231 BitSet32 matchedCurrentBits(0);
232 BitSet32 usedIdBits(0);
233 bool first = true;
234 for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) {
235 for (;;) {
236 if (first) {
237 // The first time through the loop, we just consume the root element of
238 // the heap (the one with smallest distance).
239 first = false;
240 } else {
241 // Previous iterations consumed the root element of the heap.
242 // Pop root element off of the heap (sift down).
243 heapSize -= 1;
244 assert(heapSize > 0);
245
246 // Sift down.
247 heap[0] = heap[heapSize];
248 for (uint32_t parentIndex = 0; ;) {
249 uint32_t childIndex = parentIndex * 2 + 1;
250 if (childIndex >= heapSize) {
251 break;
252 }
253
254 if (childIndex + 1 < heapSize
255 && heap[childIndex + 1].distance < heap[childIndex].distance) {
256 childIndex += 1;
257 }
258
259 if (heap[parentIndex].distance <= heap[childIndex].distance) {
260 break;
261 }
262
263 swap(heap[parentIndex], heap[childIndex]);
264 parentIndex = childIndex;
265 }
266
267#if DEBUG_POINTER_ASSIGNMENT
268 LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
269 for (size_t i = 0; i < heapSize; i++) {
270 LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
271 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
272 heap[i].distance);
273 }
274#endif
275 }
276
277 uint32_t currentPointerIndex = heap[0].currentPointerIndex;
278 if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
279
280 uint32_t lastPointerIndex = heap[0].lastPointerIndex;
281 if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
282
283 matchedCurrentBits.markBit(currentPointerIndex);
284 matchedLastBits.markBit(lastPointerIndex);
285
286 uint32_t id = lastTouch.pointers[lastPointerIndex].id;
287 currentTouch.pointers[currentPointerIndex].id = id;
288 currentTouch.idToIndex[id] = currentPointerIndex;
289 usedIdBits.markBit(id);
290
291#if DEBUG_POINTER_ASSIGNMENT
292 LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
293 lastPointerIndex, currentPointerIndex, id, heap[0].distance);
294#endif
295 break;
296 }
297 }
298
299 // Assign fresh ids to new pointers.
300 if (currentPointerCount > lastPointerCount) {
301 for (uint32_t i = currentPointerCount - lastPointerCount; ;) {
302 uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit();
303 uint32_t id = usedIdBits.firstUnmarkedBit();
304
305 currentTouch.pointers[currentPointerIndex].id = id;
306 currentTouch.idToIndex[id] = currentPointerIndex;
307 usedIdBits.markBit(id);
308
309#if DEBUG_POINTER_ASSIGNMENT
310 LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
311 currentPointerIndex, id);
312#endif
313
314 if (--i == 0) break; // done
315 matchedCurrentBits.markBit(currentPointerIndex);
316 }
317 }
318
319 // Fix id bits.
320 currentTouch.idBits = usedIdBits;
321 }
322}
323
324/* Special hack for devices that have bad screen data: if one of the
325 * points has moved more than a screen height from the last position,
326 * then drop it. */
327bool InputDevice::TouchScreenState::applyBadTouchFilter() {
328 // This hack requires valid axis parameters.
329 if (! parameters.yAxis.valid) {
330 return false;
331 }
332
333 uint32_t pointerCount = currentTouch.pointerCount;
334
335 // Nothing to do if there are no points.
336 if (pointerCount == 0) {
337 return false;
338 }
339
340 // Don't do anything if a finger is going down or up. We run
341 // here before assigning pointer IDs, so there isn't a good
342 // way to do per-finger matching.
343 if (pointerCount != lastTouch.pointerCount) {
344 return false;
345 }
346
347 // We consider a single movement across more than a 7/16 of
348 // the long size of the screen to be bad. This was a magic value
349 // determined by looking at the maximum distance it is feasible
350 // to actually move in one sample.
351 int32_t maxDeltaY = parameters.yAxis.range * 7 / 16;
352
353 // XXX The original code in InputDevice.java included commented out
354 // code for testing the X axis. Note that when we drop a point
355 // we don't actually restore the old X either. Strange.
356 // The old code also tries to track when bad points were previously
357 // detected but it turns out that due to the placement of a "break"
358 // at the end of the loop, we never set mDroppedBadPoint to true
359 // so it is effectively dead code.
360 // Need to figure out if the old code is busted or just overcomplicated
361 // but working as intended.
362
363 // Look through all new points and see if any are farther than
364 // acceptable from all previous points.
365 for (uint32_t i = pointerCount; i-- > 0; ) {
366 int32_t y = currentTouch.pointers[i].y;
367 int32_t closestY = INT_MAX;
368 int32_t closestDeltaY = 0;
369
370#if DEBUG_HACKS
371 LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y);
372#endif
373
374 for (uint32_t j = pointerCount; j-- > 0; ) {
375 int32_t lastY = lastTouch.pointers[j].y;
376 int32_t deltaY = abs(y - lastY);
377
378#if DEBUG_HACKS
379 LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d",
380 j, lastY, deltaY);
381#endif
382
383 if (deltaY < maxDeltaY) {
384 goto SkipSufficientlyClosePoint;
385 }
386 if (deltaY < closestDeltaY) {
387 closestDeltaY = deltaY;
388 closestY = lastY;
389 }
390 }
391
392 // Must not have found a close enough match.
393#if DEBUG_HACKS
394 LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d",
395 i, y, closestY, closestDeltaY, maxDeltaY);
396#endif
397
398 currentTouch.pointers[i].y = closestY;
399 return true; // XXX original code only corrects one point
400
401 SkipSufficientlyClosePoint: ;
402 }
403
404 // No change.
405 return false;
406}
407
408/* Special hack for devices that have bad screen data: drop points where
409 * the coordinate value for one axis has jumped to the other pointer's location.
410 */
411bool InputDevice::TouchScreenState::applyJumpyTouchFilter() {
412 // This hack requires valid axis parameters.
413 if (! parameters.yAxis.valid) {
414 return false;
415 }
416
417 uint32_t pointerCount = currentTouch.pointerCount;
418 if (lastTouch.pointerCount != pointerCount) {
419#if DEBUG_HACKS
420 LOGD("JumpyTouchFilter: Different pointer count %d -> %d",
421 lastTouch.pointerCount, pointerCount);
422 for (uint32_t i = 0; i < pointerCount; i++) {
423 LOGD(" Pointer %d (%d, %d)", i,
424 currentTouch.pointers[i].x, currentTouch.pointers[i].y);
425 }
426#endif
427
428 if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
429 if (lastTouch.pointerCount == 1 && pointerCount == 2) {
430 // Just drop the first few events going from 1 to 2 pointers.
431 // They're bad often enough that they're not worth considering.
432 currentTouch.pointerCount = 1;
433 jumpyTouchFilter.jumpyPointsDropped += 1;
434
435#if DEBUG_HACKS
436 LOGD("JumpyTouchFilter: Pointer 2 dropped");
437#endif
438 return true;
439 } else if (lastTouch.pointerCount == 2 && pointerCount == 1) {
440 // The event when we go from 2 -> 1 tends to be messed up too
441 currentTouch.pointerCount = 2;
442 currentTouch.pointers[0] = lastTouch.pointers[0];
443 currentTouch.pointers[1] = lastTouch.pointers[1];
444 jumpyTouchFilter.jumpyPointsDropped += 1;
445
446#if DEBUG_HACKS
447 for (int32_t i = 0; i < 2; i++) {
448 LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i,
449 currentTouch.pointers[i].x, currentTouch.pointers[i].y);
450 }
451#endif
452 return true;
453 }
454 }
455 // Reset jumpy points dropped on other transitions or if limit exceeded.
456 jumpyTouchFilter.jumpyPointsDropped = 0;
457
458#if DEBUG_HACKS
459 LOGD("JumpyTouchFilter: Transition - drop limit reset");
460#endif
461 return false;
462 }
463
464 // We have the same number of pointers as last time.
465 // A 'jumpy' point is one where the coordinate value for one axis
466 // has jumped to the other pointer's location. No need to do anything
467 // else if we only have one pointer.
468 if (pointerCount < 2) {
469 return false;
470 }
471
472 if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
473 int jumpyEpsilon = parameters.yAxis.range / JUMPY_EPSILON_DIVISOR;
474
475 // We only replace the single worst jumpy point as characterized by pointer distance
476 // in a single axis.
477 int32_t badPointerIndex = -1;
478 int32_t badPointerReplacementIndex = -1;
479 int32_t badPointerDistance = INT_MIN; // distance to be corrected
480
481 for (uint32_t i = pointerCount; i-- > 0; ) {
482 int32_t x = currentTouch.pointers[i].x;
483 int32_t y = currentTouch.pointers[i].y;
484
485#if DEBUG_HACKS
486 LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y);
487#endif
488
489 // Check if a touch point is too close to another's coordinates
490 bool dropX = false, dropY = false;
491 for (uint32_t j = 0; j < pointerCount; j++) {
492 if (i == j) {
493 continue;
494 }
495
496 if (abs(x - currentTouch.pointers[j].x) <= jumpyEpsilon) {
497 dropX = true;
498 break;
499 }
500
501 if (abs(y - currentTouch.pointers[j].y) <= jumpyEpsilon) {
502 dropY = true;
503 break;
504 }
505 }
506 if (! dropX && ! dropY) {
507 continue; // not jumpy
508 }
509
510 // Find a replacement candidate by comparing with older points on the
511 // complementary (non-jumpy) axis.
512 int32_t distance = INT_MIN; // distance to be corrected
513 int32_t replacementIndex = -1;
514
515 if (dropX) {
516 // X looks too close. Find an older replacement point with a close Y.
517 int32_t smallestDeltaY = INT_MAX;
518 for (uint32_t j = 0; j < pointerCount; j++) {
519 int32_t deltaY = abs(y - lastTouch.pointers[j].y);
520 if (deltaY < smallestDeltaY) {
521 smallestDeltaY = deltaY;
522 replacementIndex = j;
523 }
524 }
525 distance = abs(x - lastTouch.pointers[replacementIndex].x);
526 } else {
527 // Y looks too close. Find an older replacement point with a close X.
528 int32_t smallestDeltaX = INT_MAX;
529 for (uint32_t j = 0; j < pointerCount; j++) {
530 int32_t deltaX = abs(x - lastTouch.pointers[j].x);
531 if (deltaX < smallestDeltaX) {
532 smallestDeltaX = deltaX;
533 replacementIndex = j;
534 }
535 }
536 distance = abs(y - lastTouch.pointers[replacementIndex].y);
537 }
538
539 // If replacing this pointer would correct a worse error than the previous ones
540 // considered, then use this replacement instead.
541 if (distance > badPointerDistance) {
542 badPointerIndex = i;
543 badPointerReplacementIndex = replacementIndex;
544 badPointerDistance = distance;
545 }
546 }
547
548 // Correct the jumpy pointer if one was found.
549 if (badPointerIndex >= 0) {
550#if DEBUG_HACKS
551 LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)",
552 badPointerIndex,
553 lastTouch.pointers[badPointerReplacementIndex].x,
554 lastTouch.pointers[badPointerReplacementIndex].y);
555#endif
556
557 currentTouch.pointers[badPointerIndex].x =
558 lastTouch.pointers[badPointerReplacementIndex].x;
559 currentTouch.pointers[badPointerIndex].y =
560 lastTouch.pointers[badPointerReplacementIndex].y;
561 jumpyTouchFilter.jumpyPointsDropped += 1;
562 return true;
563 }
564 }
565
566 jumpyTouchFilter.jumpyPointsDropped = 0;
567 return false;
568}
569
570/* Special hack for devices that have bad screen data: aggregate and
571 * compute averages of the coordinate data, to reduce the amount of
572 * jitter seen by applications. */
573void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
574 for (uint32_t currentIndex = 0; currentIndex < currentTouch.pointerCount; currentIndex++) {
575 uint32_t id = currentTouch.pointers[currentIndex].id;
576 int32_t x = currentTouch.pointers[currentIndex].x;
577 int32_t y = currentTouch.pointers[currentIndex].y;
578 int32_t pressure = currentTouch.pointers[currentIndex].pressure;
579
580 if (lastTouch.idBits.hasBit(id)) {
581 // Pointer was down before and is still down now.
582 // Compute average over history trace.
583 uint32_t start = averagingTouchFilter.historyStart[id];
584 uint32_t end = averagingTouchFilter.historyEnd[id];
585
586 int64_t deltaX = x - averagingTouchFilter.historyData[end].pointers[id].x;
587 int64_t deltaY = y - averagingTouchFilter.historyData[end].pointers[id].y;
588 uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
589
590#if DEBUG_HACKS
591 LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld",
592 id, distance);
593#endif
594
595 if (distance < AVERAGING_DISTANCE_LIMIT) {
596 // Increment end index in preparation for recording new historical data.
597 end += 1;
598 if (end > AVERAGING_HISTORY_SIZE) {
599 end = 0;
600 }
601
602 // If the end index has looped back to the start index then we have filled
603 // the historical trace up to the desired size so we drop the historical
604 // data at the start of the trace.
605 if (end == start) {
606 start += 1;
607 if (start > AVERAGING_HISTORY_SIZE) {
608 start = 0;
609 }
610 }
611
612 // Add the raw data to the historical trace.
613 averagingTouchFilter.historyStart[id] = start;
614 averagingTouchFilter.historyEnd[id] = end;
615 averagingTouchFilter.historyData[end].pointers[id].x = x;
616 averagingTouchFilter.historyData[end].pointers[id].y = y;
617 averagingTouchFilter.historyData[end].pointers[id].pressure = pressure;
618
619 // Average over all historical positions in the trace by total pressure.
620 int32_t averagedX = 0;
621 int32_t averagedY = 0;
622 int32_t totalPressure = 0;
623 for (;;) {
624 int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x;
625 int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].y;
626 int32_t historicalPressure = averagingTouchFilter.historyData[start]
627 .pointers[id].pressure;
628
629 averagedX += historicalX * historicalPressure;
630 averagedY += historicalY * historicalPressure;
631 totalPressure += historicalPressure;
632
633 if (start == end) {
634 break;
635 }
636
637 start += 1;
638 if (start > AVERAGING_HISTORY_SIZE) {
639 start = 0;
640 }
641 }
642
643 averagedX /= totalPressure;
644 averagedY /= totalPressure;
645
646#if DEBUG_HACKS
647 LOGD("AveragingTouchFilter: Pointer id %d - "
648 "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
649 averagedX, averagedY);
650#endif
651
652 currentTouch.pointers[currentIndex].x = averagedX;
653 currentTouch.pointers[currentIndex].y = averagedY;
654 } else {
655#if DEBUG_HACKS
656 LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
657#endif
658 }
659 } else {
660#if DEBUG_HACKS
661 LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id);
662#endif
663 }
664
665 // Reset pointer history.
666 averagingTouchFilter.historyStart[id] = 0;
667 averagingTouchFilter.historyEnd[id] = 0;
668 averagingTouchFilter.historyData[0].pointers[id].x = x;
669 averagingTouchFilter.historyData[0].pointers[id].y = y;
670 averagingTouchFilter.historyData[0].pointers[id].pressure = pressure;
671 }
672}
673
674bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const {
675 if (! parameters.xAxis.valid || ! parameters.yAxis.valid) {
676 // Assume all points on a touch screen without valid axis parameters are
677 // inside the display.
678 return true;
679 }
680
681 return x >= parameters.xAxis.minValue
682 && x <= parameters.xAxis.maxValue
683 && y >= parameters.yAxis.minValue
684 && y <= parameters.yAxis.maxValue;
685}
686
687const InputDevice::VirtualKey* InputDevice::TouchScreenState::findVirtualKeyHit() const {
688 int32_t x = currentTouch.pointers[0].x;
689 int32_t y = currentTouch.pointers[0].y;
690 for (size_t i = 0; i < virtualKeys.size(); i++) {
691 const InputDevice::VirtualKey& virtualKey = virtualKeys[i];
692
693#if DEBUG_VIRTUAL_KEYS
694 LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
695 "left=%d, top=%d, right=%d, bottom=%d",
696 x, y,
697 virtualKey.keyCode, virtualKey.scanCode,
698 virtualKey.hitLeft, virtualKey.hitTop,
699 virtualKey.hitRight, virtualKey.hitBottom);
700#endif
701
702 if (virtualKey.isHit(x, y)) {
703 return & virtualKey;
704 }
705 }
706
707 return NULL;
708}
709
710
711// --- InputDevice::SingleTouchScreenState ---
712
713void InputDevice::SingleTouchScreenState::reset() {
714 accumulator.clear();
715 current.down = false;
716 current.x = 0;
717 current.y = 0;
718 current.pressure = 0;
719 current.size = 0;
720}
721
722
723// --- InputDevice::MultiTouchScreenState ---
724
725void InputDevice::MultiTouchScreenState::reset() {
726 accumulator.clear();
727}
728
729} // namespace android