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