blob: 5a280aed37a7f70dc93381f4ce909f8a89538061 [file] [log] [blame]
Jeff Brown46b9ac02010-04-22 18:58:52 -07001//
2// Copyright 2010 The Android Open Source Project
3//
4// The input reader.
5//
6#define LOG_TAG "InputReader"
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 1
15
16// Log debug messages about virtual key processing.
17#define DEBUG_VIRTUAL_KEYS 1
18
19// Log debug messages about pointers.
20#define DEBUG_POINTERS 1
21
Jeff Brown5c225b12010-06-16 01:53:36 -070022// Log debug messages about pointer assignment calculations.
23#define DEBUG_POINTER_ASSIGNMENT 0
24
Jeff Brown46b9ac02010-04-22 18:58:52 -070025#include <cutils/log.h>
26#include <ui/InputReader.h>
27
28#include <stddef.h>
29#include <unistd.h>
Jeff Brown46b9ac02010-04-22 18:58:52 -070030#include <errno.h>
31#include <limits.h>
32
Jeff Brown9c3cda02010-06-15 01:31:58 -070033/** Amount that trackball needs to move in order to generate a key event. */
34#define TRACKBALL_MOVEMENT_THRESHOLD 6
35
36/* Slop distance for jumpy pointer detection.
37 * The vertical range of the screen divided by this is our epsilon value. */
38#define JUMPY_EPSILON_DIVISOR 212
39
40/* Number of jumpy points to drop for touchscreens that need it. */
41#define JUMPY_TRANSITION_DROPS 3
42#define JUMPY_DROP_LIMIT 3
43
44/* Maximum squared distance for averaging.
45 * If moving farther than this, turn of averaging to avoid lag in response. */
46#define AVERAGING_DISTANCE_LIMIT (75 * 75)
47
48
Jeff Brown46b9ac02010-04-22 18:58:52 -070049namespace android {
50
51// --- Static Functions ---
52
53template<typename T>
54inline static T abs(const T& value) {
55 return value < 0 ? - value : value;
56}
57
58template<typename T>
59inline static T min(const T& a, const T& b) {
60 return a < b ? a : b;
61}
62
Jeff Brown5c225b12010-06-16 01:53:36 -070063template<typename T>
64inline static void swap(T& a, T& b) {
65 T temp = a;
66 a = b;
67 b = temp;
68}
69
70
Jeff Brown46b9ac02010-04-22 18:58:52 -070071int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
72 int32_t mask;
73 switch (keyCode) {
74 case KEYCODE_ALT_LEFT:
75 mask = META_ALT_LEFT_ON;
76 break;
77 case KEYCODE_ALT_RIGHT:
78 mask = META_ALT_RIGHT_ON;
79 break;
80 case KEYCODE_SHIFT_LEFT:
81 mask = META_SHIFT_LEFT_ON;
82 break;
83 case KEYCODE_SHIFT_RIGHT:
84 mask = META_SHIFT_RIGHT_ON;
85 break;
86 case KEYCODE_SYM:
87 mask = META_SYM_ON;
88 break;
89 default:
90 return oldMetaState;
91 }
92
93 int32_t newMetaState = down ? oldMetaState | mask : oldMetaState & ~ mask
94 & ~ (META_ALT_ON | META_SHIFT_ON);
95
96 if (newMetaState & (META_ALT_LEFT_ON | META_ALT_RIGHT_ON)) {
97 newMetaState |= META_ALT_ON;
98 }
99
100 if (newMetaState & (META_SHIFT_LEFT_ON | META_SHIFT_RIGHT_ON)) {
101 newMetaState |= META_SHIFT_ON;
102 }
103
104 return newMetaState;
105}
106
107static const int32_t keyCodeRotationMap[][4] = {
108 // key codes enumerated counter-clockwise with the original (unrotated) key first
109 // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
110 { KEYCODE_DPAD_DOWN, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_UP, KEYCODE_DPAD_LEFT },
111 { KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_UP, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_DOWN },
112 { KEYCODE_DPAD_UP, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_RIGHT },
113 { KEYCODE_DPAD_LEFT, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_UP },
114};
115static const int keyCodeRotationMapSize =
116 sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
117
118int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
Jeff Brown9c3cda02010-06-15 01:31:58 -0700119 if (orientation != InputReaderPolicyInterface::ROTATION_0) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700120 for (int i = 0; i < keyCodeRotationMapSize; i++) {
121 if (keyCode == keyCodeRotationMap[i][0]) {
122 return keyCodeRotationMap[i][orientation];
123 }
124 }
125 }
126 return keyCode;
127}
128
129
130// --- InputDevice ---
131
132InputDevice::InputDevice(int32_t id, uint32_t classes, String8 name) :
133 id(id), classes(classes), name(name), ignored(false) {
134}
135
136void InputDevice::reset() {
137 if (isKeyboard()) {
138 keyboard.reset();
139 }
140
141 if (isTrackball()) {
142 trackball.reset();
143 }
144
145 if (isMultiTouchScreen()) {
146 multiTouchScreen.reset();
147 } else if (isSingleTouchScreen()) {
148 singleTouchScreen.reset();
149 }
150
151 if (isTouchScreen()) {
152 touchScreen.reset();
153 }
154}
155
156
157// --- InputDevice::TouchData ---
158
159void InputDevice::TouchData::copyFrom(const TouchData& other) {
160 pointerCount = other.pointerCount;
161 idBits = other.idBits;
162
163 for (uint32_t i = 0; i < pointerCount; i++) {
164 pointers[i] = other.pointers[i];
165 idToIndex[i] = other.idToIndex[i];
166 }
167}
168
169
170// --- InputDevice::KeyboardState ---
171
172void InputDevice::KeyboardState::reset() {
173 current.metaState = META_NONE;
174 current.downTime = 0;
175}
176
177
178// --- InputDevice::TrackballState ---
179
180void InputDevice::TrackballState::reset() {
181 accumulator.clear();
182 current.down = false;
183 current.downTime = 0;
184}
185
186
187// --- InputDevice::TouchScreenState ---
188
189void InputDevice::TouchScreenState::reset() {
190 lastTouch.clear();
191 downTime = 0;
192 currentVirtualKey.down = false;
193
194 for (uint32_t i = 0; i < MAX_POINTERS; i++) {
195 averagingTouchFilter.historyStart[i] = 0;
196 averagingTouchFilter.historyEnd[i] = 0;
197 }
198
199 jumpyTouchFilter.jumpyPointsDropped = 0;
200}
201
Jeff Brown5c225b12010-06-16 01:53:36 -0700202struct PointerDistanceHeapElement {
203 uint32_t currentPointerIndex : 8;
204 uint32_t lastPointerIndex : 8;
205 uint64_t distance : 48; // squared distance
206};
207
Jeff Brown46b9ac02010-04-22 18:58:52 -0700208void InputDevice::TouchScreenState::calculatePointerIds() {
209 uint32_t currentPointerCount = currentTouch.pointerCount;
210 uint32_t lastPointerCount = lastTouch.pointerCount;
211
212 if (currentPointerCount == 0) {
213 // No pointers to assign.
214 currentTouch.idBits.clear();
215 } else if (lastPointerCount == 0) {
216 // All pointers are new.
217 currentTouch.idBits.clear();
218 for (uint32_t i = 0; i < currentPointerCount; i++) {
219 currentTouch.pointers[i].id = i;
220 currentTouch.idToIndex[i] = i;
221 currentTouch.idBits.markBit(i);
222 }
223 } else if (currentPointerCount == 1 && lastPointerCount == 1) {
224 // Only one pointer and no change in count so it must have the same id as before.
225 uint32_t id = lastTouch.pointers[0].id;
226 currentTouch.pointers[0].id = id;
227 currentTouch.idToIndex[id] = 0;
228 currentTouch.idBits.value = BitSet32::valueForBit(id);
229 } else {
230 // General case.
231 // We build a heap of squared euclidean distances between current and last pointers
232 // associated with the current and last pointer indices. Then, we find the best
233 // match (by distance) for each current pointer.
Jeff Brown5c225b12010-06-16 01:53:36 -0700234 PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
Jeff Brown46b9ac02010-04-22 18:58:52 -0700235
236 uint32_t heapSize = 0;
237 for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
238 currentPointerIndex++) {
239 for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
240 lastPointerIndex++) {
241 int64_t deltaX = currentTouch.pointers[currentPointerIndex].x
242 - lastTouch.pointers[lastPointerIndex].x;
243 int64_t deltaY = currentTouch.pointers[currentPointerIndex].y
244 - lastTouch.pointers[lastPointerIndex].y;
245
246 uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
247
248 // Insert new element into the heap (sift up).
Jeff Brown5c225b12010-06-16 01:53:36 -0700249 heap[heapSize].currentPointerIndex = currentPointerIndex;
250 heap[heapSize].lastPointerIndex = lastPointerIndex;
251 heap[heapSize].distance = distance;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700252 heapSize += 1;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700253 }
254 }
255
Jeff Brown5c225b12010-06-16 01:53:36 -0700256 // Heapify
257 for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
258 startIndex -= 1;
259 for (uint32_t parentIndex = startIndex; ;) {
260 uint32_t childIndex = parentIndex * 2 + 1;
261 if (childIndex >= heapSize) {
262 break;
263 }
264
265 if (childIndex + 1 < heapSize
266 && heap[childIndex + 1].distance < heap[childIndex].distance) {
267 childIndex += 1;
268 }
269
270 if (heap[parentIndex].distance <= heap[childIndex].distance) {
271 break;
272 }
273
274 swap(heap[parentIndex], heap[childIndex]);
275 parentIndex = childIndex;
276 }
277 }
278
279#if DEBUG_POINTER_ASSIGNMENT
280 LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
281 for (size_t i = 0; i < heapSize; i++) {
282 LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
283 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
284 heap[i].distance);
285 }
286#endif
287
Jeff Brown46b9ac02010-04-22 18:58:52 -0700288 // Pull matches out by increasing order of distance.
289 // To avoid reassigning pointers that have already been matched, the loop keeps track
290 // of which last and current pointers have been matched using the matchedXXXBits variables.
291 // It also tracks the used pointer id bits.
292 BitSet32 matchedLastBits(0);
293 BitSet32 matchedCurrentBits(0);
294 BitSet32 usedIdBits(0);
295 bool first = true;
296 for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) {
297 for (;;) {
298 if (first) {
299 // The first time through the loop, we just consume the root element of
Jeff Brown5c225b12010-06-16 01:53:36 -0700300 // the heap (the one with smallest distance).
Jeff Brown46b9ac02010-04-22 18:58:52 -0700301 first = false;
302 } else {
303 // Previous iterations consumed the root element of the heap.
304 // Pop root element off of the heap (sift down).
305 heapSize -= 1;
306 assert(heapSize > 0);
307
Jeff Brown5c225b12010-06-16 01:53:36 -0700308 // Sift down.
309 heap[0] = heap[heapSize];
310 for (uint32_t parentIndex = 0; ;) {
311 uint32_t childIndex = parentIndex * 2 + 1;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700312 if (childIndex >= heapSize) {
313 break;
314 }
315
316 if (childIndex + 1 < heapSize
317 && heap[childIndex + 1].distance < heap[childIndex].distance) {
318 childIndex += 1;
319 }
320
Jeff Brown5c225b12010-06-16 01:53:36 -0700321 if (heap[parentIndex].distance <= heap[childIndex].distance) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700322 break;
323 }
324
Jeff Brown5c225b12010-06-16 01:53:36 -0700325 swap(heap[parentIndex], heap[childIndex]);
326 parentIndex = childIndex;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700327 }
Jeff Brown5c225b12010-06-16 01:53:36 -0700328
329#if DEBUG_POINTER_ASSIGNMENT
330 LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
331 for (size_t i = 0; i < heapSize; i++) {
332 LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
333 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
334 heap[i].distance);
335 }
336#endif
Jeff Brown46b9ac02010-04-22 18:58:52 -0700337 }
338
339 uint32_t currentPointerIndex = heap[0].currentPointerIndex;
340 if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
341
342 uint32_t lastPointerIndex = heap[0].lastPointerIndex;
343 if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
344
345 matchedCurrentBits.markBit(currentPointerIndex);
346 matchedLastBits.markBit(lastPointerIndex);
347
348 uint32_t id = lastTouch.pointers[lastPointerIndex].id;
349 currentTouch.pointers[currentPointerIndex].id = id;
350 currentTouch.idToIndex[id] = currentPointerIndex;
351 usedIdBits.markBit(id);
Jeff Brown5c225b12010-06-16 01:53:36 -0700352
353#if DEBUG_POINTER_ASSIGNMENT
354 LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
355 lastPointerIndex, currentPointerIndex, id, heap[0].distance);
356#endif
Jeff Brown46b9ac02010-04-22 18:58:52 -0700357 break;
358 }
359 }
360
361 // Assign fresh ids to new pointers.
362 if (currentPointerCount > lastPointerCount) {
363 for (uint32_t i = currentPointerCount - lastPointerCount; ;) {
364 uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit();
365 uint32_t id = usedIdBits.firstUnmarkedBit();
366
367 currentTouch.pointers[currentPointerIndex].id = id;
368 currentTouch.idToIndex[id] = currentPointerIndex;
369 usedIdBits.markBit(id);
370
Jeff Brown5c225b12010-06-16 01:53:36 -0700371#if DEBUG_POINTER_ASSIGNMENT
372 LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
373 currentPointerIndex, id);
374#endif
375
Jeff Brown46b9ac02010-04-22 18:58:52 -0700376 if (--i == 0) break; // done
377 matchedCurrentBits.markBit(currentPointerIndex);
378 }
379 }
380
381 // Fix id bits.
382 currentTouch.idBits = usedIdBits;
383 }
384}
385
386/* Special hack for devices that have bad screen data: if one of the
387 * points has moved more than a screen height from the last position,
388 * then drop it. */
389bool InputDevice::TouchScreenState::applyBadTouchFilter() {
390 uint32_t pointerCount = currentTouch.pointerCount;
391
392 // Nothing to do if there are no points.
393 if (pointerCount == 0) {
394 return false;
395 }
396
397 // Don't do anything if a finger is going down or up. We run
398 // here before assigning pointer IDs, so there isn't a good
399 // way to do per-finger matching.
400 if (pointerCount != lastTouch.pointerCount) {
401 return false;
402 }
403
404 // We consider a single movement across more than a 7/16 of
405 // the long size of the screen to be bad. This was a magic value
406 // determined by looking at the maximum distance it is feasible
407 // to actually move in one sample.
408 int32_t maxDeltaY = parameters.yAxis.range * 7 / 16;
409
410 // XXX The original code in InputDevice.java included commented out
411 // code for testing the X axis. Note that when we drop a point
412 // we don't actually restore the old X either. Strange.
413 // The old code also tries to track when bad points were previously
414 // detected but it turns out that due to the placement of a "break"
415 // at the end of the loop, we never set mDroppedBadPoint to true
416 // so it is effectively dead code.
417 // Need to figure out if the old code is busted or just overcomplicated
418 // but working as intended.
419
420 // Look through all new points and see if any are farther than
421 // acceptable from all previous points.
422 for (uint32_t i = pointerCount; i-- > 0; ) {
423 int32_t y = currentTouch.pointers[i].y;
424 int32_t closestY = INT_MAX;
425 int32_t closestDeltaY = 0;
426
427#if DEBUG_HACKS
428 LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y);
429#endif
430
431 for (uint32_t j = pointerCount; j-- > 0; ) {
432 int32_t lastY = lastTouch.pointers[j].y;
433 int32_t deltaY = abs(y - lastY);
434
435#if DEBUG_HACKS
436 LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d",
437 j, lastY, deltaY);
438#endif
439
440 if (deltaY < maxDeltaY) {
441 goto SkipSufficientlyClosePoint;
442 }
443 if (deltaY < closestDeltaY) {
444 closestDeltaY = deltaY;
445 closestY = lastY;
446 }
447 }
448
449 // Must not have found a close enough match.
450#if DEBUG_HACKS
451 LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d",
452 i, y, closestY, closestDeltaY, maxDeltaY);
453#endif
454
455 currentTouch.pointers[i].y = closestY;
456 return true; // XXX original code only corrects one point
457
458 SkipSufficientlyClosePoint: ;
459 }
460
461 // No change.
462 return false;
463}
464
465/* Special hack for devices that have bad screen data: drop points where
466 * the coordinate value for one axis has jumped to the other pointer's location.
467 */
468bool InputDevice::TouchScreenState::applyJumpyTouchFilter() {
469 uint32_t pointerCount = currentTouch.pointerCount;
470 if (lastTouch.pointerCount != pointerCount) {
471#if DEBUG_HACKS
472 LOGD("JumpyTouchFilter: Different pointer count %d -> %d",
473 lastTouch.pointerCount, pointerCount);
474 for (uint32_t i = 0; i < pointerCount; i++) {
475 LOGD(" Pointer %d (%d, %d)", i,
476 currentTouch.pointers[i].x, currentTouch.pointers[i].y);
477 }
478#endif
479
480 if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
481 if (lastTouch.pointerCount == 1 && pointerCount == 2) {
482 // Just drop the first few events going from 1 to 2 pointers.
483 // They're bad often enough that they're not worth considering.
484 currentTouch.pointerCount = 1;
485 jumpyTouchFilter.jumpyPointsDropped += 1;
486
487#if DEBUG_HACKS
488 LOGD("JumpyTouchFilter: Pointer 2 dropped");
489#endif
490 return true;
491 } else if (lastTouch.pointerCount == 2 && pointerCount == 1) {
492 // The event when we go from 2 -> 1 tends to be messed up too
493 currentTouch.pointerCount = 2;
494 currentTouch.pointers[0] = lastTouch.pointers[0];
495 currentTouch.pointers[1] = lastTouch.pointers[1];
496 jumpyTouchFilter.jumpyPointsDropped += 1;
497
498#if DEBUG_HACKS
499 for (int32_t i = 0; i < 2; i++) {
500 LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i,
501 currentTouch.pointers[i].x, currentTouch.pointers[i].y);
502 }
503#endif
504 return true;
505 }
506 }
507 // Reset jumpy points dropped on other transitions or if limit exceeded.
508 jumpyTouchFilter.jumpyPointsDropped = 0;
509
510#if DEBUG_HACKS
511 LOGD("JumpyTouchFilter: Transition - drop limit reset");
512#endif
513 return false;
514 }
515
516 // We have the same number of pointers as last time.
517 // A 'jumpy' point is one where the coordinate value for one axis
518 // has jumped to the other pointer's location. No need to do anything
519 // else if we only have one pointer.
520 if (pointerCount < 2) {
521 return false;
522 }
523
524 if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
525 int jumpyEpsilon = parameters.yAxis.range / JUMPY_EPSILON_DIVISOR;
526
527 // We only replace the single worst jumpy point as characterized by pointer distance
528 // in a single axis.
529 int32_t badPointerIndex = -1;
530 int32_t badPointerReplacementIndex = -1;
531 int32_t badPointerDistance = INT_MIN; // distance to be corrected
532
533 for (uint32_t i = pointerCount; i-- > 0; ) {
534 int32_t x = currentTouch.pointers[i].x;
535 int32_t y = currentTouch.pointers[i].y;
536
537#if DEBUG_HACKS
538 LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y);
539#endif
540
541 // Check if a touch point is too close to another's coordinates
542 bool dropX = false, dropY = false;
543 for (uint32_t j = 0; j < pointerCount; j++) {
544 if (i == j) {
545 continue;
546 }
547
548 if (abs(x - currentTouch.pointers[j].x) <= jumpyEpsilon) {
549 dropX = true;
550 break;
551 }
552
553 if (abs(y - currentTouch.pointers[j].y) <= jumpyEpsilon) {
554 dropY = true;
555 break;
556 }
557 }
558 if (! dropX && ! dropY) {
559 continue; // not jumpy
560 }
561
562 // Find a replacement candidate by comparing with older points on the
563 // complementary (non-jumpy) axis.
564 int32_t distance = INT_MIN; // distance to be corrected
565 int32_t replacementIndex = -1;
566
567 if (dropX) {
568 // X looks too close. Find an older replacement point with a close Y.
569 int32_t smallestDeltaY = INT_MAX;
570 for (uint32_t j = 0; j < pointerCount; j++) {
571 int32_t deltaY = abs(y - lastTouch.pointers[j].y);
572 if (deltaY < smallestDeltaY) {
573 smallestDeltaY = deltaY;
574 replacementIndex = j;
575 }
576 }
577 distance = abs(x - lastTouch.pointers[replacementIndex].x);
578 } else {
579 // Y looks too close. Find an older replacement point with a close X.
580 int32_t smallestDeltaX = INT_MAX;
581 for (uint32_t j = 0; j < pointerCount; j++) {
582 int32_t deltaX = abs(x - lastTouch.pointers[j].x);
583 if (deltaX < smallestDeltaX) {
584 smallestDeltaX = deltaX;
585 replacementIndex = j;
586 }
587 }
588 distance = abs(y - lastTouch.pointers[replacementIndex].y);
589 }
590
591 // If replacing this pointer would correct a worse error than the previous ones
592 // considered, then use this replacement instead.
593 if (distance > badPointerDistance) {
594 badPointerIndex = i;
595 badPointerReplacementIndex = replacementIndex;
596 badPointerDistance = distance;
597 }
598 }
599
600 // Correct the jumpy pointer if one was found.
601 if (badPointerIndex >= 0) {
602#if DEBUG_HACKS
603 LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)",
604 badPointerIndex,
605 lastTouch.pointers[badPointerReplacementIndex].x,
606 lastTouch.pointers[badPointerReplacementIndex].y);
607#endif
608
609 currentTouch.pointers[badPointerIndex].x =
610 lastTouch.pointers[badPointerReplacementIndex].x;
611 currentTouch.pointers[badPointerIndex].y =
612 lastTouch.pointers[badPointerReplacementIndex].y;
613 jumpyTouchFilter.jumpyPointsDropped += 1;
614 return true;
615 }
616 }
617
618 jumpyTouchFilter.jumpyPointsDropped = 0;
619 return false;
620}
621
622/* Special hack for devices that have bad screen data: aggregate and
623 * compute averages of the coordinate data, to reduce the amount of
624 * jitter seen by applications. */
625void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
626 for (uint32_t currentIndex = 0; currentIndex < currentTouch.pointerCount; currentIndex++) {
627 uint32_t id = currentTouch.pointers[currentIndex].id;
628 int32_t x = currentTouch.pointers[currentIndex].x;
629 int32_t y = currentTouch.pointers[currentIndex].y;
630 int32_t pressure = currentTouch.pointers[currentIndex].pressure;
631
632 if (lastTouch.idBits.hasBit(id)) {
633 // Pointer still down compute average.
634 uint32_t start = averagingTouchFilter.historyStart[id];
635 uint32_t end = averagingTouchFilter.historyEnd[id];
636
637 int64_t deltaX = x - averagingTouchFilter.historyData[end].pointers[id].x;
638 int64_t deltaY = y - averagingTouchFilter.historyData[end].pointers[id].y;
639 uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
640
641#if DEBUG_HACKS
642 LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld",
643 id, distance);
644#endif
645
646 if (distance < AVERAGING_DISTANCE_LIMIT) {
647 end += 1;
648 if (end > AVERAGING_HISTORY_SIZE) {
649 end = 0;
650 }
651
652 if (end == start) {
653 start += 1;
654 if (start > AVERAGING_HISTORY_SIZE) {
655 start = 0;
656 }
657 }
658
659 averagingTouchFilter.historyStart[id] = start;
660 averagingTouchFilter.historyEnd[id] = end;
661 averagingTouchFilter.historyData[end].pointers[id].x = x;
662 averagingTouchFilter.historyData[end].pointers[id].y = y;
663 averagingTouchFilter.historyData[end].pointers[id].pressure = pressure;
664
665 int32_t averagedX = 0;
666 int32_t averagedY = 0;
667 int32_t totalPressure = 0;
668 for (;;) {
669 int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x;
670 int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].x;
671 int32_t historicalPressure = averagingTouchFilter.historyData[start]
672 .pointers[id].pressure;
673
674 averagedX += historicalX;
675 averagedY += historicalY;
676 totalPressure += historicalPressure;
677
678 if (start == end) {
679 break;
680 }
681
682 start += 1;
683 if (start > AVERAGING_HISTORY_SIZE) {
684 start = 0;
685 }
686 }
687
688 averagedX /= totalPressure;
689 averagedY /= totalPressure;
690
691#if DEBUG_HACKS
692 LOGD("AveragingTouchFilter: Pointer id %d - "
693 "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
694 averagedX, averagedY);
695#endif
696
697 currentTouch.pointers[currentIndex].x = averagedX;
698 currentTouch.pointers[currentIndex].y = averagedY;
699 } else {
700#if DEBUG_HACKS
701 LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
702#endif
703 }
704 } else {
705#if DEBUG_HACKS
706 LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id);
707#endif
708 }
709
710 // Reset pointer history.
711 averagingTouchFilter.historyStart[id] = 0;
712 averagingTouchFilter.historyEnd[id] = 0;
713 averagingTouchFilter.historyData[0].pointers[id].x = x;
714 averagingTouchFilter.historyData[0].pointers[id].y = y;
715 averagingTouchFilter.historyData[0].pointers[id].pressure = pressure;
716 }
717}
718
719bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const {
720 return x >= parameters.xAxis.minValue
721 && x <= parameters.xAxis.maxValue
722 && y >= parameters.yAxis.minValue
723 && y <= parameters.yAxis.maxValue;
724}
725
726
727// --- InputDevice::SingleTouchScreenState ---
728
729void InputDevice::SingleTouchScreenState::reset() {
730 accumulator.clear();
731 current.down = false;
732 current.x = 0;
733 current.y = 0;
734 current.pressure = 0;
735 current.size = 0;
736}
737
738
739// --- InputDevice::MultiTouchScreenState ---
740
741void InputDevice::MultiTouchScreenState::reset() {
742 accumulator.clear();
743}
744
745
746// --- InputReader ---
747
748InputReader::InputReader(const sp<EventHubInterface>& eventHub,
Jeff Brown9c3cda02010-06-15 01:31:58 -0700749 const sp<InputReaderPolicyInterface>& policy,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700750 const sp<InputDispatcherInterface>& dispatcher) :
751 mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher) {
Jeff Brown9c3cda02010-06-15 01:31:58 -0700752 configureExcludedDevices();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700753 resetGlobalMetaState();
754 resetDisplayProperties();
Jeff Brown9c3cda02010-06-15 01:31:58 -0700755 updateExportedVirtualKeyState();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700756}
757
758InputReader::~InputReader() {
759 for (size_t i = 0; i < mDevices.size(); i++) {
760 delete mDevices.valueAt(i);
761 }
762}
763
764void InputReader::loopOnce() {
765 RawEvent rawEvent;
766 mEventHub->getEvent(& rawEvent.deviceId, & rawEvent.type, & rawEvent.scanCode,
767 & rawEvent.keyCode, & rawEvent.flags, & rawEvent.value, & rawEvent.when);
768
769 // Replace the event timestamp so it is in same timebase as java.lang.System.nanoTime()
770 // and android.os.SystemClock.uptimeMillis() as expected by the rest of the system.
771 rawEvent.when = systemTime(SYSTEM_TIME_MONOTONIC);
772
773#if DEBUG_RAW_EVENTS
774 LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",
775 rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
776 rawEvent.value);
777#endif
778
779 process(& rawEvent);
780}
781
782void InputReader::process(const RawEvent* rawEvent) {
783 switch (rawEvent->type) {
784 case EventHubInterface::DEVICE_ADDED:
785 handleDeviceAdded(rawEvent);
786 break;
787
788 case EventHubInterface::DEVICE_REMOVED:
789 handleDeviceRemoved(rawEvent);
790 break;
791
792 case EV_SYN:
793 handleSync(rawEvent);
794 break;
795
796 case EV_KEY:
797 handleKey(rawEvent);
798 break;
799
800 case EV_REL:
801 handleRelativeMotion(rawEvent);
802 break;
803
804 case EV_ABS:
805 handleAbsoluteMotion(rawEvent);
806 break;
807
808 case EV_SW:
809 handleSwitch(rawEvent);
810 break;
811 }
812}
813
814void InputReader::handleDeviceAdded(const RawEvent* rawEvent) {
815 InputDevice* device = getDevice(rawEvent->deviceId);
816 if (device) {
817 LOGW("Ignoring spurious device added event for deviceId %d.", rawEvent->deviceId);
818 return;
819 }
820
821 addDevice(rawEvent->when, rawEvent->deviceId);
822}
823
824void InputReader::handleDeviceRemoved(const RawEvent* rawEvent) {
825 InputDevice* device = getDevice(rawEvent->deviceId);
826 if (! device) {
827 LOGW("Ignoring spurious device removed event for deviceId %d.", rawEvent->deviceId);
828 return;
829 }
830
831 removeDevice(rawEvent->when, device);
832}
833
834void InputReader::handleSync(const RawEvent* rawEvent) {
835 InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
836 if (! device) return;
837
838 if (rawEvent->scanCode == SYN_MT_REPORT) {
839 // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
840 // We drop pointers with pressure <= 0 since that indicates they are not down.
841 if (device->isMultiTouchScreen()) {
842 uint32_t pointerIndex = device->multiTouchScreen.accumulator.pointerCount;
843
844 if (device->multiTouchScreen.accumulator.pointers[pointerIndex].fields) {
845 if (pointerIndex == MAX_POINTERS) {
846 LOGW("MultiTouch device driver returned more than maximum of %d pointers.",
847 MAX_POINTERS);
848 } else {
849 pointerIndex += 1;
850 device->multiTouchScreen.accumulator.pointerCount = pointerIndex;
851 }
852 }
853
854 device->multiTouchScreen.accumulator.pointers[pointerIndex].clear();
855 }
856 } else if (rawEvent->scanCode == SYN_REPORT) {
857 // General Sync: The driver has returned all data for the current event update.
858 if (device->isMultiTouchScreen()) {
859 if (device->multiTouchScreen.accumulator.isDirty()) {
860 onMultiTouchScreenStateChanged(rawEvent->when, device);
861 device->multiTouchScreen.accumulator.clear();
862 }
863 } else if (device->isSingleTouchScreen()) {
864 if (device->singleTouchScreen.accumulator.isDirty()) {
865 onSingleTouchScreenStateChanged(rawEvent->when, device);
866 device->singleTouchScreen.accumulator.clear();
867 }
868 }
869
870 if (device->trackball.accumulator.isDirty()) {
871 onTrackballStateChanged(rawEvent->when, device);
872 device->trackball.accumulator.clear();
873 }
874 }
875}
876
877void InputReader::handleKey(const RawEvent* rawEvent) {
878 InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
879 if (! device) return;
880
881 bool down = rawEvent->value != 0;
882 int32_t scanCode = rawEvent->scanCode;
883
884 if (device->isKeyboard() && (scanCode < BTN_FIRST || scanCode > BTN_LAST)) {
885 int32_t keyCode = rawEvent->keyCode;
886 onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags);
887 } else if (device->isSingleTouchScreen()) {
888 switch (rawEvent->scanCode) {
889 case BTN_TOUCH:
890 device->singleTouchScreen.accumulator.fields |=
891 InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH;
892 device->singleTouchScreen.accumulator.btnTouch = down;
893 break;
894 }
895 } else if (device->isTrackball()) {
896 switch (rawEvent->scanCode) {
897 case BTN_MOUSE:
898 device->trackball.accumulator.fields |=
899 InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
900 device->trackball.accumulator.btnMouse = down;
901
902 // send the down immediately
903 // XXX this emulates the old behavior of KeyInputQueue, unclear whether it is
904 // necessary or if we can wait until the next sync
905 onTrackballStateChanged(rawEvent->when, device);
906 device->trackball.accumulator.clear();
907 break;
908 }
909 }
910}
911
912void InputReader::handleRelativeMotion(const RawEvent* rawEvent) {
913 InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
914 if (! device) return;
915
916 if (device->isTrackball()) {
917 switch (rawEvent->scanCode) {
918 case REL_X:
919 device->trackball.accumulator.fields |=
920 InputDevice::TrackballState::Accumulator::FIELD_REL_X;
921 device->trackball.accumulator.relX = rawEvent->value;
922 break;
923 case REL_Y:
924 device->trackball.accumulator.fields |=
925 InputDevice::TrackballState::Accumulator::FIELD_REL_Y;
926 device->trackball.accumulator.relY = rawEvent->value;
927 break;
928 }
929 }
930}
931
932void InputReader::handleAbsoluteMotion(const RawEvent* rawEvent) {
933 InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
934 if (! device) return;
935
936 if (device->isMultiTouchScreen()) {
937 uint32_t pointerIndex = device->multiTouchScreen.accumulator.pointerCount;
938 InputDevice::MultiTouchScreenState::Accumulator::Pointer* pointer =
939 & device->multiTouchScreen.accumulator.pointers[pointerIndex];
940
941 switch (rawEvent->scanCode) {
942 case ABS_MT_POSITION_X:
943 pointer->fields |=
944 InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_X;
945 pointer->absMTPositionX = rawEvent->value;
946 break;
947 case ABS_MT_POSITION_Y:
948 pointer->fields |=
949 InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_Y;
950 pointer->absMTPositionY = rawEvent->value;
951 break;
952 case ABS_MT_TOUCH_MAJOR:
953 pointer->fields |=
954 InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
955 pointer->absMTTouchMajor = rawEvent->value;
956 break;
957 case ABS_MT_WIDTH_MAJOR:
958 pointer->fields |=
959 InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
960 pointer->absMTWidthMajor = rawEvent->value;
961 break;
962 case ABS_MT_TRACKING_ID:
963 pointer->fields |=
964 InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TRACKING_ID;
965 pointer->absMTTrackingId = rawEvent->value;
966 break;
967 }
968 } else if (device->isSingleTouchScreen()) {
969 switch (rawEvent->scanCode) {
970 case ABS_X:
971 device->singleTouchScreen.accumulator.fields |=
972 InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_X;
973 device->singleTouchScreen.accumulator.absX = rawEvent->value;
974 break;
975 case ABS_Y:
976 device->singleTouchScreen.accumulator.fields |=
977 InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_Y;
978 device->singleTouchScreen.accumulator.absY = rawEvent->value;
979 break;
980 case ABS_PRESSURE:
981 device->singleTouchScreen.accumulator.fields |=
982 InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_PRESSURE;
983 device->singleTouchScreen.accumulator.absPressure = rawEvent->value;
984 break;
985 case ABS_TOOL_WIDTH:
986 device->singleTouchScreen.accumulator.fields |=
987 InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_TOOL_WIDTH;
988 device->singleTouchScreen.accumulator.absToolWidth = rawEvent->value;
989 break;
990 }
991 }
992}
993
994void InputReader::handleSwitch(const RawEvent* rawEvent) {
995 InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
996 if (! device) return;
997
Jeff Brown9c3cda02010-06-15 01:31:58 -0700998 onSwitch(rawEvent->when, device, rawEvent->scanCode, rawEvent->value);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700999}
1000
1001void InputReader::onKey(nsecs_t when, InputDevice* device,
1002 bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) {
1003 /* Refresh display properties so we can rotate key codes according to display orientation */
1004
1005 if (! refreshDisplayProperties()) {
1006 return;
1007 }
1008
1009 /* Update device state */
1010
1011 int32_t oldMetaState = device->keyboard.current.metaState;
1012 int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
1013 if (oldMetaState != newMetaState) {
1014 device->keyboard.current.metaState = newMetaState;
1015 resetGlobalMetaState();
1016 }
1017
1018 // FIXME if we send a down event about a rotated key press we should ensure that we send
1019 // a corresponding up event about the rotated key press even if the orientation
1020 // has changed in the meantime
1021 keyCode = rotateKeyCode(keyCode, mDisplayOrientation);
1022
1023 if (down) {
1024 device->keyboard.current.downTime = when;
1025 }
1026
1027 /* Apply policy */
1028
1029 int32_t policyActions = mPolicy->interceptKey(when, device->id,
1030 down, keyCode, scanCode, policyFlags);
1031
1032 if (! applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
1033 return; // event dropped
1034 }
1035
1036 /* Enqueue key event for dispatch */
1037
1038 int32_t keyEventAction;
1039 if (down) {
1040 device->keyboard.current.downTime = when;
1041 keyEventAction = KEY_EVENT_ACTION_DOWN;
1042 } else {
1043 keyEventAction = KEY_EVENT_ACTION_UP;
1044 }
1045
1046 int32_t keyEventFlags = KEY_EVENT_FLAG_FROM_SYSTEM;
Jeff Brown9c3cda02010-06-15 01:31:58 -07001047 if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
Jeff Brown46b9ac02010-04-22 18:58:52 -07001048 keyEventFlags = keyEventFlags | KEY_EVENT_FLAG_WOKE_HERE;
1049 }
1050
1051 mDispatcher->notifyKey(when, device->id, INPUT_EVENT_NATURE_KEY, policyFlags,
1052 keyEventAction, keyEventFlags, keyCode, scanCode,
1053 device->keyboard.current.metaState,
1054 device->keyboard.current.downTime);
1055}
1056
Jeff Brown9c3cda02010-06-15 01:31:58 -07001057void InputReader::onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode,
1058 int32_t switchValue) {
1059 int32_t policyActions = mPolicy->interceptSwitch(when, switchCode, switchValue);
1060
1061 uint32_t policyFlags = 0;
1062 applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags);
Jeff Brown46b9ac02010-04-22 18:58:52 -07001063}
1064
1065void InputReader::onMultiTouchScreenStateChanged(nsecs_t when,
1066 InputDevice* device) {
1067 static const uint32_t REQUIRED_FIELDS =
1068 InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_X
1069 | InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_Y
1070 | InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MAJOR
1071 | InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
1072
1073 /* Refresh display properties so we can map touch screen coords into display coords */
1074
1075 if (! refreshDisplayProperties()) {
1076 return;
1077 }
1078
1079 /* Update device state */
1080
1081 InputDevice::MultiTouchScreenState* in = & device->multiTouchScreen;
1082 InputDevice::TouchData* out = & device->touchScreen.currentTouch;
1083
1084 uint32_t inCount = in->accumulator.pointerCount;
1085 uint32_t outCount = 0;
1086 bool havePointerIds = true;
1087
1088 out->clear();
1089
1090 for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
1091 uint32_t fields = in->accumulator.pointers[inIndex].fields;
1092
1093 if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
1094#if DEBUG_POINTERS
1095 LOGD("Pointers: Missing required multitouch pointer fields: index=%d, fields=%d",
1096 inIndex, fields);
1097 continue;
1098#endif
1099 }
1100
1101 if (in->accumulator.pointers[inIndex].absMTTouchMajor <= 0) {
1102 // Pointer is not down. Drop it.
1103 continue;
1104 }
1105
1106 // FIXME assignment of pressure may be incorrect, probably better to let
1107 // pressure = touch / width. Later on we pass width to MotionEvent as a size, which
1108 // isn't quite right either. Should be using touch for that.
1109 out->pointers[outCount].x = in->accumulator.pointers[inIndex].absMTPositionX;
1110 out->pointers[outCount].y = in->accumulator.pointers[inIndex].absMTPositionY;
1111 out->pointers[outCount].pressure = in->accumulator.pointers[inIndex].absMTTouchMajor;
1112 out->pointers[outCount].size = in->accumulator.pointers[inIndex].absMTWidthMajor;
1113
1114 if (havePointerIds) {
1115 if (fields & InputDevice::MultiTouchScreenState::Accumulator::
1116 FIELD_ABS_MT_TRACKING_ID) {
1117 uint32_t id = uint32_t(in->accumulator.pointers[inIndex].absMTTrackingId);
1118
1119 if (id > MAX_POINTER_ID) {
1120#if DEBUG_POINTERS
1121 LOGD("Pointers: Ignoring driver provided pointer id %d because "
1122 "it is larger than max supported id %d for optimizations",
1123 id, MAX_POINTER_ID);
1124#endif
1125 havePointerIds = false;
1126 }
1127 else {
1128 out->pointers[outCount].id = id;
1129 out->idToIndex[id] = outCount;
1130 out->idBits.markBit(id);
1131 }
1132 } else {
1133 havePointerIds = false;
1134 }
1135 }
1136
1137 outCount += 1;
1138 }
1139
1140 out->pointerCount = outCount;
1141
1142 onTouchScreenChanged(when, device, havePointerIds);
1143}
1144
1145void InputReader::onSingleTouchScreenStateChanged(nsecs_t when,
1146 InputDevice* device) {
1147 static const uint32_t POSITION_FIELDS =
1148 InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_X
1149 | InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_Y
1150 | InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_PRESSURE
1151 | InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_TOOL_WIDTH;
1152
1153 /* Refresh display properties so we can map touch screen coords into display coords */
1154
1155 if (! refreshDisplayProperties()) {
1156 return;
1157 }
1158
1159 /* Update device state */
1160
1161 InputDevice::SingleTouchScreenState* in = & device->singleTouchScreen;
1162 InputDevice::TouchData* out = & device->touchScreen.currentTouch;
1163
1164 uint32_t fields = in->accumulator.fields;
1165
1166 if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH) {
1167 in->current.down = in->accumulator.btnTouch;
1168 }
1169
1170 if ((fields & POSITION_FIELDS) == POSITION_FIELDS) {
1171 in->current.x = in->accumulator.absX;
1172 in->current.y = in->accumulator.absY;
1173 in->current.pressure = in->accumulator.absPressure;
1174 in->current.size = in->accumulator.absToolWidth;
1175 }
1176
1177 out->clear();
1178
1179 if (in->current.down) {
1180 out->pointerCount = 1;
1181 out->pointers[0].id = 0;
1182 out->pointers[0].x = in->current.x;
1183 out->pointers[0].y = in->current.y;
1184 out->pointers[0].pressure = in->current.pressure;
1185 out->pointers[0].size = in->current.size;
1186 out->idToIndex[0] = 0;
1187 out->idBits.markBit(0);
1188 }
1189
1190 onTouchScreenChanged(when, device, true);
1191}
1192
1193void InputReader::onTouchScreenChanged(nsecs_t when,
1194 InputDevice* device, bool havePointerIds) {
1195 /* Apply policy */
1196
1197 int32_t policyActions = mPolicy->interceptTouch(when);
1198
1199 uint32_t policyFlags = 0;
1200 if (! applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
1201 device->touchScreen.lastTouch.clear();
1202 return; // event dropped
1203 }
1204
1205 /* Preprocess pointer data */
1206
1207 if (device->touchScreen.parameters.useBadTouchFilter) {
1208 if (device->touchScreen.applyBadTouchFilter()) {
1209 havePointerIds = false;
1210 }
1211 }
1212
1213 if (device->touchScreen.parameters.useJumpyTouchFilter) {
1214 if (device->touchScreen.applyJumpyTouchFilter()) {
1215 havePointerIds = false;
1216 }
1217 }
1218
1219 if (! havePointerIds) {
1220 device->touchScreen.calculatePointerIds();
1221 }
1222
1223 InputDevice::TouchData temp;
1224 InputDevice::TouchData* savedTouch;
1225 if (device->touchScreen.parameters.useAveragingTouchFilter) {
1226 temp.copyFrom(device->touchScreen.currentTouch);
1227 savedTouch = & temp;
1228
1229 device->touchScreen.applyAveragingTouchFilter();
1230 } else {
1231 savedTouch = & device->touchScreen.currentTouch;
1232 }
1233
1234 /* Process virtual keys or touches */
1235
1236 if (! consumeVirtualKeyTouches(when, device, policyFlags)) {
1237 dispatchTouches(when, device, policyFlags);
1238 }
1239
1240 // Copy current touch to last touch in preparation for the next cycle.
1241 device->touchScreen.lastTouch.copyFrom(*savedTouch);
1242}
1243
1244bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
1245 InputDevice* device, uint32_t policyFlags) {
1246 if (device->touchScreen.currentVirtualKey.down) {
1247 if (device->touchScreen.currentTouch.pointerCount == 0) {
1248 // Pointer went up while virtual key was down. Send key up event.
1249 device->touchScreen.currentVirtualKey.down = false;
1250
1251#if DEBUG_VIRTUAL_KEYS
1252 LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
1253 device->touchScreen.currentVirtualKey.keyCode,
1254 device->touchScreen.currentVirtualKey.scanCode);
1255#endif
1256
1257 dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
1258 KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
1259 return true; // consumed
1260 }
1261
1262 int32_t x = device->touchScreen.currentTouch.pointers[0].x;
1263 int32_t y = device->touchScreen.currentTouch.pointers[0].y;
Jeff Brown5c225b12010-06-16 01:53:36 -07001264 if (device->touchScreen.isPointInsideDisplay(x, y)
1265 || device->touchScreen.currentTouch.pointerCount != 1) {
1266 // Pointer moved inside the display area or another pointer also went down.
1267 // Send key cancellation.
Jeff Brown46b9ac02010-04-22 18:58:52 -07001268 device->touchScreen.currentVirtualKey.down = false;
1269
1270#if DEBUG_VIRTUAL_KEYS
1271 LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
1272 device->touchScreen.currentVirtualKey.keyCode,
1273 device->touchScreen.currentVirtualKey.scanCode);
1274#endif
1275
1276 dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
1277 KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY
1278 | KEY_EVENT_FLAG_CANCELED);
1279
1280 // Clear the last touch data so we will consider the pointer as having just been
1281 // pressed down when generating subsequent motion events.
1282 device->touchScreen.lastTouch.clear();
1283 return false; // not consumed
1284 }
Jeff Brown5c225b12010-06-16 01:53:36 -07001285 } else if (device->touchScreen.currentTouch.pointerCount == 1
Jeff Brown46b9ac02010-04-22 18:58:52 -07001286 && device->touchScreen.lastTouch.pointerCount == 0) {
1287 int32_t x = device->touchScreen.currentTouch.pointers[0].x;
1288 int32_t y = device->touchScreen.currentTouch.pointers[0].y;
1289 for (size_t i = 0; i < device->touchScreen.virtualKeys.size(); i++) {
1290 const InputDevice::VirtualKey& virtualKey = device->touchScreen.virtualKeys[i];
1291
1292#if DEBUG_VIRTUAL_KEYS
1293 LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
1294 "left=%d, top=%d, right=%d, bottom=%d",
1295 x, y,
1296 virtualKey.keyCode, virtualKey.scanCode,
1297 virtualKey.hitLeft, virtualKey.hitTop,
1298 virtualKey.hitRight, virtualKey.hitBottom);
1299#endif
1300
1301 if (virtualKey.isHit(x, y)) {
1302 device->touchScreen.currentVirtualKey.down = true;
1303 device->touchScreen.currentVirtualKey.downTime = when;
1304 device->touchScreen.currentVirtualKey.keyCode = virtualKey.keyCode;
1305 device->touchScreen.currentVirtualKey.scanCode = virtualKey.scanCode;
1306
1307#if DEBUG_VIRTUAL_KEYS
1308 LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
1309 device->touchScreen.currentVirtualKey.keyCode,
1310 device->touchScreen.currentVirtualKey.scanCode);
1311#endif
1312
1313 dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_DOWN,
1314 KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
1315 return true; // consumed
1316 }
1317 }
1318 }
1319
1320 return false; // not consumed
1321}
1322
1323void InputReader::dispatchVirtualKey(nsecs_t when,
1324 InputDevice* device, uint32_t policyFlags,
1325 int32_t keyEventAction, int32_t keyEventFlags) {
1326 int32_t keyCode = device->touchScreen.currentVirtualKey.keyCode;
1327 int32_t scanCode = device->touchScreen.currentVirtualKey.scanCode;
1328 nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
1329 int32_t metaState = globalMetaState();
1330
Jeff Brown9c3cda02010-06-15 01:31:58 -07001331 updateExportedVirtualKeyState();
Jeff Brown46b9ac02010-04-22 18:58:52 -07001332
1333 mPolicy->virtualKeyFeedback(when, device->id, keyEventAction, keyEventFlags,
1334 keyCode, scanCode, metaState, downTime);
1335
1336 mDispatcher->notifyKey(when, device->id, INPUT_EVENT_NATURE_KEY, policyFlags,
1337 keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
1338}
1339
1340void InputReader::dispatchTouches(nsecs_t when,
1341 InputDevice* device, uint32_t policyFlags) {
1342 uint32_t currentPointerCount = device->touchScreen.currentTouch.pointerCount;
1343 uint32_t lastPointerCount = device->touchScreen.lastTouch.pointerCount;
1344 if (currentPointerCount == 0 && lastPointerCount == 0) {
1345 return; // nothing to do!
1346 }
1347
1348 BitSet32 currentIdBits = device->touchScreen.currentTouch.idBits;
1349 BitSet32 lastIdBits = device->touchScreen.lastTouch.idBits;
1350
1351 if (currentIdBits == lastIdBits) {
1352 // No pointer id changes so this is a move event.
1353 // The dispatcher takes care of batching moves so we don't have to deal with that here.
1354 int32_t motionEventAction = MOTION_EVENT_ACTION_MOVE;
1355 dispatchTouch(when, device, policyFlags, & device->touchScreen.currentTouch,
1356 currentIdBits, motionEventAction);
1357 } else {
1358 // There may be pointers going up and pointers going down at the same time when pointer
1359 // ids are reported by the device driver.
1360 BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value);
1361 BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value);
1362 BitSet32 activeIdBits(lastIdBits.value);
1363
1364 while (! upIdBits.isEmpty()) {
1365 uint32_t upId = upIdBits.firstMarkedBit();
1366 upIdBits.clearBit(upId);
1367 BitSet32 oldActiveIdBits = activeIdBits;
1368 activeIdBits.clearBit(upId);
1369
1370 int32_t motionEventAction;
1371 if (activeIdBits.isEmpty()) {
1372 motionEventAction = MOTION_EVENT_ACTION_UP;
1373 } else {
1374 motionEventAction = MOTION_EVENT_ACTION_POINTER_UP
1375 | (upId << MOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
1376 }
1377
1378 dispatchTouch(when, device, policyFlags, & device->touchScreen.lastTouch,
1379 oldActiveIdBits, motionEventAction);
1380 }
1381
1382 while (! downIdBits.isEmpty()) {
1383 uint32_t downId = downIdBits.firstMarkedBit();
1384 downIdBits.clearBit(downId);
1385 BitSet32 oldActiveIdBits = activeIdBits;
1386 activeIdBits.markBit(downId);
1387
1388 int32_t motionEventAction;
1389 if (oldActiveIdBits.isEmpty()) {
1390 motionEventAction = MOTION_EVENT_ACTION_DOWN;
1391 device->touchScreen.downTime = when;
1392 } else {
1393 motionEventAction = MOTION_EVENT_ACTION_POINTER_DOWN
1394 | (downId << MOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
1395 }
1396
1397 dispatchTouch(when, device, policyFlags, & device->touchScreen.currentTouch,
1398 activeIdBits, motionEventAction);
1399 }
1400 }
1401}
1402
1403void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t policyFlags,
1404 InputDevice::TouchData* touch, BitSet32 idBits,
1405 int32_t motionEventAction) {
1406 int32_t orientedWidth, orientedHeight;
1407 switch (mDisplayOrientation) {
Jeff Brown9c3cda02010-06-15 01:31:58 -07001408 case InputReaderPolicyInterface::ROTATION_90:
1409 case InputReaderPolicyInterface::ROTATION_270:
Jeff Brown46b9ac02010-04-22 18:58:52 -07001410 orientedWidth = mDisplayHeight;
1411 orientedHeight = mDisplayWidth;
1412 break;
1413 default:
1414 orientedWidth = mDisplayWidth;
1415 orientedHeight = mDisplayHeight;
1416 break;
1417 }
1418
1419 uint32_t pointerCount = 0;
1420 int32_t pointerIds[MAX_POINTERS];
1421 PointerCoords pointerCoords[MAX_POINTERS];
1422
1423 // Walk through the the active pointers and map touch screen coordinates (TouchData) into
1424 // display coordinates (PointerCoords) and adjust for display orientation.
1425 while (! idBits.isEmpty()) {
1426 uint32_t id = idBits.firstMarkedBit();
1427 idBits.clearBit(id);
1428 uint32_t index = touch->idToIndex[id];
1429
1430 float x = (float(touch->pointers[index].x)
1431 - device->touchScreen.parameters.xAxis.minValue)
1432 * device->touchScreen.precalculated.xScale;
1433 float y = (float(touch->pointers[index].y)
1434 - device->touchScreen.parameters.yAxis.minValue)
1435 * device->touchScreen.precalculated.yScale;
1436 float pressure = (float(touch->pointers[index].pressure)
1437 - device->touchScreen.parameters.pressureAxis.minValue)
1438 * device->touchScreen.precalculated.pressureScale;
1439 float size = (float(touch->pointers[index].size)
1440 - device->touchScreen.parameters.sizeAxis.minValue)
1441 * device->touchScreen.precalculated.sizeScale;
1442
1443 switch (mDisplayOrientation) {
Jeff Brown9c3cda02010-06-15 01:31:58 -07001444 case InputReaderPolicyInterface::ROTATION_90: {
Jeff Brown46b9ac02010-04-22 18:58:52 -07001445 float xTemp = x;
1446 x = y;
1447 y = mDisplayHeight - xTemp;
1448 break;
1449 }
Jeff Brown9c3cda02010-06-15 01:31:58 -07001450 case InputReaderPolicyInterface::ROTATION_180: {
Jeff Brown46b9ac02010-04-22 18:58:52 -07001451 x = mDisplayWidth - x;
1452 y = mDisplayHeight - y;
1453 break;
1454 }
Jeff Brown9c3cda02010-06-15 01:31:58 -07001455 case InputReaderPolicyInterface::ROTATION_270: {
Jeff Brown46b9ac02010-04-22 18:58:52 -07001456 float xTemp = x;
1457 x = mDisplayWidth - y;
1458 y = xTemp;
1459 break;
1460 }
1461 }
1462
1463 pointerIds[pointerCount] = int32_t(id);
1464
1465 pointerCoords[pointerCount].x = x;
1466 pointerCoords[pointerCount].y = y;
1467 pointerCoords[pointerCount].pressure = pressure;
1468 pointerCoords[pointerCount].size = size;
1469
1470 pointerCount += 1;
1471 }
1472
1473 // Check edge flags by looking only at the first pointer since the flags are
1474 // global to the event.
1475 // XXX Maybe we should revise the edge flags API to work on a per-pointer basis.
1476 int32_t motionEventEdgeFlags = 0;
1477 if (motionEventAction == MOTION_EVENT_ACTION_DOWN) {
1478 if (pointerCoords[0].x <= 0) {
1479 motionEventEdgeFlags |= MOTION_EVENT_EDGE_FLAG_LEFT;
1480 } else if (pointerCoords[0].x >= orientedWidth) {
1481 motionEventEdgeFlags |= MOTION_EVENT_EDGE_FLAG_RIGHT;
1482 }
1483 if (pointerCoords[0].y <= 0) {
1484 motionEventEdgeFlags |= MOTION_EVENT_EDGE_FLAG_TOP;
1485 } else if (pointerCoords[0].y >= orientedHeight) {
1486 motionEventEdgeFlags |= MOTION_EVENT_EDGE_FLAG_BOTTOM;
1487 }
1488 }
1489
1490 nsecs_t downTime = device->touchScreen.downTime;
1491 mDispatcher->notifyMotion(when, device->id, INPUT_EVENT_NATURE_TOUCH, policyFlags,
1492 motionEventAction, globalMetaState(), motionEventEdgeFlags,
1493 pointerCount, pointerIds, pointerCoords,
1494 0, 0, downTime);
1495}
1496
1497void InputReader::onTrackballStateChanged(nsecs_t when,
1498 InputDevice* device) {
1499 static const uint32_t DELTA_FIELDS =
1500 InputDevice::TrackballState::Accumulator::FIELD_REL_X
1501 | InputDevice::TrackballState::Accumulator::FIELD_REL_Y;
1502
1503 /* Refresh display properties so we can trackball moves according to display orientation */
1504
1505 if (! refreshDisplayProperties()) {
1506 return;
1507 }
1508
1509 /* Update device state */
1510
1511 uint32_t fields = device->trackball.accumulator.fields;
1512 bool downChanged = fields & InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
1513 bool deltaChanged = (fields & DELTA_FIELDS) == DELTA_FIELDS;
1514
1515 bool down;
1516 if (downChanged) {
1517 if (device->trackball.accumulator.btnMouse) {
1518 device->trackball.current.down = true;
1519 device->trackball.current.downTime = when;
1520 down = true;
1521 } else {
1522 device->trackball.current.down = false;
1523 down = false;
1524 }
1525 } else {
1526 down = device->trackball.current.down;
1527 }
1528
1529 /* Apply policy */
1530
1531 int32_t policyActions = mPolicy->interceptTrackball(when, downChanged, down, deltaChanged);
1532
1533 uint32_t policyFlags = 0;
1534 if (! applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
1535 return; // event dropped
1536 }
1537
1538 /* Enqueue motion event for dispatch */
1539
1540 int32_t motionEventAction;
1541 if (downChanged) {
1542 motionEventAction = down ? MOTION_EVENT_ACTION_DOWN : MOTION_EVENT_ACTION_UP;
1543 } else {
1544 motionEventAction = MOTION_EVENT_ACTION_MOVE;
1545 }
1546
1547 int32_t pointerId = 0;
1548 PointerCoords pointerCoords;
1549 pointerCoords.x = device->trackball.accumulator.relX
1550 * device->trackball.precalculated.xScale;
1551 pointerCoords.y = device->trackball.accumulator.relY
1552 * device->trackball.precalculated.yScale;
1553 pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise.
1554 pointerCoords.size = 0;
1555
1556 float temp;
1557 switch (mDisplayOrientation) {
Jeff Brown9c3cda02010-06-15 01:31:58 -07001558 case InputReaderPolicyInterface::ROTATION_90:
Jeff Brown46b9ac02010-04-22 18:58:52 -07001559 temp = pointerCoords.x;
1560 pointerCoords.x = pointerCoords.y;
1561 pointerCoords.y = - temp;
1562 break;
1563
Jeff Brown9c3cda02010-06-15 01:31:58 -07001564 case InputReaderPolicyInterface::ROTATION_180:
Jeff Brown46b9ac02010-04-22 18:58:52 -07001565 pointerCoords.x = - pointerCoords.x;
1566 pointerCoords.y = - pointerCoords.y;
1567 break;
1568
Jeff Brown9c3cda02010-06-15 01:31:58 -07001569 case InputReaderPolicyInterface::ROTATION_270:
Jeff Brown46b9ac02010-04-22 18:58:52 -07001570 temp = pointerCoords.x;
1571 pointerCoords.x = - pointerCoords.y;
1572 pointerCoords.y = temp;
1573 break;
1574 }
1575
1576 mDispatcher->notifyMotion(when, device->id, INPUT_EVENT_NATURE_TRACKBALL, policyFlags,
1577 motionEventAction, globalMetaState(), MOTION_EVENT_EDGE_FLAG_NONE,
1578 1, & pointerId, & pointerCoords,
1579 device->trackball.precalculated.xPrecision,
1580 device->trackball.precalculated.yPrecision,
1581 device->trackball.current.downTime);
1582}
1583
1584void InputReader::onConfigurationChanged(nsecs_t when) {
1585 // Reset global meta state because it depends on the list of all configured devices.
1586 resetGlobalMetaState();
1587
1588 // Reset virtual keys, just in case.
Jeff Brown9c3cda02010-06-15 01:31:58 -07001589 updateExportedVirtualKeyState();
1590
1591 // Update input configuration.
1592 updateExportedInputConfiguration();
Jeff Brown46b9ac02010-04-22 18:58:52 -07001593
1594 // Enqueue configuration changed.
Jeff Brown9c3cda02010-06-15 01:31:58 -07001595 mDispatcher->notifyConfigurationChanged(when);
Jeff Brown46b9ac02010-04-22 18:58:52 -07001596}
1597
1598bool InputReader::applyStandardInputDispatchPolicyActions(nsecs_t when,
1599 int32_t policyActions, uint32_t* policyFlags) {
Jeff Brown9c3cda02010-06-15 01:31:58 -07001600 if (policyActions & InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING) {
Jeff Brown46b9ac02010-04-22 18:58:52 -07001601 mDispatcher->notifyAppSwitchComing(when);
1602 }
1603
Jeff Brown9c3cda02010-06-15 01:31:58 -07001604 if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
Jeff Brown46b9ac02010-04-22 18:58:52 -07001605 *policyFlags |= POLICY_FLAG_WOKE_HERE;
1606 }
1607
Jeff Brown9c3cda02010-06-15 01:31:58 -07001608 if (policyActions & InputReaderPolicyInterface::ACTION_BRIGHT_HERE) {
Jeff Brown46b9ac02010-04-22 18:58:52 -07001609 *policyFlags |= POLICY_FLAG_BRIGHT_HERE;
1610 }
1611
Jeff Brown9c3cda02010-06-15 01:31:58 -07001612 return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
Jeff Brown46b9ac02010-04-22 18:58:52 -07001613}
1614
1615void InputReader::resetDisplayProperties() {
1616 mDisplayWidth = mDisplayHeight = -1;
1617 mDisplayOrientation = -1;
1618}
1619
1620bool InputReader::refreshDisplayProperties() {
1621 int32_t newWidth, newHeight, newOrientation;
1622 if (mPolicy->getDisplayInfo(0, & newWidth, & newHeight, & newOrientation)) {
1623 if (newWidth != mDisplayWidth || newHeight != mDisplayHeight) {
1624 LOGD("Display size changed from %dx%d to %dx%d, updating device configuration",
1625 mDisplayWidth, mDisplayHeight, newWidth, newHeight);
1626
1627 mDisplayWidth = newWidth;
1628 mDisplayHeight = newHeight;
1629
1630 for (size_t i = 0; i < mDevices.size(); i++) {
1631 configureDeviceForCurrentDisplaySize(mDevices.valueAt(i));
1632 }
1633 }
1634
1635 mDisplayOrientation = newOrientation;
1636 return true;
1637 } else {
1638 resetDisplayProperties();
1639 return false;
1640 }
1641}
1642
1643InputDevice* InputReader::getDevice(int32_t deviceId) {
1644 ssize_t index = mDevices.indexOfKey(deviceId);
1645 return index >= 0 ? mDevices.valueAt((size_t) index) : NULL;
1646}
1647
1648InputDevice* InputReader::getNonIgnoredDevice(int32_t deviceId) {
1649 InputDevice* device = getDevice(deviceId);
1650 return device && ! device->ignored ? device : NULL;
1651}
1652
1653void InputReader::addDevice(nsecs_t when, int32_t deviceId) {
1654 uint32_t classes = mEventHub->getDeviceClasses(deviceId);
1655 String8 name = mEventHub->getDeviceName(deviceId);
1656 InputDevice* device = new InputDevice(deviceId, classes, name);
1657
1658 if (classes != 0) {
1659 LOGI("Device added: id=0x%x, name=%s, classes=%02x", device->id,
1660 device->name.string(), device->classes);
1661
1662 configureDevice(device);
1663 } else {
1664 LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", device->id,
1665 device->name.string());
1666
1667 device->ignored = true;
1668 }
1669
1670 device->reset();
1671
1672 mDevices.add(deviceId, device);
1673
1674 if (! device->ignored) {
1675 onConfigurationChanged(when);
1676 }
1677}
1678
1679void InputReader::removeDevice(nsecs_t when, InputDevice* device) {
1680 mDevices.removeItem(device->id);
1681
1682 if (! device->ignored) {
1683 LOGI("Device removed: id=0x%x, name=%s, classes=%02x", device->id,
1684 device->name.string(), device->classes);
1685
1686 onConfigurationChanged(when);
1687 } else {
1688 LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)", device->id,
1689 device->name.string());
1690 }
1691
1692 delete device;
1693}
1694
1695void InputReader::configureDevice(InputDevice* device) {
1696 if (device->isMultiTouchScreen()) {
1697 configureAbsoluteAxisInfo(device, ABS_MT_POSITION_X, "X",
1698 & device->touchScreen.parameters.xAxis);
1699 configureAbsoluteAxisInfo(device, ABS_MT_POSITION_Y, "Y",
1700 & device->touchScreen.parameters.yAxis);
1701 configureAbsoluteAxisInfo(device, ABS_MT_TOUCH_MAJOR, "Pressure",
1702 & device->touchScreen.parameters.pressureAxis);
1703 configureAbsoluteAxisInfo(device, ABS_MT_WIDTH_MAJOR, "Size",
1704 & device->touchScreen.parameters.sizeAxis);
1705 } else if (device->isSingleTouchScreen()) {
1706 configureAbsoluteAxisInfo(device, ABS_X, "X",
1707 & device->touchScreen.parameters.xAxis);
1708 configureAbsoluteAxisInfo(device, ABS_Y, "Y",
1709 & device->touchScreen.parameters.yAxis);
1710 configureAbsoluteAxisInfo(device, ABS_PRESSURE, "Pressure",
1711 & device->touchScreen.parameters.pressureAxis);
1712 configureAbsoluteAxisInfo(device, ABS_TOOL_WIDTH, "Size",
1713 & device->touchScreen.parameters.sizeAxis);
1714 }
1715
1716 if (device->isTouchScreen()) {
1717 device->touchScreen.parameters.useBadTouchFilter =
1718 mPolicy->filterTouchEvents();
1719 device->touchScreen.parameters.useAveragingTouchFilter =
1720 mPolicy->filterTouchEvents();
1721 device->touchScreen.parameters.useJumpyTouchFilter =
1722 mPolicy->filterJumpyTouchEvents();
1723
1724 device->touchScreen.precalculated.pressureScale =
1725 1.0f / device->touchScreen.parameters.pressureAxis.range;
1726 device->touchScreen.precalculated.sizeScale =
1727 1.0f / device->touchScreen.parameters.sizeAxis.range;
1728 }
1729
1730 if (device->isTrackball()) {
1731 device->trackball.precalculated.xPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
1732 device->trackball.precalculated.yPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
1733 device->trackball.precalculated.xScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
1734 device->trackball.precalculated.yScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
1735 }
1736
1737 configureDeviceForCurrentDisplaySize(device);
1738}
1739
1740void InputReader::configureDeviceForCurrentDisplaySize(InputDevice* device) {
1741 if (device->isTouchScreen()) {
1742 if (mDisplayWidth < 0) {
1743 LOGD("Skipping part of touch screen configuration since display size is unknown.");
1744 } else {
1745 LOGI("Device configured: id=0x%x, name=%s (display size was changed)", device->id,
1746 device->name.string());
1747 configureVirtualKeys(device);
1748
1749 device->touchScreen.precalculated.xScale =
1750 float(mDisplayWidth) / device->touchScreen.parameters.xAxis.range;
1751 device->touchScreen.precalculated.yScale =
1752 float(mDisplayHeight) / device->touchScreen.parameters.yAxis.range;
1753 }
1754 }
1755}
1756
1757void InputReader::configureVirtualKeys(InputDevice* device) {
1758 device->touchScreen.virtualKeys.clear();
1759
Jeff Brown9c3cda02010-06-15 01:31:58 -07001760 Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
Jeff Brown46b9ac02010-04-22 18:58:52 -07001761 mPolicy->getVirtualKeyDefinitions(device->name, virtualKeyDefinitions);
1762 if (virtualKeyDefinitions.size() == 0) {
1763 return;
1764 }
1765
1766 device->touchScreen.virtualKeys.setCapacity(virtualKeyDefinitions.size());
1767
1768 int32_t touchScreenLeft = device->touchScreen.parameters.xAxis.minValue;
1769 int32_t touchScreenTop = device->touchScreen.parameters.yAxis.minValue;
1770 int32_t touchScreenWidth = device->touchScreen.parameters.xAxis.range;
1771 int32_t touchScreenHeight = device->touchScreen.parameters.yAxis.range;
1772
1773 for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
Jeff Brown9c3cda02010-06-15 01:31:58 -07001774 const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
Jeff Brown46b9ac02010-04-22 18:58:52 -07001775 virtualKeyDefinitions[i];
1776
1777 device->touchScreen.virtualKeys.add();
1778 InputDevice::VirtualKey& virtualKey =
1779 device->touchScreen.virtualKeys.editTop();
1780
1781 virtualKey.scanCode = virtualKeyDefinition.scanCode;
1782 int32_t keyCode;
1783 uint32_t flags;
1784 if (mEventHub->scancodeToKeycode(device->id, virtualKey.scanCode,
1785 & keyCode, & flags)) {
1786 LOGI(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
1787 device->touchScreen.virtualKeys.pop(); // drop the key
1788 continue;
1789 }
1790
1791 virtualKey.keyCode = keyCode;
1792 virtualKey.flags = flags;
1793
1794 // convert the key definition's display coordinates into touch coordinates for a hit box
1795 int32_t halfWidth = virtualKeyDefinition.width / 2;
1796 int32_t halfHeight = virtualKeyDefinition.height / 2;
1797
1798 virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
1799 * touchScreenWidth / mDisplayWidth + touchScreenLeft;
1800 virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
1801 * touchScreenWidth / mDisplayWidth + touchScreenLeft;
1802 virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
1803 * touchScreenHeight / mDisplayHeight + touchScreenTop;
1804 virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
1805 * touchScreenHeight / mDisplayHeight + touchScreenTop;
1806
1807 LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
1808 virtualKey.scanCode, virtualKey.keyCode,
1809 virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
1810 }
1811}
1812
1813void InputReader::configureAbsoluteAxisInfo(InputDevice* device,
1814 int axis, const char* name, InputDevice::AbsoluteAxisInfo* out) {
1815 if (! mEventHub->getAbsoluteInfo(device->id, axis,
1816 & out->minValue, & out->maxValue, & out->flat, &out->fuzz)) {
1817 out->range = out->maxValue - out->minValue;
1818 if (out->range != 0) {
1819 LOGI(" %s: min=%d max=%d flat=%d fuzz=%d",
1820 name, out->minValue, out->maxValue, out->flat, out->fuzz);
1821 return;
1822 }
1823 }
1824
1825 out->minValue = 0;
1826 out->maxValue = 0;
1827 out->flat = 0;
1828 out->fuzz = 0;
1829 out->range = 0;
1830 LOGI(" %s: unknown axis values, setting to zero", name);
1831}
1832
Jeff Brown9c3cda02010-06-15 01:31:58 -07001833void InputReader::configureExcludedDevices() {
1834 Vector<String8> excludedDeviceNames;
1835 mPolicy->getExcludedDeviceNames(excludedDeviceNames);
1836
1837 for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
1838 mEventHub->addExcludedDevice(excludedDeviceNames[i]);
1839 }
1840}
1841
Jeff Brown46b9ac02010-04-22 18:58:52 -07001842void InputReader::resetGlobalMetaState() {
1843 mGlobalMetaState = -1;
1844}
1845
1846int32_t InputReader::globalMetaState() {
1847 if (mGlobalMetaState == -1) {
1848 mGlobalMetaState = 0;
1849 for (size_t i = 0; i < mDevices.size(); i++) {
1850 InputDevice* device = mDevices.valueAt(i);
1851 if (device->isKeyboard()) {
1852 mGlobalMetaState |= device->keyboard.current.metaState;
1853 }
1854 }
1855 }
1856 return mGlobalMetaState;
1857}
1858
Jeff Brown9c3cda02010-06-15 01:31:58 -07001859void InputReader::updateExportedVirtualKeyState() {
Jeff Brown46b9ac02010-04-22 18:58:52 -07001860 int32_t keyCode = -1, scanCode = -1;
1861
1862 for (size_t i = 0; i < mDevices.size(); i++) {
1863 InputDevice* device = mDevices.valueAt(i);
1864 if (device->isTouchScreen()) {
1865 if (device->touchScreen.currentVirtualKey.down) {
1866 keyCode = device->touchScreen.currentVirtualKey.keyCode;
1867 scanCode = device->touchScreen.currentVirtualKey.scanCode;
1868 }
1869 }
1870 }
1871
Jeff Brown9c3cda02010-06-15 01:31:58 -07001872 { // acquire exported state lock
Jeff Brown46b9ac02010-04-22 18:58:52 -07001873 AutoMutex _l(mExportedStateLock);
1874
Jeff Brown9c3cda02010-06-15 01:31:58 -07001875 mExportedVirtualKeyCode = keyCode;
1876 mExportedVirtualScanCode = scanCode;
1877 } // release exported state lock
Jeff Brown46b9ac02010-04-22 18:58:52 -07001878}
1879
1880bool InputReader::getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const {
Jeff Brown9c3cda02010-06-15 01:31:58 -07001881 { // acquire exported state lock
1882 AutoMutex _l(mExportedStateLock);
Jeff Brown46b9ac02010-04-22 18:58:52 -07001883
Jeff Brown9c3cda02010-06-15 01:31:58 -07001884 *outKeyCode = mExportedVirtualKeyCode;
1885 *outScanCode = mExportedVirtualScanCode;
1886 return mExportedVirtualKeyCode != -1;
1887 } // release exported state lock
1888}
1889
1890void InputReader::updateExportedInputConfiguration() {
1891 int32_t touchScreenConfig = InputConfiguration::TOUCHSCREEN_NOTOUCH;
1892 int32_t keyboardConfig = InputConfiguration::KEYBOARD_NOKEYS;
1893 int32_t navigationConfig = InputConfiguration::NAVIGATION_NONAV;
1894
1895 for (size_t i = 0; i < mDevices.size(); i++) {
1896 InputDevice* device = mDevices.valueAt(i);
1897 int32_t deviceClasses = device->classes;
1898
1899 if (deviceClasses & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
1900 touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER;
1901 }
1902 if (deviceClasses & INPUT_DEVICE_CLASS_ALPHAKEY) {
1903 keyboardConfig = InputConfiguration::KEYBOARD_QWERTY;
1904 }
1905 if (deviceClasses & INPUT_DEVICE_CLASS_TRACKBALL) {
1906 navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL;
1907 } else if (deviceClasses & INPUT_DEVICE_CLASS_DPAD) {
1908 navigationConfig = InputConfiguration::NAVIGATION_DPAD;
1909 }
1910 }
1911
1912 { // acquire exported state lock
1913 AutoMutex _l(mExportedStateLock);
1914
1915 mExportedInputConfiguration.touchScreen = touchScreenConfig;
1916 mExportedInputConfiguration.keyboard = keyboardConfig;
1917 mExportedInputConfiguration.navigation = navigationConfig;
1918 } // release exported state lock
1919}
1920
1921void InputReader::getCurrentInputConfiguration(InputConfiguration* outConfiguration) const {
1922 { // acquire exported state lock
1923 AutoMutex _l(mExportedStateLock);
1924
1925 *outConfiguration = mExportedInputConfiguration;
1926 } // release exported state lock
1927}
1928
1929int32_t InputReader::getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
1930 int32_t scanCode) const {
1931 { // acquire exported state lock
1932 AutoMutex _l(mExportedStateLock);
1933
1934 if (mExportedVirtualScanCode == scanCode) {
1935 return KEY_STATE_VIRTUAL;
1936 }
1937 } // release exported state lock
1938
1939 return mEventHub->getScanCodeState(deviceId, deviceClasses, scanCode);
1940}
1941
1942int32_t InputReader::getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
1943 int32_t keyCode) const {
1944 { // acquire exported state lock
1945 AutoMutex _l(mExportedStateLock);
1946
1947 if (mExportedVirtualKeyCode == keyCode) {
1948 return KEY_STATE_VIRTUAL;
1949 }
1950 } // release exported state lock
1951
1952 return mEventHub->getKeyCodeState(deviceId, deviceClasses, keyCode);
1953}
1954
1955int32_t InputReader::getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
1956 int32_t sw) const {
1957 return mEventHub->getSwitchState(deviceId, deviceClasses, sw);
1958}
1959
1960bool InputReader::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const {
1961 return mEventHub->hasKeys(numCodes, keyCodes, outFlags);
Jeff Brown46b9ac02010-04-22 18:58:52 -07001962}
1963
1964
1965// --- InputReaderThread ---
1966
1967InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
1968 Thread(/*canCallJava*/ true), mReader(reader) {
1969}
1970
1971InputReaderThread::~InputReaderThread() {
1972}
1973
1974bool InputReaderThread::threadLoop() {
1975 mReader->loopOnce();
1976 return true;
1977}
1978
1979} // namespace android