2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #define LOG_TAG "InputReader"
19 //#define LOG_NDEBUG 0
21 // Log debug messages for each raw event received from the EventHub.
22 #define DEBUG_RAW_EVENTS 0
24 // Log debug messages about touch screen filtering hacks.
27 // Log debug messages about virtual key processing.
28 #define DEBUG_VIRTUAL_KEYS 0
30 // Log debug messages about pointers.
31 #define DEBUG_POINTERS 0
33 // Log debug messages about pointer assignment calculations.
34 #define DEBUG_POINTER_ASSIGNMENT 0
36 // Log debug messages about gesture detection.
37 #define DEBUG_GESTURES 0
39 // Log debug messages about the vibrator.
40 #define DEBUG_VIBRATOR 0
42 // Log debug messages about fusing stylus data.
43 #define DEBUG_STYLUS_FUSION 0
45 #include "InputReader.h"
47 #include <cutils/log.h>
48 #include <input/Keyboard.h>
49 #include <input/VirtualKeyMap.h>
69 // Maximum number of slots supported when using the slot-based Multitouch Protocol B.
70 static const size_t MAX_SLOTS = 32;
72 // Maximum amount of latency to add to touch events while waiting for data from an
74 static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
76 // Maximum amount of time to wait on touch data before pushing out new pressure data.
77 static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
79 // Artificial latency on synthetic events created from stylus data without corresponding touch
81 static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
83 // --- Static Functions ---
86 inline static T abs(const T& value) {
87 return value < 0 ? - value : value;
91 inline static T min(const T& a, const T& b) {
96 inline static void swap(T& a, T& b) {
102 inline static float avg(float x, float y) {
106 inline static float distance(float x1, float y1, float x2, float y2) {
107 return hypotf(x1 - x2, y1 - y2);
110 inline static int32_t signExtendNybble(int32_t value) {
111 return value >= 8 ? value - 16 : value;
114 static inline const char* toString(bool value) {
115 return value ? "true" : "false";
118 static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation,
119 const int32_t map[][4], size_t mapSize, int32_t rotationMapOffset) {
120 if (orientation != DISPLAY_ORIENTATION_0) {
121 for (size_t i = rotationMapOffset; i < mapSize; i++) {
122 if (value == map[i][0]) {
123 return map[i][orientation];
130 static const int32_t keyCodeRotationMap[][4] = {
131 // key codes enumerated counter-clockwise with the original (unrotated) key first
132 // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
134 // volume keys - tablet
135 { AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_DOWN },
136 { AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_UP },
138 // volume keys - phone or hybrid
139 { AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_UP },
140 { AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_DOWN },
142 // dpad keys - common
143 { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT },
144 { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN },
145 { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT },
146 { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP },
148 static const size_t keyCodeRotationMapSize =
149 sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
151 static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation, int32_t rotationMapOffset) {
152 return rotateValueUsingRotationMap(keyCode, orientation,
153 keyCodeRotationMap, keyCodeRotationMapSize, rotationMapOffset);
156 static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) {
158 switch (orientation) {
159 case DISPLAY_ORIENTATION_90:
165 case DISPLAY_ORIENTATION_180:
170 case DISPLAY_ORIENTATION_270:
178 static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
179 return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0;
182 // Returns true if the pointer should be reported as being down given the specified
183 // button states. This determines whether the event is reported as a touch event.
184 static bool isPointerDown(int32_t buttonState) {
186 (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY
187 | AMOTION_EVENT_BUTTON_TERTIARY);
190 static float calculateCommonVector(float a, float b) {
191 if (a > 0 && b > 0) {
192 return a < b ? a : b;
193 } else if (a < 0 && b < 0) {
194 return a > b ? a : b;
200 static void synthesizeButtonKey(InputReaderContext* context, int32_t action,
201 nsecs_t when, int32_t deviceId, uint32_t source,
202 uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState,
203 int32_t buttonState, int32_t keyCode) {
205 (action == AKEY_EVENT_ACTION_DOWN
206 && !(lastButtonState & buttonState)
207 && (currentButtonState & buttonState))
208 || (action == AKEY_EVENT_ACTION_UP
209 && (lastButtonState & buttonState)
210 && !(currentButtonState & buttonState))) {
211 NotifyKeyArgs args(when, deviceId, source, policyFlags,
212 action, 0, keyCode, 0, context->getGlobalMetaState(), when);
213 context->getListener()->notifyKey(&args);
217 static void synthesizeButtonKeys(InputReaderContext* context, int32_t action,
218 nsecs_t when, int32_t deviceId, uint32_t source,
219 uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) {
220 synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
221 lastButtonState, currentButtonState,
222 AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK);
223 synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
224 lastButtonState, currentButtonState,
225 AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD);
229 // --- InputReaderConfiguration ---
231 bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const {
232 const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay;
233 if (viewport.displayId >= 0) {
234 *outViewport = viewport;
240 void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) {
241 DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay;
246 // -- TouchAffineTransformation --
247 void TouchAffineTransformation::applyTo(float& x, float& y) const {
249 newX = x * x_scale + y * x_ymix + x_offset;
250 newY = x * y_xmix + y * y_scale + y_offset;
257 // --- InputReader ---
259 InputReader::InputReader(const sp<EventHubInterface>& eventHub,
260 const sp<InputReaderPolicyInterface>& policy,
261 const sp<InputListenerInterface>& listener) :
262 mContext(this), mEventHub(eventHub), mPolicy(policy),
263 mGlobalMetaState(0), mGeneration(1),
264 mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
265 mConfigurationChangesToRefresh(0) {
266 mQueuedListener = new QueuedInputListener(listener);
271 refreshConfigurationLocked(0);
272 updateGlobalMetaStateLocked();
276 InputReader::~InputReader() {
277 for (size_t i = 0; i < mDevices.size(); i++) {
278 delete mDevices.valueAt(i);
282 void InputReader::loopOnce() {
283 int32_t oldGeneration;
284 int32_t timeoutMillis;
285 bool inputDevicesChanged = false;
286 Vector<InputDeviceInfo> inputDevices;
290 oldGeneration = mGeneration;
293 uint32_t changes = mConfigurationChangesToRefresh;
295 mConfigurationChangesToRefresh = 0;
297 refreshConfigurationLocked(changes);
298 } else if (mNextTimeout != LLONG_MAX) {
299 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
300 timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
304 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
308 mReaderIsAliveCondition.broadcast();
311 processEventsLocked(mEventBuffer, count);
314 if (mNextTimeout != LLONG_MAX) {
315 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
316 if (now >= mNextTimeout) {
318 ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
320 mNextTimeout = LLONG_MAX;
321 timeoutExpiredLocked(now);
325 if (oldGeneration != mGeneration) {
326 inputDevicesChanged = true;
327 getInputDevicesLocked(inputDevices);
331 // Send out a message that the describes the changed input devices.
332 if (inputDevicesChanged) {
333 mPolicy->notifyInputDevicesChanged(inputDevices);
336 // Flush queued events out to the listener.
337 // This must happen outside of the lock because the listener could potentially call
338 // back into the InputReader's methods, such as getScanCodeState, or become blocked
339 // on another thread similarly waiting to acquire the InputReader lock thereby
340 // resulting in a deadlock. This situation is actually quite plausible because the
341 // listener is actually the input dispatcher, which calls into the window manager,
342 // which occasionally calls into the input reader.
343 mQueuedListener->flush();
346 void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
347 for (const RawEvent* rawEvent = rawEvents; count;) {
348 int32_t type = rawEvent->type;
349 size_t batchSize = 1;
350 if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
351 int32_t deviceId = rawEvent->deviceId;
352 while (batchSize < count) {
353 if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
354 || rawEvent[batchSize].deviceId != deviceId) {
360 ALOGD("BatchSize: %d Count: %d", batchSize, count);
362 processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
364 switch (rawEvent->type) {
365 case EventHubInterface::DEVICE_ADDED:
366 addDeviceLocked(rawEvent->when, rawEvent->deviceId);
368 case EventHubInterface::DEVICE_REMOVED:
369 removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
371 case EventHubInterface::FINISHED_DEVICE_SCAN:
372 handleConfigurationChangedLocked(rawEvent->when);
375 ALOG_ASSERT(false); // can't happen
380 rawEvent += batchSize;
384 void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
385 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
386 if (deviceIndex >= 0) {
387 ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
391 InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
392 uint32_t classes = mEventHub->getDeviceClasses(deviceId);
393 int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
395 InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
396 device->configure(when, &mConfig, 0);
399 if (device->isIgnored()) {
400 ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
401 identifier.name.string());
403 ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
404 identifier.name.string(), device->getSources());
407 mDevices.add(deviceId, device);
408 bumpGenerationLocked();
410 if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
411 notifyExternalStylusPresenceChanged();
415 void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
416 InputDevice* device = NULL;
417 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
418 if (deviceIndex < 0) {
419 ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
423 device = mDevices.valueAt(deviceIndex);
424 mDevices.removeItemsAt(deviceIndex, 1);
425 bumpGenerationLocked();
427 if (device->isIgnored()) {
428 ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)",
429 device->getId(), device->getName().string());
431 ALOGI("Device removed: id=%d, name='%s', sources=0x%08x",
432 device->getId(), device->getName().string(), device->getSources());
435 if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
436 notifyExternalStylusPresenceChanged();
443 InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
444 const InputDeviceIdentifier& identifier, uint32_t classes) {
445 InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
446 controllerNumber, identifier, classes);
449 if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
450 device->setExternal(true);
453 // Devices with mics.
454 if (classes & INPUT_DEVICE_CLASS_MIC) {
455 device->setMic(true);
458 // Switch-like devices.
459 if (classes & INPUT_DEVICE_CLASS_SWITCH) {
460 device->addMapper(new SwitchInputMapper(device));
463 // Scroll wheel-like devices.
464 if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
465 device->addMapper(new RotaryEncoderInputMapper(device));
468 // Vibrator-like devices.
469 if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
470 device->addMapper(new VibratorInputMapper(device));
473 // Keyboard-like devices.
474 uint32_t keyboardSource = 0;
475 int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
476 if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
477 keyboardSource |= AINPUT_SOURCE_KEYBOARD;
479 if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
480 keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
482 if (classes & INPUT_DEVICE_CLASS_DPAD) {
483 keyboardSource |= AINPUT_SOURCE_DPAD;
485 if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
486 keyboardSource |= AINPUT_SOURCE_GAMEPAD;
489 if (keyboardSource != 0) {
490 device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
493 // Cursor-like devices.
494 if (classes & INPUT_DEVICE_CLASS_CURSOR) {
495 device->addMapper(new CursorInputMapper(device));
498 // Touchscreens and touchpad devices.
499 if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
500 device->addMapper(new MultiTouchInputMapper(device));
501 } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
502 device->addMapper(new SingleTouchInputMapper(device));
505 // Joystick-like devices.
506 if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
507 device->addMapper(new JoystickInputMapper(device));
510 // External stylus-like devices.
511 if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
512 device->addMapper(new ExternalStylusInputMapper(device));
518 void InputReader::processEventsForDeviceLocked(int32_t deviceId,
519 const RawEvent* rawEvents, size_t count) {
520 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
521 if (deviceIndex < 0) {
522 ALOGW("Discarding event for unknown deviceId %d.", deviceId);
526 InputDevice* device = mDevices.valueAt(deviceIndex);
527 if (device->isIgnored()) {
528 //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
532 device->process(rawEvents, count);
535 void InputReader::timeoutExpiredLocked(nsecs_t when) {
536 for (size_t i = 0; i < mDevices.size(); i++) {
537 InputDevice* device = mDevices.valueAt(i);
538 if (!device->isIgnored()) {
539 device->timeoutExpired(when);
544 void InputReader::handleConfigurationChangedLocked(nsecs_t when) {
545 // Reset global meta state because it depends on the list of all configured devices.
546 updateGlobalMetaStateLocked();
548 // Enqueue configuration changed.
549 NotifyConfigurationChangedArgs args(when);
550 mQueuedListener->notifyConfigurationChanged(&args);
553 void InputReader::refreshConfigurationLocked(uint32_t changes) {
554 mPolicy->getReaderConfiguration(&mConfig);
555 mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
558 ALOGI("Reconfiguring input devices. changes=0x%08x", changes);
559 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
561 if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
562 mEventHub->requestReopenDevices();
564 for (size_t i = 0; i < mDevices.size(); i++) {
565 InputDevice* device = mDevices.valueAt(i);
566 device->configure(now, &mConfig, changes);
572 void InputReader::updateGlobalMetaStateLocked() {
573 mGlobalMetaState = 0;
575 for (size_t i = 0; i < mDevices.size(); i++) {
576 InputDevice* device = mDevices.valueAt(i);
577 mGlobalMetaState |= device->getMetaState();
581 int32_t InputReader::getGlobalMetaStateLocked() {
582 return mGlobalMetaState;
585 void InputReader::notifyExternalStylusPresenceChanged() {
586 refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE);
589 void InputReader::getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices) {
590 for (size_t i = 0; i < mDevices.size(); i++) {
591 InputDevice* device = mDevices.valueAt(i);
592 if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) {
594 device->getDeviceInfo(&outDevices.editTop());
599 void InputReader::dispatchExternalStylusState(const StylusState& state) {
600 for (size_t i = 0; i < mDevices.size(); i++) {
601 InputDevice* device = mDevices.valueAt(i);
602 device->updateExternalStylusState(state);
606 void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) {
607 mDisableVirtualKeysTimeout = time;
610 bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now,
611 InputDevice* device, int32_t keyCode, int32_t scanCode) {
612 if (now < mDisableVirtualKeysTimeout) {
613 ALOGI("Dropping virtual key from device %s because virtual keys are "
614 "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d",
615 device->getName().string(),
616 (mDisableVirtualKeysTimeout - now) * 0.000001,
624 void InputReader::fadePointerLocked() {
625 for (size_t i = 0; i < mDevices.size(); i++) {
626 InputDevice* device = mDevices.valueAt(i);
627 device->fadePointer();
631 void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) {
632 if (when < mNextTimeout) {
638 int32_t InputReader::bumpGenerationLocked() {
639 return ++mGeneration;
642 void InputReader::getInputDevices(Vector<InputDeviceInfo>& outInputDevices) {
644 getInputDevicesLocked(outInputDevices);
647 void InputReader::getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices) {
648 outInputDevices.clear();
650 size_t numDevices = mDevices.size();
651 for (size_t i = 0; i < numDevices; i++) {
652 InputDevice* device = mDevices.valueAt(i);
653 if (!device->isIgnored()) {
654 outInputDevices.push();
655 device->getDeviceInfo(&outInputDevices.editTop());
660 int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
664 return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState);
667 int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask,
671 return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState);
674 int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) {
677 return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState);
680 int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code,
681 GetStateFunc getStateFunc) {
682 int32_t result = AKEY_STATE_UNKNOWN;
684 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
685 if (deviceIndex >= 0) {
686 InputDevice* device = mDevices.valueAt(deviceIndex);
687 if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
688 result = (device->*getStateFunc)(sourceMask, code);
692 size_t numDevices = mDevices.size();
693 for (size_t i = 0; i < numDevices; i++) {
694 InputDevice* device = mDevices.valueAt(i);
695 if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
696 // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
697 // value. Otherwise, return AKEY_STATE_UP as long as one device reports it.
698 int32_t currentResult = (device->*getStateFunc)(sourceMask, code);
699 if (currentResult >= AKEY_STATE_DOWN) {
700 return currentResult;
701 } else if (currentResult == AKEY_STATE_UP) {
702 result = currentResult;
710 void InputReader::toggleCapsLockState(int32_t deviceId) {
711 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
712 if (deviceIndex < 0) {
713 ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId);
717 InputDevice* device = mDevices.valueAt(deviceIndex);
718 if (device->isIgnored()) {
722 device->updateMetaState(AKEYCODE_CAPS_LOCK);
725 bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask,
726 size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
729 memset(outFlags, 0, numCodes);
730 return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags);
733 bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask,
734 size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
737 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
738 if (deviceIndex >= 0) {
739 InputDevice* device = mDevices.valueAt(deviceIndex);
740 if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
741 result = device->markSupportedKeyCodes(sourceMask,
742 numCodes, keyCodes, outFlags);
746 size_t numDevices = mDevices.size();
747 for (size_t i = 0; i < numDevices; i++) {
748 InputDevice* device = mDevices.valueAt(i);
749 if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
750 result |= device->markSupportedKeyCodes(sourceMask,
751 numCodes, keyCodes, outFlags);
758 void InputReader::requestRefreshConfiguration(uint32_t changes) {
762 bool needWake = !mConfigurationChangesToRefresh;
763 mConfigurationChangesToRefresh |= changes;
771 void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
772 ssize_t repeat, int32_t token) {
775 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
776 if (deviceIndex >= 0) {
777 InputDevice* device = mDevices.valueAt(deviceIndex);
778 device->vibrate(pattern, patternSize, repeat, token);
782 void InputReader::cancelVibrate(int32_t deviceId, int32_t token) {
785 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
786 if (deviceIndex >= 0) {
787 InputDevice* device = mDevices.valueAt(deviceIndex);
788 device->cancelVibrate(token);
792 void InputReader::dump(String8& dump) {
795 mEventHub->dump(dump);
798 dump.append("Input Reader State:\n");
800 for (size_t i = 0; i < mDevices.size(); i++) {
801 mDevices.valueAt(i)->dump(dump);
804 dump.append(INDENT "Configuration:\n");
805 dump.append(INDENT2 "ExcludedDeviceNames: [");
806 for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) {
810 dump.append(mConfig.excludedDeviceNames.itemAt(i).string());
813 dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
814 mConfig.virtualKeyQuietTime * 0.000001f);
816 dump.appendFormat(INDENT2 "PointerVelocityControlParameters: "
817 "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
818 mConfig.pointerVelocityControlParameters.scale,
819 mConfig.pointerVelocityControlParameters.lowThreshold,
820 mConfig.pointerVelocityControlParameters.highThreshold,
821 mConfig.pointerVelocityControlParameters.acceleration);
823 dump.appendFormat(INDENT2 "WheelVelocityControlParameters: "
824 "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
825 mConfig.wheelVelocityControlParameters.scale,
826 mConfig.wheelVelocityControlParameters.lowThreshold,
827 mConfig.wheelVelocityControlParameters.highThreshold,
828 mConfig.wheelVelocityControlParameters.acceleration);
830 dump.appendFormat(INDENT2 "PointerGesture:\n");
831 dump.appendFormat(INDENT3 "Enabled: %s\n",
832 toString(mConfig.pointerGesturesEnabled));
833 dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n",
834 mConfig.pointerGestureQuietInterval * 0.000001f);
835 dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n",
836 mConfig.pointerGestureDragMinSwitchSpeed);
837 dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n",
838 mConfig.pointerGestureTapInterval * 0.000001f);
839 dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n",
840 mConfig.pointerGestureTapDragInterval * 0.000001f);
841 dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n",
842 mConfig.pointerGestureTapSlop);
843 dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
844 mConfig.pointerGestureMultitouchSettleInterval * 0.000001f);
845 dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n",
846 mConfig.pointerGestureMultitouchMinDistance);
847 dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
848 mConfig.pointerGestureSwipeTransitionAngleCosine);
849 dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
850 mConfig.pointerGestureSwipeMaxWidthRatio);
851 dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n",
852 mConfig.pointerGestureMovementSpeedRatio);
853 dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n",
854 mConfig.pointerGestureZoomSpeedRatio);
857 void InputReader::monitor() {
858 // Acquire and release the lock to ensure that the reader has not deadlocked.
861 mReaderIsAliveCondition.wait(mLock);
864 // Check the EventHub
865 mEventHub->monitor();
869 // --- InputReader::ContextImpl ---
871 InputReader::ContextImpl::ContextImpl(InputReader* reader) :
875 void InputReader::ContextImpl::updateGlobalMetaState() {
876 // lock is already held by the input loop
877 mReader->updateGlobalMetaStateLocked();
880 int32_t InputReader::ContextImpl::getGlobalMetaState() {
881 // lock is already held by the input loop
882 return mReader->getGlobalMetaStateLocked();
885 void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) {
886 // lock is already held by the input loop
887 mReader->disableVirtualKeysUntilLocked(time);
890 bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now,
891 InputDevice* device, int32_t keyCode, int32_t scanCode) {
892 // lock is already held by the input loop
893 return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode);
896 void InputReader::ContextImpl::fadePointer() {
897 // lock is already held by the input loop
898 mReader->fadePointerLocked();
901 void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) {
902 // lock is already held by the input loop
903 mReader->requestTimeoutAtTimeLocked(when);
906 int32_t InputReader::ContextImpl::bumpGeneration() {
907 // lock is already held by the input loop
908 return mReader->bumpGenerationLocked();
911 void InputReader::ContextImpl::getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
912 // lock is already held by whatever called refreshConfigurationLocked
913 mReader->getExternalStylusDevicesLocked(outDevices);
916 void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) {
917 mReader->dispatchExternalStylusState(state);
920 InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() {
921 return mReader->mPolicy.get();
924 InputListenerInterface* InputReader::ContextImpl::getListener() {
925 return mReader->mQueuedListener.get();
928 EventHubInterface* InputReader::ContextImpl::getEventHub() {
929 return mReader->mEventHub.get();
933 // --- InputReaderThread ---
935 InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
936 Thread(/*canCallJava*/ true), mReader(reader) {
939 InputReaderThread::~InputReaderThread() {
942 bool InputReaderThread::threadLoop() {
948 // --- InputDevice ---
950 InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
951 int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) :
952 mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber),
953 mIdentifier(identifier), mClasses(classes),
954 mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) {
957 InputDevice::~InputDevice() {
958 size_t numMappers = mMappers.size();
959 for (size_t i = 0; i < numMappers; i++) {
965 void InputDevice::dump(String8& dump) {
966 InputDeviceInfo deviceInfo;
967 getDeviceInfo(& deviceInfo);
969 dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(),
970 deviceInfo.getDisplayName().string());
971 dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration);
972 dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
973 dump.appendFormat(INDENT2 "HasMic: %s\n", toString(mHasMic));
974 dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
975 dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
977 const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
978 if (!ranges.isEmpty()) {
979 dump.append(INDENT2 "Motion Ranges:\n");
980 for (size_t i = 0; i < ranges.size(); i++) {
981 const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
982 const char* label = getAxisLabel(range.axis);
985 strncpy(name, label, sizeof(name));
986 name[sizeof(name) - 1] = '\0';
988 snprintf(name, sizeof(name), "%d", range.axis);
990 dump.appendFormat(INDENT3 "%s: source=0x%08x, "
991 "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
992 name, range.source, range.min, range.max, range.flat, range.fuzz,
997 size_t numMappers = mMappers.size();
998 for (size_t i = 0; i < numMappers; i++) {
999 InputMapper* mapper = mMappers[i];
1004 void InputDevice::addMapper(InputMapper* mapper) {
1005 mMappers.add(mapper);
1008 void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) {
1012 if (!changes) { // first time only
1013 mContext->getEventHub()->getConfiguration(mId, &mConfiguration);
1016 if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
1017 if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
1018 sp<KeyCharacterMap> keyboardLayout =
1019 mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier);
1020 if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) {
1026 if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) {
1027 if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
1028 String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
1029 if (mAlias != alias) {
1036 size_t numMappers = mMappers.size();
1037 for (size_t i = 0; i < numMappers; i++) {
1038 InputMapper* mapper = mMappers[i];
1039 mapper->configure(when, config, changes);
1040 mSources |= mapper->getSources();
1045 void InputDevice::reset(nsecs_t when) {
1046 size_t numMappers = mMappers.size();
1047 for (size_t i = 0; i < numMappers; i++) {
1048 InputMapper* mapper = mMappers[i];
1049 mapper->reset(when);
1052 mContext->updateGlobalMetaState();
1057 void InputDevice::process(const RawEvent* rawEvents, size_t count) {
1058 // Process all of the events in order for each mapper.
1059 // We cannot simply ask each mapper to process them in bulk because mappers may
1060 // have side-effects that must be interleaved. For example, joystick movement events and
1061 // gamepad button presses are handled by different mappers but they should be dispatched
1062 // in the order received.
1063 size_t numMappers = mMappers.size();
1064 for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
1065 #if DEBUG_RAW_EVENTS
1066 ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
1067 rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
1071 if (mDropUntilNextSync) {
1072 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
1073 mDropUntilNextSync = false;
1074 #if DEBUG_RAW_EVENTS
1075 ALOGD("Recovered from input event buffer overrun.");
1078 #if DEBUG_RAW_EVENTS
1079 ALOGD("Dropped input event while waiting for next input sync.");
1082 } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
1083 ALOGI("Detected input event buffer overrun for device %s.", getName().string());
1084 mDropUntilNextSync = true;
1085 reset(rawEvent->when);
1087 for (size_t i = 0; i < numMappers; i++) {
1088 InputMapper* mapper = mMappers[i];
1089 mapper->process(rawEvent);
1095 void InputDevice::timeoutExpired(nsecs_t when) {
1096 size_t numMappers = mMappers.size();
1097 for (size_t i = 0; i < numMappers; i++) {
1098 InputMapper* mapper = mMappers[i];
1099 mapper->timeoutExpired(when);
1103 void InputDevice::updateExternalStylusState(const StylusState& state) {
1104 size_t numMappers = mMappers.size();
1105 for (size_t i = 0; i < numMappers; i++) {
1106 InputMapper* mapper = mMappers[i];
1107 mapper->updateExternalStylusState(state);
1111 void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
1112 outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias,
1113 mIsExternal, mHasMic);
1114 size_t numMappers = mMappers.size();
1115 for (size_t i = 0; i < numMappers; i++) {
1116 InputMapper* mapper = mMappers[i];
1117 mapper->populateDeviceInfo(outDeviceInfo);
1121 int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
1122 return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState);
1125 int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
1126 return getState(sourceMask, scanCode, & InputMapper::getScanCodeState);
1129 int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
1130 return getState(sourceMask, switchCode, & InputMapper::getSwitchState);
1133 int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
1134 int32_t result = AKEY_STATE_UNKNOWN;
1135 size_t numMappers = mMappers.size();
1136 for (size_t i = 0; i < numMappers; i++) {
1137 InputMapper* mapper = mMappers[i];
1138 if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
1139 // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
1140 // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
1141 int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code);
1142 if (currentResult >= AKEY_STATE_DOWN) {
1143 return currentResult;
1144 } else if (currentResult == AKEY_STATE_UP) {
1145 result = currentResult;
1152 bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
1153 const int32_t* keyCodes, uint8_t* outFlags) {
1154 bool result = false;
1155 size_t numMappers = mMappers.size();
1156 for (size_t i = 0; i < numMappers; i++) {
1157 InputMapper* mapper = mMappers[i];
1158 if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
1159 result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
1165 void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
1167 size_t numMappers = mMappers.size();
1168 for (size_t i = 0; i < numMappers; i++) {
1169 InputMapper* mapper = mMappers[i];
1170 mapper->vibrate(pattern, patternSize, repeat, token);
1174 void InputDevice::cancelVibrate(int32_t token) {
1175 size_t numMappers = mMappers.size();
1176 for (size_t i = 0; i < numMappers; i++) {
1177 InputMapper* mapper = mMappers[i];
1178 mapper->cancelVibrate(token);
1182 void InputDevice::cancelTouch(nsecs_t when) {
1183 size_t numMappers = mMappers.size();
1184 for (size_t i = 0; i < numMappers; i++) {
1185 InputMapper* mapper = mMappers[i];
1186 mapper->cancelTouch(when);
1190 int32_t InputDevice::getMetaState() {
1192 size_t numMappers = mMappers.size();
1193 for (size_t i = 0; i < numMappers; i++) {
1194 InputMapper* mapper = mMappers[i];
1195 result |= mapper->getMetaState();
1200 void InputDevice::updateMetaState(int32_t keyCode) {
1201 size_t numMappers = mMappers.size();
1202 for (size_t i = 0; i < numMappers; i++) {
1203 mMappers[i]->updateMetaState(keyCode);
1207 void InputDevice::fadePointer() {
1208 size_t numMappers = mMappers.size();
1209 for (size_t i = 0; i < numMappers; i++) {
1210 InputMapper* mapper = mMappers[i];
1211 mapper->fadePointer();
1215 void InputDevice::bumpGeneration() {
1216 mGeneration = mContext->bumpGeneration();
1219 void InputDevice::notifyReset(nsecs_t when) {
1220 NotifyDeviceResetArgs args(when, mId);
1221 mContext->getListener()->notifyDeviceReset(&args);
1225 // --- CursorButtonAccumulator ---
1227 CursorButtonAccumulator::CursorButtonAccumulator() {
1231 void CursorButtonAccumulator::reset(InputDevice* device) {
1232 mBtnLeft = device->isKeyPressed(BTN_LEFT);
1233 mBtnRight = device->isKeyPressed(BTN_RIGHT);
1234 mBtnMiddle = device->isKeyPressed(BTN_MIDDLE);
1235 mBtnBack = device->isKeyPressed(BTN_BACK);
1236 mBtnSide = device->isKeyPressed(BTN_SIDE);
1237 mBtnForward = device->isKeyPressed(BTN_FORWARD);
1238 mBtnExtra = device->isKeyPressed(BTN_EXTRA);
1239 mBtnTask = device->isKeyPressed(BTN_TASK);
1242 void CursorButtonAccumulator::clearButtons() {
1253 void CursorButtonAccumulator::process(const RawEvent* rawEvent) {
1254 if (rawEvent->type == EV_KEY) {
1255 switch (rawEvent->code) {
1257 mBtnLeft = rawEvent->value;
1260 mBtnRight = rawEvent->value;
1263 mBtnMiddle = rawEvent->value;
1266 mBtnBack = rawEvent->value;
1269 mBtnSide = rawEvent->value;
1272 mBtnForward = rawEvent->value;
1275 mBtnExtra = rawEvent->value;
1278 mBtnTask = rawEvent->value;
1284 uint32_t CursorButtonAccumulator::getButtonState() const {
1285 uint32_t result = 0;
1287 result |= AMOTION_EVENT_BUTTON_PRIMARY;
1290 result |= AMOTION_EVENT_BUTTON_SECONDARY;
1293 result |= AMOTION_EVENT_BUTTON_TERTIARY;
1295 if (mBtnBack || mBtnSide) {
1296 result |= AMOTION_EVENT_BUTTON_BACK;
1298 if (mBtnForward || mBtnExtra) {
1299 result |= AMOTION_EVENT_BUTTON_FORWARD;
1305 // --- CursorMotionAccumulator ---
1307 CursorMotionAccumulator::CursorMotionAccumulator() {
1308 clearRelativeAxes();
1311 void CursorMotionAccumulator::reset(InputDevice* device) {
1312 clearRelativeAxes();
1315 void CursorMotionAccumulator::clearRelativeAxes() {
1320 void CursorMotionAccumulator::process(const RawEvent* rawEvent) {
1321 if (rawEvent->type == EV_REL) {
1322 switch (rawEvent->code) {
1324 mRelX = rawEvent->value;
1327 mRelY = rawEvent->value;
1333 void CursorMotionAccumulator::finishSync() {
1334 clearRelativeAxes();
1338 // --- CursorScrollAccumulator ---
1340 CursorScrollAccumulator::CursorScrollAccumulator() :
1341 mHaveRelWheel(false), mHaveRelHWheel(false) {
1342 clearRelativeAxes();
1345 void CursorScrollAccumulator::configure(InputDevice* device) {
1346 mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL);
1347 mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL);
1350 void CursorScrollAccumulator::reset(InputDevice* device) {
1351 clearRelativeAxes();
1354 void CursorScrollAccumulator::clearRelativeAxes() {
1359 void CursorScrollAccumulator::process(const RawEvent* rawEvent) {
1360 if (rawEvent->type == EV_REL) {
1361 switch (rawEvent->code) {
1363 mRelWheel = rawEvent->value;
1366 mRelHWheel = rawEvent->value;
1372 void CursorScrollAccumulator::finishSync() {
1373 clearRelativeAxes();
1377 // --- TouchButtonAccumulator ---
1379 TouchButtonAccumulator::TouchButtonAccumulator() :
1380 mHaveBtnTouch(false), mHaveStylus(false) {
1384 void TouchButtonAccumulator::configure(InputDevice* device) {
1385 mHaveBtnTouch = device->hasKey(BTN_TOUCH);
1386 mHaveStylus = device->hasKey(BTN_TOOL_PEN)
1387 || device->hasKey(BTN_TOOL_RUBBER)
1388 || device->hasKey(BTN_TOOL_BRUSH)
1389 || device->hasKey(BTN_TOOL_PENCIL)
1390 || device->hasKey(BTN_TOOL_AIRBRUSH);
1393 void TouchButtonAccumulator::reset(InputDevice* device) {
1394 mBtnTouch = device->isKeyPressed(BTN_TOUCH);
1395 mBtnStylus = device->isKeyPressed(BTN_STYLUS);
1396 // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch
1398 device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0);
1399 mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER);
1400 mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN);
1401 mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER);
1402 mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH);
1403 mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL);
1404 mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH);
1405 mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE);
1406 mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS);
1407 mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP);
1408 mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP);
1409 mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP);
1412 void TouchButtonAccumulator::clearButtons() {
1421 mBtnToolAirbrush = 0;
1424 mBtnToolDoubleTap = 0;
1425 mBtnToolTripleTap = 0;
1426 mBtnToolQuadTap = 0;
1429 void TouchButtonAccumulator::process(const RawEvent* rawEvent) {
1430 if (rawEvent->type == EV_KEY) {
1431 switch (rawEvent->code) {
1433 mBtnTouch = rawEvent->value;
1436 mBtnStylus = rawEvent->value;
1439 case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch
1440 mBtnStylus2 = rawEvent->value;
1442 case BTN_TOOL_FINGER:
1443 mBtnToolFinger = rawEvent->value;
1446 mBtnToolPen = rawEvent->value;
1448 case BTN_TOOL_RUBBER:
1449 mBtnToolRubber = rawEvent->value;
1451 case BTN_TOOL_BRUSH:
1452 mBtnToolBrush = rawEvent->value;
1454 case BTN_TOOL_PENCIL:
1455 mBtnToolPencil = rawEvent->value;
1457 case BTN_TOOL_AIRBRUSH:
1458 mBtnToolAirbrush = rawEvent->value;
1460 case BTN_TOOL_MOUSE:
1461 mBtnToolMouse = rawEvent->value;
1464 mBtnToolLens = rawEvent->value;
1466 case BTN_TOOL_DOUBLETAP:
1467 mBtnToolDoubleTap = rawEvent->value;
1469 case BTN_TOOL_TRIPLETAP:
1470 mBtnToolTripleTap = rawEvent->value;
1472 case BTN_TOOL_QUADTAP:
1473 mBtnToolQuadTap = rawEvent->value;
1479 uint32_t TouchButtonAccumulator::getButtonState() const {
1480 uint32_t result = 0;
1482 result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY;
1485 result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY;
1490 int32_t TouchButtonAccumulator::getToolType() const {
1491 if (mBtnToolMouse || mBtnToolLens) {
1492 return AMOTION_EVENT_TOOL_TYPE_MOUSE;
1494 if (mBtnToolRubber) {
1495 return AMOTION_EVENT_TOOL_TYPE_ERASER;
1497 if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) {
1498 return AMOTION_EVENT_TOOL_TYPE_STYLUS;
1500 if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) {
1501 return AMOTION_EVENT_TOOL_TYPE_FINGER;
1503 return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
1506 bool TouchButtonAccumulator::isToolActive() const {
1507 return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber
1508 || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush
1509 || mBtnToolMouse || mBtnToolLens
1510 || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap;
1513 bool TouchButtonAccumulator::isHovering() const {
1514 return mHaveBtnTouch && !mBtnTouch;
1517 bool TouchButtonAccumulator::hasStylus() const {
1522 // --- RawPointerAxes ---
1524 RawPointerAxes::RawPointerAxes() {
1528 void RawPointerAxes::clear() {
1536 orientation.clear();
1545 // --- RawPointerData ---
1547 RawPointerData::RawPointerData() {
1551 void RawPointerData::clear() {
1556 void RawPointerData::copyFrom(const RawPointerData& other) {
1557 pointerCount = other.pointerCount;
1558 hoveringIdBits = other.hoveringIdBits;
1559 touchingIdBits = other.touchingIdBits;
1561 for (uint32_t i = 0; i < pointerCount; i++) {
1562 pointers[i] = other.pointers[i];
1564 int id = pointers[i].id;
1565 idToIndex[id] = other.idToIndex[id];
1569 void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const {
1571 uint32_t count = touchingIdBits.count();
1573 for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty(); ) {
1574 uint32_t id = idBits.clearFirstMarkedBit();
1575 const Pointer& pointer = pointerForId(id);
1587 // --- CookedPointerData ---
1589 CookedPointerData::CookedPointerData() {
1593 void CookedPointerData::clear() {
1595 hoveringIdBits.clear();
1596 touchingIdBits.clear();
1599 void CookedPointerData::copyFrom(const CookedPointerData& other) {
1600 pointerCount = other.pointerCount;
1601 hoveringIdBits = other.hoveringIdBits;
1602 touchingIdBits = other.touchingIdBits;
1604 for (uint32_t i = 0; i < pointerCount; i++) {
1605 pointerProperties[i].copyFrom(other.pointerProperties[i]);
1606 pointerCoords[i].copyFrom(other.pointerCoords[i]);
1608 int id = pointerProperties[i].id;
1609 idToIndex[id] = other.idToIndex[id];
1614 // --- SingleTouchMotionAccumulator ---
1616 SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() {
1617 clearAbsoluteAxes();
1620 void SingleTouchMotionAccumulator::reset(InputDevice* device) {
1621 mAbsX = device->getAbsoluteAxisValue(ABS_X);
1622 mAbsY = device->getAbsoluteAxisValue(ABS_Y);
1623 mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE);
1624 mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH);
1625 mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE);
1626 mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X);
1627 mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y);
1630 void SingleTouchMotionAccumulator::clearAbsoluteAxes() {
1640 void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) {
1641 if (rawEvent->type == EV_ABS) {
1642 switch (rawEvent->code) {
1644 mAbsX = rawEvent->value;
1647 mAbsY = rawEvent->value;
1650 mAbsPressure = rawEvent->value;
1652 case ABS_TOOL_WIDTH:
1653 mAbsToolWidth = rawEvent->value;
1656 mAbsDistance = rawEvent->value;
1659 mAbsTiltX = rawEvent->value;
1662 mAbsTiltY = rawEvent->value;
1669 // --- MultiTouchMotionAccumulator ---
1671 MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() :
1672 mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false),
1673 mHaveStylus(false) {
1676 MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() {
1680 void MultiTouchMotionAccumulator::configure(InputDevice* device,
1681 size_t slotCount, bool usingSlotsProtocol) {
1682 mSlotCount = slotCount;
1683 mUsingSlotsProtocol = usingSlotsProtocol;
1684 mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
1687 mSlots = new Slot[slotCount];
1690 void MultiTouchMotionAccumulator::reset(InputDevice* device) {
1691 // Unfortunately there is no way to read the initial contents of the slots.
1692 // So when we reset the accumulator, we must assume they are all zeroes.
1693 if (mUsingSlotsProtocol) {
1694 // Query the driver for the current slot index and use it as the initial slot
1695 // before we start reading events from the device. It is possible that the
1696 // current slot index will not be the same as it was when the first event was
1697 // written into the evdev buffer, which means the input mapper could start
1698 // out of sync with the initial state of the events in the evdev buffer.
1699 // In the extremely unlikely case that this happens, the data from
1700 // two slots will be confused until the next ABS_MT_SLOT event is received.
1701 // This can cause the touch point to "jump", but at least there will be
1702 // no stuck touches.
1703 int32_t initialSlot;
1704 status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(),
1705 ABS_MT_SLOT, &initialSlot);
1707 ALOGD("Could not retrieve current multitouch slot index. status=%d", status);
1710 clearSlots(initialSlot);
1716 void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
1718 for (size_t i = 0; i < mSlotCount; i++) {
1722 mCurrentSlot = initialSlot;
1725 void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
1726 if (rawEvent->type == EV_ABS) {
1727 bool newSlot = false;
1728 if (mUsingSlotsProtocol) {
1729 if (rawEvent->code == ABS_MT_SLOT) {
1730 mCurrentSlot = rawEvent->value;
1733 } else if (mCurrentSlot < 0) {
1737 if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
1740 ALOGW("MultiTouch device emitted invalid slot index %d but it "
1741 "should be between 0 and %d; ignoring this slot.",
1742 mCurrentSlot, mSlotCount - 1);
1746 Slot* slot = &mSlots[mCurrentSlot];
1748 switch (rawEvent->code) {
1749 case ABS_MT_POSITION_X:
1750 slot->mInUse = true;
1751 slot->mAbsMTPositionX = rawEvent->value;
1753 case ABS_MT_POSITION_Y:
1754 slot->mInUse = true;
1755 slot->mAbsMTPositionY = rawEvent->value;
1757 case ABS_MT_TOUCH_MAJOR:
1758 slot->mInUse = true;
1759 slot->mAbsMTTouchMajor = rawEvent->value;
1761 case ABS_MT_TOUCH_MINOR:
1762 slot->mInUse = true;
1763 slot->mAbsMTTouchMinor = rawEvent->value;
1764 slot->mHaveAbsMTTouchMinor = true;
1766 case ABS_MT_WIDTH_MAJOR:
1767 slot->mInUse = true;
1768 slot->mAbsMTWidthMajor = rawEvent->value;
1770 case ABS_MT_WIDTH_MINOR:
1771 slot->mInUse = true;
1772 slot->mAbsMTWidthMinor = rawEvent->value;
1773 slot->mHaveAbsMTWidthMinor = true;
1775 case ABS_MT_ORIENTATION:
1776 slot->mInUse = true;
1777 slot->mAbsMTOrientation = rawEvent->value;
1779 case ABS_MT_TRACKING_ID:
1780 if (mUsingSlotsProtocol && rawEvent->value < 0) {
1781 // The slot is no longer in use but it retains its previous contents,
1782 // which may be reused for subsequent touches.
1783 slot->mInUse = false;
1785 slot->mInUse = true;
1786 slot->mAbsMTTrackingId = rawEvent->value;
1789 case ABS_MT_PRESSURE:
1790 slot->mInUse = true;
1791 slot->mAbsMTPressure = rawEvent->value;
1793 case ABS_MT_DISTANCE:
1794 slot->mInUse = true;
1795 slot->mAbsMTDistance = rawEvent->value;
1797 case ABS_MT_TOOL_TYPE:
1798 slot->mInUse = true;
1799 slot->mAbsMTToolType = rawEvent->value;
1800 slot->mHaveAbsMTToolType = true;
1804 } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
1805 // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
1810 void MultiTouchMotionAccumulator::finishSync() {
1811 if (!mUsingSlotsProtocol) {
1816 bool MultiTouchMotionAccumulator::hasStylus() const {
1821 // --- MultiTouchMotionAccumulator::Slot ---
1823 MultiTouchMotionAccumulator::Slot::Slot() {
1827 void MultiTouchMotionAccumulator::Slot::clear() {
1829 mHaveAbsMTTouchMinor = false;
1830 mHaveAbsMTWidthMinor = false;
1831 mHaveAbsMTToolType = false;
1832 mAbsMTPositionX = 0;
1833 mAbsMTPositionY = 0;
1834 mAbsMTTouchMajor = 0;
1835 mAbsMTTouchMinor = 0;
1836 mAbsMTWidthMajor = 0;
1837 mAbsMTWidthMinor = 0;
1838 mAbsMTOrientation = 0;
1839 mAbsMTTrackingId = -1;
1845 int32_t MultiTouchMotionAccumulator::Slot::getToolType() const {
1846 if (mHaveAbsMTToolType) {
1847 switch (mAbsMTToolType) {
1848 case MT_TOOL_FINGER:
1849 return AMOTION_EVENT_TOOL_TYPE_FINGER;
1851 return AMOTION_EVENT_TOOL_TYPE_STYLUS;
1854 return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
1858 // --- InputMapper ---
1860 InputMapper::InputMapper(InputDevice* device) :
1861 mDevice(device), mContext(device->getContext()) {
1864 InputMapper::~InputMapper() {
1867 void InputMapper::populateDeviceInfo(InputDeviceInfo* info) {
1868 info->addSource(getSources());
1871 void InputMapper::dump(String8& dump) {
1874 void InputMapper::configure(nsecs_t when,
1875 const InputReaderConfiguration* config, uint32_t changes) {
1878 void InputMapper::reset(nsecs_t when) {
1881 void InputMapper::timeoutExpired(nsecs_t when) {
1884 int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
1885 return AKEY_STATE_UNKNOWN;
1888 int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
1889 return AKEY_STATE_UNKNOWN;
1892 int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
1893 return AKEY_STATE_UNKNOWN;
1896 bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
1897 const int32_t* keyCodes, uint8_t* outFlags) {
1901 void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
1905 void InputMapper::cancelVibrate(int32_t token) {
1908 void InputMapper::cancelTouch(nsecs_t when) {
1911 int32_t InputMapper::getMetaState() {
1915 void InputMapper::updateMetaState(int32_t keyCode) {
1918 void InputMapper::updateExternalStylusState(const StylusState& state) {
1922 void InputMapper::fadePointer() {
1925 status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) {
1926 return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo);
1929 void InputMapper::bumpGeneration() {
1930 mDevice->bumpGeneration();
1933 void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump,
1934 const RawAbsoluteAxisInfo& axis, const char* name) {
1936 dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n",
1937 name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution);
1939 dump.appendFormat(INDENT4 "%s: unknown range\n", name);
1943 void InputMapper::dumpStylusState(String8& dump, const StylusState& state) {
1944 dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when);
1945 dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure);
1946 dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons);
1947 dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType);
1950 // --- SwitchInputMapper ---
1952 SwitchInputMapper::SwitchInputMapper(InputDevice* device) :
1953 InputMapper(device), mSwitchValues(0), mUpdatedSwitchMask(0) {
1956 SwitchInputMapper::~SwitchInputMapper() {
1959 uint32_t SwitchInputMapper::getSources() {
1960 return AINPUT_SOURCE_SWITCH;
1963 void SwitchInputMapper::process(const RawEvent* rawEvent) {
1964 switch (rawEvent->type) {
1966 processSwitch(rawEvent->code, rawEvent->value);
1970 if (rawEvent->code == SYN_REPORT) {
1971 sync(rawEvent->when);
1976 void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
1977 if (switchCode >= 0 && switchCode < 32) {
1979 mSwitchValues |= 1 << switchCode;
1981 mSwitchValues &= ~(1 << switchCode);
1983 mUpdatedSwitchMask |= 1 << switchCode;
1987 void SwitchInputMapper::sync(nsecs_t when) {
1988 if (mUpdatedSwitchMask) {
1989 uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
1990 NotifySwitchArgs args(when, 0, updatedSwitchValues, mUpdatedSwitchMask);
1991 getListener()->notifySwitch(&args);
1993 mUpdatedSwitchMask = 0;
1997 int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
1998 return getEventHub()->getSwitchState(getDeviceId(), switchCode);
2001 void SwitchInputMapper::dump(String8& dump) {
2002 dump.append(INDENT2 "Switch Input Mapper:\n");
2003 dump.appendFormat(INDENT3 "SwitchValues: %x\n", mSwitchValues);
2006 // --- VibratorInputMapper ---
2008 VibratorInputMapper::VibratorInputMapper(InputDevice* device) :
2009 InputMapper(device), mVibrating(false) {
2012 VibratorInputMapper::~VibratorInputMapper() {
2015 uint32_t VibratorInputMapper::getSources() {
2019 void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
2020 InputMapper::populateDeviceInfo(info);
2022 info->setVibrator(true);
2025 void VibratorInputMapper::process(const RawEvent* rawEvent) {
2026 // TODO: Handle FF_STATUS, although it does not seem to be widely supported.
2029 void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
2033 for (size_t i = 0; i < patternSize; i++) {
2035 patternStr.append(", ");
2037 patternStr.appendFormat("%lld", pattern[i]);
2039 ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d",
2040 getDeviceId(), patternStr.string(), repeat, token);
2044 memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t));
2045 mPatternSize = patternSize;
2053 void VibratorInputMapper::cancelVibrate(int32_t token) {
2055 ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token);
2058 if (mVibrating && mToken == token) {
2063 void VibratorInputMapper::timeoutExpired(nsecs_t when) {
2065 if (when >= mNextStepTime) {
2068 getContext()->requestTimeoutAtTime(mNextStepTime);
2073 void VibratorInputMapper::nextStep() {
2075 if (size_t(mIndex) >= mPatternSize) {
2084 bool vibratorOn = mIndex & 1;
2085 nsecs_t duration = mPattern[mIndex];
2088 ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld",
2089 getDeviceId(), duration);
2091 getEventHub()->vibrate(getDeviceId(), duration);
2094 ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId());
2096 getEventHub()->cancelVibrate(getDeviceId());
2098 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
2099 mNextStepTime = now + duration;
2100 getContext()->requestTimeoutAtTime(mNextStepTime);
2102 ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f);
2106 void VibratorInputMapper::stopVibrating() {
2109 ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId());
2111 getEventHub()->cancelVibrate(getDeviceId());
2114 void VibratorInputMapper::dump(String8& dump) {
2115 dump.append(INDENT2 "Vibrator Input Mapper:\n");
2116 dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating));
2120 // --- KeyboardInputMapper ---
2122 KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
2123 uint32_t source, int32_t keyboardType) :
2124 InputMapper(device), mSource(source),
2125 mKeyboardType(keyboardType) {
2128 KeyboardInputMapper::~KeyboardInputMapper() {
2131 uint32_t KeyboardInputMapper::getSources() {
2135 void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
2136 InputMapper::populateDeviceInfo(info);
2138 info->setKeyboardType(mKeyboardType);
2139 info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId()));
2142 void KeyboardInputMapper::dump(String8& dump) {
2143 dump.append(INDENT2 "Keyboard Input Mapper:\n");
2144 dumpParameters(dump);
2145 dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType);
2146 dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
2147 dump.appendFormat(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
2148 dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState);
2149 dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime);
2153 void KeyboardInputMapper::configure(nsecs_t when,
2154 const InputReaderConfiguration* config, uint32_t changes) {
2155 InputMapper::configure(when, config, changes);
2157 if (!changes) { // first time only
2158 // Configure basic parameters.
2159 configureParameters();
2162 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
2163 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
2165 if (config->getDisplayInfo(false /*external*/, &v)) {
2166 mOrientation = v.orientation;
2168 mOrientation = DISPLAY_ORIENTATION_0;
2171 mOrientation = DISPLAY_ORIENTATION_0;
2174 if (!changes || (changes & InputReaderConfiguration::CHANGE_VOLUME_KEYS_ROTATION)) {
2175 // mode 0 (disabled) ~ offset 4
2176 // mode 1 (phone) ~ offset 2
2177 // mode 2 (tablet) ~ offset 0
2178 mRotationMapOffset = 4 - 2 * config->volumeKeysRotationMode;
2182 void KeyboardInputMapper::configureParameters() {
2183 mParameters.orientationAware = !getDevice()->isExternal();
2184 getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
2185 mParameters.orientationAware);
2187 mParameters.hasAssociatedDisplay = false;
2188 if (mParameters.orientationAware) {
2189 mParameters.hasAssociatedDisplay = true;
2192 mParameters.handlesKeyRepeat = false;
2193 getDevice()->getConfiguration().tryGetProperty(String8("keyboard.handlesKeyRepeat"),
2194 mParameters.handlesKeyRepeat);
2197 void KeyboardInputMapper::dumpParameters(String8& dump) {
2198 dump.append(INDENT3 "Parameters:\n");
2199 dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
2200 toString(mParameters.hasAssociatedDisplay));
2201 dump.appendFormat(INDENT4 "OrientationAware: %s\n",
2202 toString(mParameters.orientationAware));
2203 dump.appendFormat(INDENT4 "HandlesKeyRepeat: %s\n",
2204 toString(mParameters.handlesKeyRepeat));
2207 void KeyboardInputMapper::reset(nsecs_t when) {
2208 mMetaState = AMETA_NONE;
2211 mCurrentHidUsage = 0;
2215 InputMapper::reset(when);
2218 void KeyboardInputMapper::process(const RawEvent* rawEvent) {
2219 switch (rawEvent->type) {
2221 int32_t scanCode = rawEvent->code;
2222 int32_t usageCode = mCurrentHidUsage;
2223 mCurrentHidUsage = 0;
2225 if (isKeyboardOrGamepadKey(scanCode)) {
2226 processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
2231 if (rawEvent->code == MSC_SCAN) {
2232 mCurrentHidUsage = rawEvent->value;
2237 if (rawEvent->code == SYN_REPORT) {
2238 mCurrentHidUsage = 0;
2244 bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
2245 return scanCode < BTN_MOUSE
2246 || scanCode >= KEY_OK
2247 || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE)
2248 || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
2251 void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
2252 int32_t usageCode) {
2254 int32_t keyMetaState;
2255 uint32_t policyFlags;
2257 if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
2258 &keyCode, &keyMetaState, &policyFlags)) {
2259 keyCode = AKEYCODE_UNKNOWN;
2260 keyMetaState = mMetaState;
2265 // Rotate key codes according to orientation if needed.
2266 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
2267 keyCode = rotateKeyCode(keyCode, mOrientation, mRotationMapOffset);
2271 ssize_t keyDownIndex = findKeyDown(scanCode);
2272 if (keyDownIndex >= 0) {
2273 // key repeat, be sure to use same keycode as before in case of rotation
2274 keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
2277 if ((policyFlags & POLICY_FLAG_VIRTUAL)
2278 && mContext->shouldDropVirtualKey(when,
2279 getDevice(), keyCode, scanCode)) {
2282 if (policyFlags & POLICY_FLAG_GESTURE) {
2283 mDevice->cancelTouch(when);
2287 KeyDown& keyDown = mKeyDowns.editTop();
2288 keyDown.keyCode = keyCode;
2289 keyDown.scanCode = scanCode;
2295 ssize_t keyDownIndex = findKeyDown(scanCode);
2296 if (keyDownIndex >= 0) {
2297 // key up, be sure to use same keycode as before in case of rotation
2298 keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
2299 mKeyDowns.removeAt(size_t(keyDownIndex));
2301 // key was not actually down
2302 ALOGI("Dropping key up from device %s because the key was not down. "
2303 "keyCode=%d, scanCode=%d",
2304 getDeviceName().string(), keyCode, scanCode);
2309 if (updateMetaStateIfNeeded(keyCode, down)) {
2310 // If global meta state changed send it along with the key.
2311 // If it has not changed then we'll use what keymap gave us,
2312 // since key replacement logic might temporarily reset a few
2313 // meta bits for given key.
2314 keyMetaState = mMetaState;
2317 nsecs_t downTime = mDownTime;
2319 // Key down on external an keyboard should wake the device.
2320 // We don't do this for internal keyboards to prevent them from waking up in your pocket.
2321 // For internal keyboards, the key layout file should specify the policy flags for
2322 // each wake key individually.
2323 // TODO: Use the input device configuration to control this behavior more finely.
2324 if (down && getDevice()->isExternal()) {
2325 policyFlags |= POLICY_FLAG_WAKE;
2328 if (mParameters.handlesKeyRepeat) {
2329 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
2332 if (down && !isMetaKey(keyCode)) {
2333 getContext()->fadePointer();
2336 NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
2337 down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
2338 AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
2339 getListener()->notifyKey(&args);
2342 ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
2343 size_t n = mKeyDowns.size();
2344 for (size_t i = 0; i < n; i++) {
2345 if (mKeyDowns[i].scanCode == scanCode) {
2352 int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
2353 return getEventHub()->getKeyCodeState(getDeviceId(), keyCode);
2356 int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
2357 return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
2360 bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
2361 const int32_t* keyCodes, uint8_t* outFlags) {
2362 return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags);
2365 int32_t KeyboardInputMapper::getMetaState() {
2369 void KeyboardInputMapper::updateMetaState(int32_t keyCode) {
2370 updateMetaStateIfNeeded(keyCode, false);
2373 bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) {
2374 int32_t oldMetaState = mMetaState;
2375 int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState);
2376 bool metaStateChanged = oldMetaState != newMetaState;
2377 if (metaStateChanged) {
2378 mMetaState = newMetaState;
2379 updateLedState(false);
2381 getContext()->updateGlobalMetaState();
2384 return metaStateChanged;
2387 void KeyboardInputMapper::resetLedState() {
2388 initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK);
2389 initializeLedState(mNumLockLedState, ALED_NUM_LOCK);
2390 initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK);
2392 updateLedState(true);
2395 void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) {
2396 ledState.avail = getEventHub()->hasLed(getDeviceId(), led);
2397 ledState.on = false;
2400 void KeyboardInputMapper::updateLedState(bool reset) {
2401 updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK,
2402 AMETA_CAPS_LOCK_ON, reset);
2403 updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK,
2404 AMETA_NUM_LOCK_ON, reset);
2405 updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK,
2406 AMETA_SCROLL_LOCK_ON, reset);
2409 void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState,
2410 int32_t led, int32_t modifier, bool reset) {
2411 if (ledState.avail) {
2412 bool desiredState = (mMetaState & modifier) != 0;
2413 if (reset || ledState.on != desiredState) {
2414 getEventHub()->setLedState(getDeviceId(), led, desiredState);
2415 ledState.on = desiredState;
2421 // --- CursorInputMapper ---
2423 CursorInputMapper::CursorInputMapper(InputDevice* device) :
2424 InputMapper(device) {
2427 CursorInputMapper::~CursorInputMapper() {
2430 uint32_t CursorInputMapper::getSources() {
2434 void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
2435 InputMapper::populateDeviceInfo(info);
2437 if (mParameters.mode == Parameters::MODE_POINTER) {
2438 float minX, minY, maxX, maxY;
2439 if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
2440 info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
2441 info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f);
2444 info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
2445 info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
2447 info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
2449 if (mCursorScrollAccumulator.haveRelativeVWheel()) {
2450 info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
2452 if (mCursorScrollAccumulator.haveRelativeHWheel()) {
2453 info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
2457 void CursorInputMapper::dump(String8& dump) {
2458 dump.append(INDENT2 "Cursor Input Mapper:\n");
2459 dumpParameters(dump);
2460 dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale);
2461 dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale);
2462 dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
2463 dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
2464 dump.appendFormat(INDENT3 "HaveVWheel: %s\n",
2465 toString(mCursorScrollAccumulator.haveRelativeVWheel()));
2466 dump.appendFormat(INDENT3 "HaveHWheel: %s\n",
2467 toString(mCursorScrollAccumulator.haveRelativeHWheel()));
2468 dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
2469 dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
2470 dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
2471 dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
2472 dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
2473 dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime);
2476 void CursorInputMapper::configure(nsecs_t when,
2477 const InputReaderConfiguration* config, uint32_t changes) {
2478 InputMapper::configure(when, config, changes);
2480 if (!changes) { // first time only
2481 mCursorScrollAccumulator.configure(getDevice());
2483 // Configure basic parameters.
2484 configureParameters();
2486 // Configure device mode.
2487 switch (mParameters.mode) {
2488 case Parameters::MODE_POINTER:
2489 mSource = AINPUT_SOURCE_MOUSE;
2494 mPointerController = getPolicy()->obtainPointerController(getDeviceId());
2496 case Parameters::MODE_NAVIGATION:
2497 mSource = AINPUT_SOURCE_TRACKBALL;
2498 mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
2499 mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
2500 mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
2501 mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
2505 mVWheelScale = 1.0f;
2506 mHWheelScale = 1.0f;
2509 if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
2510 mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
2511 mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
2512 mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
2515 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
2516 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
2518 if (config->getDisplayInfo(false /*external*/, &v)) {
2519 mOrientation = v.orientation;
2521 mOrientation = DISPLAY_ORIENTATION_0;
2524 mOrientation = DISPLAY_ORIENTATION_0;
2530 void CursorInputMapper::configureParameters() {
2531 mParameters.mode = Parameters::MODE_POINTER;
2532 String8 cursorModeString;
2533 if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) {
2534 if (cursorModeString == "navigation") {
2535 mParameters.mode = Parameters::MODE_NAVIGATION;
2536 } else if (cursorModeString != "pointer" && cursorModeString != "default") {
2537 ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
2541 mParameters.orientationAware = false;
2542 getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
2543 mParameters.orientationAware);
2545 mParameters.hasAssociatedDisplay = false;
2546 if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
2547 mParameters.hasAssociatedDisplay = true;
2551 void CursorInputMapper::dumpParameters(String8& dump) {
2552 dump.append(INDENT3 "Parameters:\n");
2553 dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
2554 toString(mParameters.hasAssociatedDisplay));
2556 switch (mParameters.mode) {
2557 case Parameters::MODE_POINTER:
2558 dump.append(INDENT4 "Mode: pointer\n");
2560 case Parameters::MODE_NAVIGATION:
2561 dump.append(INDENT4 "Mode: navigation\n");
2567 dump.appendFormat(INDENT4 "OrientationAware: %s\n",
2568 toString(mParameters.orientationAware));
2571 void CursorInputMapper::reset(nsecs_t when) {
2575 mPointerVelocityControl.reset();
2576 mWheelXVelocityControl.reset();
2577 mWheelYVelocityControl.reset();
2579 mCursorButtonAccumulator.reset(getDevice());
2580 mCursorMotionAccumulator.reset(getDevice());
2581 mCursorScrollAccumulator.reset(getDevice());
2583 InputMapper::reset(when);
2586 void CursorInputMapper::process(const RawEvent* rawEvent) {
2587 mCursorButtonAccumulator.process(rawEvent);
2588 mCursorMotionAccumulator.process(rawEvent);
2589 mCursorScrollAccumulator.process(rawEvent);
2591 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
2592 sync(rawEvent->when);
2596 void CursorInputMapper::sync(nsecs_t when) {
2597 int32_t lastButtonState = mButtonState;
2598 int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
2599 mButtonState = currentButtonState;
2601 bool wasDown = isPointerDown(lastButtonState);
2602 bool down = isPointerDown(currentButtonState);
2604 if (!wasDown && down) {
2607 } else if (wasDown && !down) {
2610 downChanged = false;
2612 nsecs_t downTime = mDownTime;
2613 bool buttonsChanged = currentButtonState != lastButtonState;
2614 int32_t buttonsPressed = currentButtonState & ~lastButtonState;
2615 int32_t buttonsReleased = lastButtonState & ~currentButtonState;
2617 float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
2618 float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
2619 bool moved = deltaX != 0 || deltaY != 0;
2621 // Rotate delta according to orientation if needed.
2622 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay
2623 && (deltaX != 0.0f || deltaY != 0.0f)) {
2624 rotateDelta(mOrientation, &deltaX, &deltaY);
2627 // Move the pointer.
2628 PointerProperties pointerProperties;
2629 pointerProperties.clear();
2630 pointerProperties.id = 0;
2631 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;
2633 PointerCoords pointerCoords;
2634 pointerCoords.clear();
2636 float vscroll = mCursorScrollAccumulator.getRelativeVWheel();
2637 float hscroll = mCursorScrollAccumulator.getRelativeHWheel();
2638 bool scrolled = vscroll != 0 || hscroll != 0;
2640 mWheelYVelocityControl.move(when, NULL, &vscroll);
2641 mWheelXVelocityControl.move(when, &hscroll, NULL);
2643 mPointerVelocityControl.move(when, &deltaX, &deltaY);
2646 if (mPointerController != NULL) {
2647 if (moved || scrolled || buttonsChanged) {
2648 mPointerController->setPresentation(
2649 PointerControllerInterface::PRESENTATION_POINTER);
2652 mPointerController->move(deltaX, deltaY);
2655 if (buttonsChanged) {
2656 mPointerController->setButtonState(currentButtonState);
2659 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
2663 mPointerController->getPosition(&x, &y);
2664 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
2665 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
2666 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
2667 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
2668 displayId = ADISPLAY_ID_DEFAULT;
2670 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
2671 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
2672 displayId = ADISPLAY_ID_NONE;
2675 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
2677 // Moving an external trackball or mouse should wake the device.
2678 // We don't do this for internal cursor devices to prevent them from waking up
2679 // the device in your pocket.
2680 // TODO: Use the input device configuration to control this behavior more finely.
2681 uint32_t policyFlags = 0;
2682 if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) {
2683 policyFlags |= POLICY_FLAG_WAKE;
2686 // Synthesize key down from buttons if needed.
2687 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
2688 policyFlags, lastButtonState, currentButtonState);
2690 // Send motion event.
2691 if (downChanged || moved || scrolled || buttonsChanged) {
2692 int32_t metaState = mContext->getGlobalMetaState();
2693 int32_t buttonState = lastButtonState;
2694 int32_t motionEventAction;
2696 motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
2697 } else if (down || mPointerController == NULL) {
2698 motionEventAction = AMOTION_EVENT_ACTION_MOVE;
2700 motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
2703 if (buttonsReleased) {
2704 BitSet32 released(buttonsReleased);
2705 while (!released.isEmpty()) {
2706 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
2707 buttonState &= ~actionButton;
2708 NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags,
2709 AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
2710 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2711 displayId, 1, &pointerProperties, &pointerCoords,
2712 mXPrecision, mYPrecision, downTime);
2713 getListener()->notifyMotion(&releaseArgs);
2717 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
2718 motionEventAction, 0, 0, metaState, currentButtonState,
2719 AMOTION_EVENT_EDGE_FLAG_NONE,
2720 displayId, 1, &pointerProperties, &pointerCoords,
2721 mXPrecision, mYPrecision, downTime);
2722 getListener()->notifyMotion(&args);
2724 if (buttonsPressed) {
2725 BitSet32 pressed(buttonsPressed);
2726 while (!pressed.isEmpty()) {
2727 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
2728 buttonState |= actionButton;
2729 NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags,
2730 AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
2731 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2732 displayId, 1, &pointerProperties, &pointerCoords,
2733 mXPrecision, mYPrecision, downTime);
2734 getListener()->notifyMotion(&pressArgs);
2738 ALOG_ASSERT(buttonState == currentButtonState);
2740 // Send hover move after UP to tell the application that the mouse is hovering now.
2741 if (motionEventAction == AMOTION_EVENT_ACTION_UP
2742 && mPointerController != NULL) {
2743 NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
2744 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
2745 metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2746 displayId, 1, &pointerProperties, &pointerCoords,
2747 mXPrecision, mYPrecision, downTime);
2748 getListener()->notifyMotion(&hoverArgs);
2751 // Send scroll events.
2753 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
2754 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
2756 NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
2757 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
2758 AMOTION_EVENT_EDGE_FLAG_NONE,
2759 displayId, 1, &pointerProperties, &pointerCoords,
2760 mXPrecision, mYPrecision, downTime);
2761 getListener()->notifyMotion(&scrollArgs);
2765 // Synthesize key up from buttons if needed.
2766 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
2767 policyFlags, lastButtonState, currentButtonState);
2769 mCursorMotionAccumulator.finishSync();
2770 mCursorScrollAccumulator.finishSync();
2773 int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
2774 if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) {
2775 return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
2777 return AKEY_STATE_UNKNOWN;
2781 void CursorInputMapper::fadePointer() {
2782 if (mPointerController != NULL) {
2783 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
2787 // --- RotaryEncoderInputMapper ---
2789 RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) :
2790 InputMapper(device) {
2791 mSource = AINPUT_SOURCE_ROTARY_ENCODER;
2794 RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {
2797 uint32_t RotaryEncoderInputMapper::getSources() {
2801 void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
2802 InputMapper::populateDeviceInfo(info);
2804 if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) {
2806 if (!mDevice->getConfiguration().tryGetProperty(String8("device.res"), res)) {
2807 ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n");
2809 if (!mDevice->getConfiguration().tryGetProperty(String8("device.scalingFactor"),
2811 ALOGW("Rotary Encoder device configuration file didn't specify scaling factor,"
2812 "default to 1.0!\n");
2813 mScalingFactor = 1.0f;
2815 info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
2816 res * mScalingFactor);
2820 void RotaryEncoderInputMapper::dump(String8& dump) {
2821 dump.append(INDENT2 "Rotary Encoder Input Mapper:\n");
2822 dump.appendFormat(INDENT3 "HaveWheel: %s\n",
2823 toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel()));
2826 void RotaryEncoderInputMapper::configure(nsecs_t when,
2827 const InputReaderConfiguration* config, uint32_t changes) {
2828 InputMapper::configure(when, config, changes);
2830 mRotaryEncoderScrollAccumulator.configure(getDevice());
2834 void RotaryEncoderInputMapper::reset(nsecs_t when) {
2835 mRotaryEncoderScrollAccumulator.reset(getDevice());
2837 InputMapper::reset(when);
2840 void RotaryEncoderInputMapper::process(const RawEvent* rawEvent) {
2841 mRotaryEncoderScrollAccumulator.process(rawEvent);
2843 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
2844 sync(rawEvent->when);
2848 void RotaryEncoderInputMapper::sync(nsecs_t when) {
2849 PointerCoords pointerCoords;
2850 pointerCoords.clear();
2852 PointerProperties pointerProperties;
2853 pointerProperties.clear();
2854 pointerProperties.id = 0;
2855 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
2857 float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel();
2858 bool scrolled = scroll != 0;
2860 // This is not a pointer, so it's not associated with a display.
2861 int32_t displayId = ADISPLAY_ID_NONE;
2863 // Moving the rotary encoder should wake the device (if specified).
2864 uint32_t policyFlags = 0;
2865 if (scrolled && getDevice()->isExternal()) {
2866 policyFlags |= POLICY_FLAG_WAKE;
2869 // Send motion event.
2871 int32_t metaState = mContext->getGlobalMetaState();
2872 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
2874 NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
2875 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
2876 AMOTION_EVENT_EDGE_FLAG_NONE,
2877 displayId, 1, &pointerProperties, &pointerCoords,
2879 getListener()->notifyMotion(&scrollArgs);
2882 mRotaryEncoderScrollAccumulator.finishSync();
2885 // --- TouchInputMapper ---
2887 TouchInputMapper::TouchInputMapper(InputDevice* device) :
2888 InputMapper(device),
2889 mSource(0), mDeviceMode(DEVICE_MODE_DISABLED),
2890 mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0),
2891 mSurfaceOrientation(DISPLAY_ORIENTATION_0) {
2894 TouchInputMapper::~TouchInputMapper() {
2897 uint32_t TouchInputMapper::getSources() {
2901 void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
2902 InputMapper::populateDeviceInfo(info);
2904 if (mDeviceMode != DEVICE_MODE_DISABLED) {
2905 info->addMotionRange(mOrientedRanges.x);
2906 info->addMotionRange(mOrientedRanges.y);
2907 info->addMotionRange(mOrientedRanges.pressure);
2909 if (mOrientedRanges.haveSize) {
2910 info->addMotionRange(mOrientedRanges.size);
2913 if (mOrientedRanges.haveTouchSize) {
2914 info->addMotionRange(mOrientedRanges.touchMajor);
2915 info->addMotionRange(mOrientedRanges.touchMinor);
2918 if (mOrientedRanges.haveToolSize) {
2919 info->addMotionRange(mOrientedRanges.toolMajor);
2920 info->addMotionRange(mOrientedRanges.toolMinor);
2923 if (mOrientedRanges.haveOrientation) {
2924 info->addMotionRange(mOrientedRanges.orientation);
2927 if (mOrientedRanges.haveDistance) {
2928 info->addMotionRange(mOrientedRanges.distance);
2931 if (mOrientedRanges.haveTilt) {
2932 info->addMotionRange(mOrientedRanges.tilt);
2935 if (mCursorScrollAccumulator.haveRelativeVWheel()) {
2936 info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
2939 if (mCursorScrollAccumulator.haveRelativeHWheel()) {
2940 info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
2943 if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
2944 const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
2945 const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
2946 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat,
2947 x.fuzz, x.resolution);
2948 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat,
2949 y.fuzz, y.resolution);
2950 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat,
2951 x.fuzz, x.resolution);
2952 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat,
2953 y.fuzz, y.resolution);
2955 info->setButtonUnderPad(mParameters.hasButtonUnderPad);
2959 void TouchInputMapper::dump(String8& dump) {
2960 dump.append(INDENT2 "Touch Input Mapper:\n");
2961 dumpParameters(dump);
2962 dumpVirtualKeys(dump);
2963 dumpRawPointerAxes(dump);
2964 dumpCalibration(dump);
2965 dumpAffineTransformation(dump);
2968 dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
2969 dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
2970 dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
2971 dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale);
2972 dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale);
2973 dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
2974 dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
2975 dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
2976 dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
2977 dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
2978 dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale);
2979 dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale);
2980 dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt));
2981 dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter);
2982 dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale);
2983 dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
2984 dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
2986 dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
2987 dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n",
2988 mLastRawState.rawPointerData.pointerCount);
2989 for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
2990 const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
2991 dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
2992 "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
2993 "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
2994 "toolType=%d, isHovering=%s\n", i,
2995 pointer.id, pointer.x, pointer.y, pointer.pressure,
2996 pointer.touchMajor, pointer.touchMinor,
2997 pointer.toolMajor, pointer.toolMinor,
2998 pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance,
2999 pointer.toolType, toString(pointer.isHovering));
3002 dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState);
3003 dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
3004 mLastCookedState.cookedPointerData.pointerCount);
3005 for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) {
3006 const PointerProperties& pointerProperties =
3007 mLastCookedState.cookedPointerData.pointerProperties[i];
3008 const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
3009 dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
3010 "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, "
3011 "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
3012 "toolType=%d, isHovering=%s\n", i,
3013 pointerProperties.id,
3014 pointerCoords.getX(),
3015 pointerCoords.getY(),
3016 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
3017 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
3018 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
3019 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
3020 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
3021 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
3022 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT),
3023 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE),
3024 pointerProperties.toolType,
3025 toString(mLastCookedState.cookedPointerData.isHovering(i)));
3028 dump.append(INDENT3 "Stylus Fusion:\n");
3029 dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n",
3030 toString(mExternalStylusConnected));
3031 dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
3032 dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
3033 mExternalStylusFusionTimeout);
3034 dump.append(INDENT3 "External Stylus State:\n");
3035 dumpStylusState(dump, mExternalStylusState);
3037 if (mDeviceMode == DEVICE_MODE_POINTER) {
3038 dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
3039 dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
3040 mPointerXMovementScale);
3041 dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n",
3042 mPointerYMovementScale);
3043 dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n",
3044 mPointerXZoomScale);
3045 dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n",
3046 mPointerYZoomScale);
3047 dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n",
3048 mPointerGestureMaxSwipeWidth);
3052 void TouchInputMapper::configure(nsecs_t when,
3053 const InputReaderConfiguration* config, uint32_t changes) {
3054 InputMapper::configure(when, config, changes);
3058 if (!changes) { // first time only
3059 // Configure basic parameters.
3060 configureParameters();
3062 // Configure common accumulators.
3063 mCursorScrollAccumulator.configure(getDevice());
3064 mTouchButtonAccumulator.configure(getDevice());
3066 // Configure absolute axis information.
3067 configureRawPointerAxes();
3069 // Prepare input device calibration.
3071 resolveCalibration();
3074 if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) {
3075 // Update location calibration to reflect current settings
3076 updateAffineTransformation();
3079 if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
3080 // Update pointer speed.
3081 mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
3082 mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
3083 mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
3086 bool resetNeeded = false;
3087 if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO
3088 | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
3089 | InputReaderConfiguration::CHANGE_SHOW_TOUCHES
3090 | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
3091 // Configure device sources, surface dimensions, orientation and
3093 configureSurface(when, &resetNeeded);
3096 if (changes && resetNeeded) {
3097 // Send reset, unless this is the first time the device has been configured,
3098 // in which case the reader will call reset itself after all mappers are ready.
3099 getDevice()->notifyReset(when);
3103 void TouchInputMapper::resolveExternalStylusPresence() {
3104 Vector<InputDeviceInfo> devices;
3105 mContext->getExternalStylusDevices(devices);
3106 mExternalStylusConnected = !devices.isEmpty();
3108 if (!mExternalStylusConnected) {
3109 resetExternalStylus();
3113 void TouchInputMapper::configureParameters() {
3114 // Use the pointer presentation mode for devices that do not support distinct
3115 // multitouch. The spot-based presentation relies on being able to accurately
3116 // locate two or more fingers on the touch pad.
3117 mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT)
3118 ? Parameters::GESTURE_MODE_SINGLE_TOUCH : Parameters::GESTURE_MODE_MULTI_TOUCH;
3120 String8 gestureModeString;
3121 if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"),
3122 gestureModeString)) {
3123 if (gestureModeString == "single-touch") {
3124 mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH;
3125 } else if (gestureModeString == "multi-touch") {
3126 mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH;
3127 } else if (gestureModeString != "default") {
3128 ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
3132 if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) {
3133 // The device is a touch screen.
3134 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
3135 } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) {
3136 // The device is a pointing device like a track pad.
3137 mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
3138 } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X)
3139 || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) {
3140 // The device is a cursor device with a touch pad attached.
3141 // By default don't use the touch pad to move the pointer.
3142 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
3144 // The device is a touch pad of unknown purpose.
3145 mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
3148 mParameters.hasButtonUnderPad=
3149 getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD);
3151 String8 deviceTypeString;
3152 if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
3153 deviceTypeString)) {
3154 if (deviceTypeString == "touchScreen") {
3155 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
3156 } else if (deviceTypeString == "touchPad") {
3157 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
3158 } else if (deviceTypeString == "touchNavigation") {
3159 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION;
3160 } else if (deviceTypeString == "pointer") {
3161 mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
3162 } else if (deviceTypeString == "gesture") {
3163 mParameters.deviceType = Parameters::DEVICE_TYPE_GESTURE_SENSOR;
3164 } else if (deviceTypeString != "default") {
3165 ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
3169 mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
3170 getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
3171 mParameters.orientationAware);
3173 mParameters.hasAssociatedDisplay = false;
3174 mParameters.associatedDisplayIsExternal = false;
3175 if (mParameters.orientationAware
3176 || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
3177 || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
3178 mParameters.hasAssociatedDisplay = true;
3179 mParameters.associatedDisplayIsExternal =
3180 mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
3181 && getDevice()->isExternal();
3184 // Initial downs on external touch devices should wake the device.
3185 // Normally we don't do this for internal touch screens to prevent them from waking
3186 // up in your pocket but you can enable it using the input device configuration.
3187 mParameters.wake = getDevice()->isExternal();
3188 getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"),
3192 void TouchInputMapper::dumpParameters(String8& dump) {
3193 dump.append(INDENT3 "Parameters:\n");
3195 switch (mParameters.gestureMode) {
3196 case Parameters::GESTURE_MODE_SINGLE_TOUCH:
3197 dump.append(INDENT4 "GestureMode: single-touch\n");
3199 case Parameters::GESTURE_MODE_MULTI_TOUCH:
3200 dump.append(INDENT4 "GestureMode: multi-touch\n");
3206 switch (mParameters.deviceType) {
3207 case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
3208 dump.append(INDENT4 "DeviceType: touchScreen\n");
3210 case Parameters::DEVICE_TYPE_TOUCH_PAD:
3211 dump.append(INDENT4 "DeviceType: touchPad\n");
3213 case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION:
3214 dump.append(INDENT4 "DeviceType: touchNavigation\n");
3216 case Parameters::DEVICE_TYPE_POINTER:
3217 dump.append(INDENT4 "DeviceType: pointer\n");
3219 case Parameters::DEVICE_TYPE_GESTURE_SENSOR:
3220 dump.append(INDENT4 "DeviceType: gesture\n");
3226 dump.appendFormat(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s\n",
3227 toString(mParameters.hasAssociatedDisplay),
3228 toString(mParameters.associatedDisplayIsExternal));
3229 dump.appendFormat(INDENT4 "OrientationAware: %s\n",
3230 toString(mParameters.orientationAware));
3233 void TouchInputMapper::configureRawPointerAxes() {
3234 mRawPointerAxes.clear();
3237 void TouchInputMapper::dumpRawPointerAxes(String8& dump) {
3238 dump.append(INDENT3 "Raw Touch Axes:\n");
3239 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X");
3240 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y");
3241 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure");
3242 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor");
3243 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor");
3244 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor");
3245 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor");
3246 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation");
3247 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance");
3248 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX");
3249 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY");
3250 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId");
3251 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot");
3254 bool TouchInputMapper::hasExternalStylus() const {
3255 return mExternalStylusConnected;
3258 void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
3259 int32_t oldDeviceMode = mDeviceMode;
3261 resolveExternalStylusPresence();
3263 // Determine device mode.
3264 if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
3265 && mConfig.pointerGesturesEnabled) {
3266 mSource = AINPUT_SOURCE_MOUSE;
3267 mDeviceMode = DEVICE_MODE_POINTER;
3269 mSource |= AINPUT_SOURCE_STYLUS;
3271 } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
3272 && mParameters.hasAssociatedDisplay) {
3273 mSource = AINPUT_SOURCE_TOUCHSCREEN;
3274 mDeviceMode = DEVICE_MODE_DIRECT;
3276 mSource |= AINPUT_SOURCE_STYLUS;
3278 if (hasExternalStylus()) {
3279 mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
3281 } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
3282 mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
3283 mDeviceMode = DEVICE_MODE_NAVIGATION;
3284 } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_GESTURE_SENSOR) {
3285 mSource = AINPUT_SOURCE_GESTURE_SENSOR;
3286 mDeviceMode = DEVICE_MODE_UNSCALED;
3288 mSource = AINPUT_SOURCE_TOUCHPAD;
3289 mDeviceMode = DEVICE_MODE_UNSCALED;
3292 // Ensure we have valid X and Y axes.
3293 if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
3294 ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis! "
3295 "The device will be inoperable.", getDeviceName().string());
3296 mDeviceMode = DEVICE_MODE_DISABLED;
3300 // Raw width and height in the natural orientation.
3301 int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
3302 int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
3304 // Get associated display dimensions.
3305 DisplayViewport newViewport;
3306 if (mParameters.hasAssociatedDisplay) {
3307 if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal, &newViewport)) {
3308 ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
3309 "display. The device will be inoperable until the display size "
3310 "becomes available.",
3311 getDeviceName().string());
3312 mDeviceMode = DEVICE_MODE_DISABLED;
3316 newViewport.setNonDisplayViewport(rawWidth, rawHeight);
3318 bool viewportChanged = mViewport != newViewport;
3319 if (viewportChanged) {
3320 mViewport = newViewport;
3322 if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
3323 // Convert rotated viewport to natural surface coordinates.
3324 int32_t naturalLogicalWidth, naturalLogicalHeight;
3325 int32_t naturalPhysicalWidth, naturalPhysicalHeight;
3326 int32_t naturalPhysicalLeft, naturalPhysicalTop;
3327 int32_t naturalDeviceWidth, naturalDeviceHeight;
3328 switch (mViewport.orientation) {
3329 case DISPLAY_ORIENTATION_90:
3330 naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
3331 naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
3332 naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
3333 naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
3334 naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
3335 naturalPhysicalTop = mViewport.physicalLeft;
3336 naturalDeviceWidth = mViewport.deviceHeight;
3337 naturalDeviceHeight = mViewport.deviceWidth;
3339 case DISPLAY_ORIENTATION_180:
3340 naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
3341 naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
3342 naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
3343 naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
3344 naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight;
3345 naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom;
3346 naturalDeviceWidth = mViewport.deviceWidth;
3347 naturalDeviceHeight = mViewport.deviceHeight;
3349 case DISPLAY_ORIENTATION_270:
3350 naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
3351 naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
3352 naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
3353 naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
3354 naturalPhysicalLeft = mViewport.physicalTop;
3355 naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight;
3356 naturalDeviceWidth = mViewport.deviceHeight;
3357 naturalDeviceHeight = mViewport.deviceWidth;
3359 case DISPLAY_ORIENTATION_0:
3361 naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
3362 naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
3363 naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
3364 naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
3365 naturalPhysicalLeft = mViewport.physicalLeft;
3366 naturalPhysicalTop = mViewport.physicalTop;
3367 naturalDeviceWidth = mViewport.deviceWidth;
3368 naturalDeviceHeight = mViewport.deviceHeight;
3372 mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
3373 mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
3374 mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
3375 mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
3377 mSurfaceOrientation = mParameters.orientationAware ?
3378 mViewport.orientation : DISPLAY_ORIENTATION_0;
3380 mSurfaceWidth = rawWidth;
3381 mSurfaceHeight = rawHeight;
3384 mSurfaceOrientation = DISPLAY_ORIENTATION_0;
3388 // If moving between pointer modes, need to reset some state.
3389 bool deviceModeChanged = mDeviceMode != oldDeviceMode;
3390 if (deviceModeChanged) {
3391 mOrientedRanges.clear();
3394 // Create pointer controller if needed.
3395 if (mDeviceMode == DEVICE_MODE_POINTER ||
3396 (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
3397 if (mPointerController == NULL) {
3398 mPointerController = getPolicy()->obtainPointerController(getDeviceId());
3401 mPointerController.clear();
3404 if (viewportChanged || deviceModeChanged) {
3405 ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
3407 getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight,
3408 mSurfaceOrientation, mDeviceMode, mViewport.displayId);
3410 // Configure X and Y factors.
3411 mXScale = float(mSurfaceWidth) / rawWidth;
3412 mYScale = float(mSurfaceHeight) / rawHeight;
3413 mXTranslate = -mSurfaceLeft;
3414 mYTranslate = -mSurfaceTop;
3415 mXPrecision = 1.0f / mXScale;
3416 mYPrecision = 1.0f / mYScale;
3418 mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
3419 mOrientedRanges.x.source = mSource;
3420 mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
3421 mOrientedRanges.y.source = mSource;
3423 configureVirtualKeys();
3425 // Scale factor for terms that are not oriented in a particular axis.
3426 // If the pixels are square then xScale == yScale otherwise we fake it
3427 // by choosing an average.
3428 mGeometricScale = avg(mXScale, mYScale);
3430 // Size of diagonal axis.
3431 float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight);
3434 if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
3435 if (mRawPointerAxes.touchMajor.valid
3436 && mRawPointerAxes.touchMajor.maxValue != 0) {
3437 mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
3438 } else if (mRawPointerAxes.toolMajor.valid
3439 && mRawPointerAxes.toolMajor.maxValue != 0) {
3440 mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue;
3445 mOrientedRanges.haveTouchSize = true;
3446 mOrientedRanges.haveToolSize = true;
3447 mOrientedRanges.haveSize = true;
3449 mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
3450 mOrientedRanges.touchMajor.source = mSource;
3451 mOrientedRanges.touchMajor.min = 0;
3452 mOrientedRanges.touchMajor.max = diagonalSize;
3453 mOrientedRanges.touchMajor.flat = 0;
3454 mOrientedRanges.touchMajor.fuzz = 0;
3455 mOrientedRanges.touchMajor.resolution = 0;
3457 mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
3458 mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
3460 mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
3461 mOrientedRanges.toolMajor.source = mSource;
3462 mOrientedRanges.toolMajor.min = 0;
3463 mOrientedRanges.toolMajor.max = diagonalSize;
3464 mOrientedRanges.toolMajor.flat = 0;
3465 mOrientedRanges.toolMajor.fuzz = 0;
3466 mOrientedRanges.toolMajor.resolution = 0;
3468 mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
3469 mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
3471 mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
3472 mOrientedRanges.size.source = mSource;
3473 mOrientedRanges.size.min = 0;
3474 mOrientedRanges.size.max = 1.0;
3475 mOrientedRanges.size.flat = 0;
3476 mOrientedRanges.size.fuzz = 0;
3477 mOrientedRanges.size.resolution = 0;
3482 // Pressure factors.
3484 if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL
3485 || mCalibration.pressureCalibration
3486 == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
3487 if (mCalibration.havePressureScale) {
3488 mPressureScale = mCalibration.pressureScale;
3489 } else if (mRawPointerAxes.pressure.valid
3490 && mRawPointerAxes.pressure.maxValue != 0) {
3491 mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
3495 mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
3496 mOrientedRanges.pressure.source = mSource;
3497 mOrientedRanges.pressure.min = 0;
3498 mOrientedRanges.pressure.max = 1.0;
3499 mOrientedRanges.pressure.flat = 0;
3500 mOrientedRanges.pressure.fuzz = 0;
3501 mOrientedRanges.pressure.resolution = 0;
3508 mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid;
3510 mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue,
3511 mRawPointerAxes.tiltX.maxValue);
3512 mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue,
3513 mRawPointerAxes.tiltY.maxValue);
3514 mTiltXScale = M_PI / 180;
3515 mTiltYScale = M_PI / 180;
3517 mOrientedRanges.haveTilt = true;
3519 mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
3520 mOrientedRanges.tilt.source = mSource;
3521 mOrientedRanges.tilt.min = 0;
3522 mOrientedRanges.tilt.max = M_PI_2;
3523 mOrientedRanges.tilt.flat = 0;
3524 mOrientedRanges.tilt.fuzz = 0;
3525 mOrientedRanges.tilt.resolution = 0;
3529 mOrientationScale = 0;
3531 mOrientedRanges.haveOrientation = true;
3533 mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
3534 mOrientedRanges.orientation.source = mSource;
3535 mOrientedRanges.orientation.min = -M_PI;
3536 mOrientedRanges.orientation.max = M_PI;
3537 mOrientedRanges.orientation.flat = 0;
3538 mOrientedRanges.orientation.fuzz = 0;
3539 mOrientedRanges.orientation.resolution = 0;
3540 } else if (mCalibration.orientationCalibration !=
3541 Calibration::ORIENTATION_CALIBRATION_NONE) {
3542 if (mCalibration.orientationCalibration
3543 == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) {
3544 if (mRawPointerAxes.orientation.valid) {
3545 if (mRawPointerAxes.orientation.maxValue > 0) {
3546 mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
3547 } else if (mRawPointerAxes.orientation.minValue < 0) {
3548 mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue;
3550 mOrientationScale = 0;
3555 mOrientedRanges.haveOrientation = true;
3557 mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
3558 mOrientedRanges.orientation.source = mSource;
3559 mOrientedRanges.orientation.min = -M_PI_2;
3560 mOrientedRanges.orientation.max = M_PI_2;
3561 mOrientedRanges.orientation.flat = 0;
3562 mOrientedRanges.orientation.fuzz = 0;
3563 mOrientedRanges.orientation.resolution = 0;
3568 if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) {
3569 if (mCalibration.distanceCalibration
3570 == Calibration::DISTANCE_CALIBRATION_SCALED) {
3571 if (mCalibration.haveDistanceScale) {
3572 mDistanceScale = mCalibration.distanceScale;
3574 mDistanceScale = 1.0f;
3578 mOrientedRanges.haveDistance = true;
3580 mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE;
3581 mOrientedRanges.distance.source = mSource;
3582 mOrientedRanges.distance.min =
3583 mRawPointerAxes.distance.minValue * mDistanceScale;
3584 mOrientedRanges.distance.max =
3585 mRawPointerAxes.distance.maxValue * mDistanceScale;
3586 mOrientedRanges.distance.flat = 0;
3587 mOrientedRanges.distance.fuzz =
3588 mRawPointerAxes.distance.fuzz * mDistanceScale;
3589 mOrientedRanges.distance.resolution = 0;
3592 // Compute oriented precision, scales and ranges.
3593 // Note that the maximum value reported is an inclusive maximum value so it is one
3594 // unit less than the total width or height of surface.
3595 switch (mSurfaceOrientation) {
3596 case DISPLAY_ORIENTATION_90:
3597 case DISPLAY_ORIENTATION_270:
3598 mOrientedXPrecision = mYPrecision;
3599 mOrientedYPrecision = mXPrecision;
3601 mOrientedRanges.x.min = mYTranslate;
3602 mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1;
3603 mOrientedRanges.x.flat = 0;
3604 mOrientedRanges.x.fuzz = 0;
3605 mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
3607 mOrientedRanges.y.min = mXTranslate;
3608 mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1;
3609 mOrientedRanges.y.flat = 0;
3610 mOrientedRanges.y.fuzz = 0;
3611 mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
3615 mOrientedXPrecision = mXPrecision;
3616 mOrientedYPrecision = mYPrecision;
3618 mOrientedRanges.x.min = mXTranslate;
3619 mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1;
3620 mOrientedRanges.x.flat = 0;
3621 mOrientedRanges.x.fuzz = 0;
3622 mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
3624 mOrientedRanges.y.min = mYTranslate;
3625 mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1;
3626 mOrientedRanges.y.flat = 0;
3627 mOrientedRanges.y.fuzz = 0;
3628 mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
3633 updateAffineTransformation();
3635 if (mDeviceMode == DEVICE_MODE_POINTER) {
3636 // Compute pointer gesture detection parameters.
3637 float rawDiagonal = hypotf(rawWidth, rawHeight);
3638 float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight);
3640 // Scale movements such that one whole swipe of the touch pad covers a
3641 // given area relative to the diagonal size of the display when no acceleration
3643 // Assume that the touch pad has a square aspect ratio such that movements in
3644 // X and Y of the same number of raw units cover the same physical distance.
3645 mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio
3646 * displayDiagonal / rawDiagonal;
3647 mPointerYMovementScale = mPointerXMovementScale;
3649 // Scale zooms to cover a smaller range of the display than movements do.
3650 // This value determines the area around the pointer that is affected by freeform
3651 // pointer gestures.
3652 mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio
3653 * displayDiagonal / rawDiagonal;
3654 mPointerYZoomScale = mPointerXZoomScale;
3656 // Max width between pointers to detect a swipe gesture is more than some fraction
3657 // of the diagonal axis of the touch pad. Touches that are wider than this are
3658 // translated into freeform gestures.
3659 mPointerGestureMaxSwipeWidth =
3660 mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal;
3662 // Abort current pointer usages because the state has changed.
3663 abortPointerUsage(when, 0 /*policyFlags*/);
3666 // Inform the dispatcher about the changes.
3667 *outResetNeeded = true;
3672 void TouchInputMapper::dumpSurface(String8& dump) {
3673 dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, "
3674 "logicalFrame=[%d, %d, %d, %d], "
3675 "physicalFrame=[%d, %d, %d, %d], "
3676 "deviceSize=[%d, %d]\n",
3677 mViewport.displayId, mViewport.orientation,
3678 mViewport.logicalLeft, mViewport.logicalTop,
3679 mViewport.logicalRight, mViewport.logicalBottom,
3680 mViewport.physicalLeft, mViewport.physicalTop,
3681 mViewport.physicalRight, mViewport.physicalBottom,
3682 mViewport.deviceWidth, mViewport.deviceHeight);
3684 dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
3685 dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
3686 dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
3687 dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
3688 dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
3691 void TouchInputMapper::configureVirtualKeys() {
3692 Vector<VirtualKeyDefinition> virtualKeyDefinitions;
3693 getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
3695 mVirtualKeys.clear();
3697 if (virtualKeyDefinitions.size() == 0) {
3701 mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
3703 int32_t touchScreenLeft = mRawPointerAxes.x.minValue;
3704 int32_t touchScreenTop = mRawPointerAxes.y.minValue;
3705 int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
3706 int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
3708 for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
3709 const VirtualKeyDefinition& virtualKeyDefinition =
3710 virtualKeyDefinitions[i];
3713 VirtualKey& virtualKey = mVirtualKeys.editTop();
3715 virtualKey.scanCode = virtualKeyDefinition.scanCode;
3717 int32_t dummyKeyMetaState;
3719 if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0,
3720 &keyCode, &dummyKeyMetaState, &flags)) {
3721 ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
3722 virtualKey.scanCode);
3723 mVirtualKeys.pop(); // drop the key
3727 virtualKey.keyCode = keyCode;
3728 virtualKey.flags = flags;
3730 // convert the key definition's display coordinates into touch coordinates for a hit box
3731 int32_t halfWidth = virtualKeyDefinition.width / 2;
3732 int32_t halfHeight = virtualKeyDefinition.height / 2;
3734 virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
3735 * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
3736 virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
3737 * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
3738 virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
3739 * touchScreenHeight / mSurfaceHeight + touchScreenTop;
3740 virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
3741 * touchScreenHeight / mSurfaceHeight + touchScreenTop;
3745 void TouchInputMapper::dumpVirtualKeys(String8& dump) {
3746 if (!mVirtualKeys.isEmpty()) {
3747 dump.append(INDENT3 "Virtual Keys:\n");
3749 for (size_t i = 0; i < mVirtualKeys.size(); i++) {
3750 const VirtualKey& virtualKey = mVirtualKeys.itemAt(i);
3751 dump.appendFormat(INDENT4 "%zu: scanCode=%d, keyCode=%d, "
3752 "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
3753 i, virtualKey.scanCode, virtualKey.keyCode,
3754 virtualKey.hitLeft, virtualKey.hitRight,
3755 virtualKey.hitTop, virtualKey.hitBottom);
3760 void TouchInputMapper::parseCalibration() {
3761 const PropertyMap& in = getDevice()->getConfiguration();
3762 Calibration& out = mCalibration;
3765 out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT;
3766 String8 sizeCalibrationString;
3767 if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) {
3768 if (sizeCalibrationString == "none") {
3769 out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
3770 } else if (sizeCalibrationString == "geometric") {
3771 out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
3772 } else if (sizeCalibrationString == "diameter") {
3773 out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER;
3774 } else if (sizeCalibrationString == "box") {
3775 out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX;
3776 } else if (sizeCalibrationString == "area") {
3777 out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA;
3778 } else if (sizeCalibrationString != "default") {
3779 ALOGW("Invalid value for touch.size.calibration: '%s'",
3780 sizeCalibrationString.string());
3784 out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"),
3786 out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"),
3788 out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"),
3792 out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT;
3793 String8 pressureCalibrationString;
3794 if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) {
3795 if (pressureCalibrationString == "none") {
3796 out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
3797 } else if (pressureCalibrationString == "physical") {
3798 out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
3799 } else if (pressureCalibrationString == "amplitude") {
3800 out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE;
3801 } else if (pressureCalibrationString != "default") {
3802 ALOGW("Invalid value for touch.pressure.calibration: '%s'",
3803 pressureCalibrationString.string());
3807 out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"),
3811 out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT;
3812 String8 orientationCalibrationString;
3813 if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) {
3814 if (orientationCalibrationString == "none") {
3815 out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
3816 } else if (orientationCalibrationString == "interpolated") {
3817 out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
3818 } else if (orientationCalibrationString == "vector") {
3819 out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR;
3820 } else if (orientationCalibrationString != "default") {
3821 ALOGW("Invalid value for touch.orientation.calibration: '%s'",
3822 orientationCalibrationString.string());
3827 out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT;
3828 String8 distanceCalibrationString;
3829 if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) {
3830 if (distanceCalibrationString == "none") {
3831 out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
3832 } else if (distanceCalibrationString == "scaled") {
3833 out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
3834 } else if (distanceCalibrationString != "default") {
3835 ALOGW("Invalid value for touch.distance.calibration: '%s'",
3836 distanceCalibrationString.string());
3840 out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"),
3843 out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT;
3844 String8 coverageCalibrationString;
3845 if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) {
3846 if (coverageCalibrationString == "none") {
3847 out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
3848 } else if (coverageCalibrationString == "box") {
3849 out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX;
3850 } else if (coverageCalibrationString != "default") {
3851 ALOGW("Invalid value for touch.coverage.calibration: '%s'",
3852 coverageCalibrationString.string());
3857 void TouchInputMapper::resolveCalibration() {
3859 if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) {
3860 if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) {
3861 mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
3864 mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
3868 if (mRawPointerAxes.pressure.valid) {
3869 if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) {
3870 mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
3873 mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
3877 if (mRawPointerAxes.orientation.valid) {
3878 if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) {
3879 mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
3882 mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
3886 if (mRawPointerAxes.distance.valid) {
3887 if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) {
3888 mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
3891 mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
3895 if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) {
3896 mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
3900 void TouchInputMapper::dumpCalibration(String8& dump) {
3901 dump.append(INDENT3 "Calibration:\n");
3904 switch (mCalibration.sizeCalibration) {
3905 case Calibration::SIZE_CALIBRATION_NONE:
3906 dump.append(INDENT4 "touch.size.calibration: none\n");
3908 case Calibration::SIZE_CALIBRATION_GEOMETRIC:
3909 dump.append(INDENT4 "touch.size.calibration: geometric\n");
3911 case Calibration::SIZE_CALIBRATION_DIAMETER:
3912 dump.append(INDENT4 "touch.size.calibration: diameter\n");
3914 case Calibration::SIZE_CALIBRATION_BOX:
3915 dump.append(INDENT4 "touch.size.calibration: box\n");
3917 case Calibration::SIZE_CALIBRATION_AREA:
3918 dump.append(INDENT4 "touch.size.calibration: area\n");
3924 if (mCalibration.haveSizeScale) {
3925 dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n",
3926 mCalibration.sizeScale);
3929 if (mCalibration.haveSizeBias) {
3930 dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n",
3931 mCalibration.sizeBias);
3934 if (mCalibration.haveSizeIsSummed) {
3935 dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n",
3936 toString(mCalibration.sizeIsSummed));
3940 switch (mCalibration.pressureCalibration) {
3941 case Calibration::PRESSURE_CALIBRATION_NONE:
3942 dump.append(INDENT4 "touch.pressure.calibration: none\n");
3944 case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
3945 dump.append(INDENT4 "touch.pressure.calibration: physical\n");
3947 case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
3948 dump.append(INDENT4 "touch.pressure.calibration: amplitude\n");
3954 if (mCalibration.havePressureScale) {
3955 dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n",
3956 mCalibration.pressureScale);
3960 switch (mCalibration.orientationCalibration) {
3961 case Calibration::ORIENTATION_CALIBRATION_NONE:
3962 dump.append(INDENT4 "touch.orientation.calibration: none\n");
3964 case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
3965 dump.append(INDENT4 "touch.orientation.calibration: interpolated\n");
3967 case Calibration::ORIENTATION_CALIBRATION_VECTOR:
3968 dump.append(INDENT4 "touch.orientation.calibration: vector\n");
3975 switch (mCalibration.distanceCalibration) {
3976 case Calibration::DISTANCE_CALIBRATION_NONE:
3977 dump.append(INDENT4 "touch.distance.calibration: none\n");
3979 case Calibration::DISTANCE_CALIBRATION_SCALED:
3980 dump.append(INDENT4 "touch.distance.calibration: scaled\n");
3986 if (mCalibration.haveDistanceScale) {
3987 dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n",
3988 mCalibration.distanceScale);
3991 switch (mCalibration.coverageCalibration) {
3992 case Calibration::COVERAGE_CALIBRATION_NONE:
3993 dump.append(INDENT4 "touch.coverage.calibration: none\n");
3995 case Calibration::COVERAGE_CALIBRATION_BOX:
3996 dump.append(INDENT4 "touch.coverage.calibration: box\n");
4003 void TouchInputMapper::dumpAffineTransformation(String8& dump) {
4004 dump.append(INDENT3 "Affine Transformation:\n");
4006 dump.appendFormat(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale);
4007 dump.appendFormat(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix);
4008 dump.appendFormat(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset);
4009 dump.appendFormat(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix);
4010 dump.appendFormat(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale);
4011 dump.appendFormat(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset);
4014 void TouchInputMapper::updateAffineTransformation() {
4015 mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(),
4016 mSurfaceOrientation);
4019 void TouchInputMapper::reset(nsecs_t when) {
4020 mCursorButtonAccumulator.reset(getDevice());
4021 mCursorScrollAccumulator.reset(getDevice());
4022 mTouchButtonAccumulator.reset(getDevice());
4024 mPointerVelocityControl.reset();
4025 mWheelXVelocityControl.reset();
4026 mWheelYVelocityControl.reset();
4028 mRawStatesPending.clear();
4029 mCurrentRawState.clear();
4030 mCurrentCookedState.clear();
4031 mLastRawState.clear();
4032 mLastCookedState.clear();
4033 mPointerUsage = POINTER_USAGE_NONE;
4034 mSentHoverEnter = false;
4035 mHavePointerIds = false;
4036 mCurrentMotionAborted = false;
4039 mCurrentVirtualKey.down = false;
4041 mPointerGesture.reset();
4042 mPointerSimple.reset();
4043 resetExternalStylus();
4045 if (mPointerController != NULL) {
4046 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
4047 mPointerController->clearSpots();
4050 InputMapper::reset(when);
4053 void TouchInputMapper::resetExternalStylus() {
4054 mExternalStylusState.clear();
4055 mExternalStylusId = -1;
4056 mExternalStylusFusionTimeout = LLONG_MAX;
4057 mExternalStylusDataPending = false;
4060 void TouchInputMapper::clearStylusDataPendingFlags() {
4061 mExternalStylusDataPending = false;
4062 mExternalStylusFusionTimeout = LLONG_MAX;
4065 void TouchInputMapper::process(const RawEvent* rawEvent) {
4066 mCursorButtonAccumulator.process(rawEvent);
4067 mCursorScrollAccumulator.process(rawEvent);
4068 mTouchButtonAccumulator.process(rawEvent);
4070 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
4071 sync(rawEvent->when);
4075 void TouchInputMapper::sync(nsecs_t when) {
4076 const RawState* last = mRawStatesPending.isEmpty() ?
4077 &mCurrentRawState : &mRawStatesPending.top();
4079 // Push a new state.
4080 mRawStatesPending.push();
4081 RawState* next = &mRawStatesPending.editTop();
4085 // Sync button state.
4086 next->buttonState = mTouchButtonAccumulator.getButtonState()
4087 | mCursorButtonAccumulator.getButtonState();
4090 next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
4091 next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
4092 mCursorScrollAccumulator.finishSync();
4095 syncTouch(when, next);
4097 // Assign pointer ids.
4098 if (!mHavePointerIds) {
4099 assignPointerIds(last, next);
4102 #if DEBUG_RAW_EVENTS
4103 ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
4104 "hovering ids 0x%08x -> 0x%08x",
4105 last->rawPointerData.pointerCount,
4106 next->rawPointerData.pointerCount,
4107 last->rawPointerData.touchingIdBits.value,
4108 next->rawPointerData.touchingIdBits.value,
4109 last->rawPointerData.hoveringIdBits.value,
4110 next->rawPointerData.hoveringIdBits.value);
4113 processRawTouches(false /*timeout*/);
4116 void TouchInputMapper::processRawTouches(bool timeout) {
4117 if (mDeviceMode == DEVICE_MODE_DISABLED) {
4118 // Drop all input if the device is disabled.
4119 mCurrentRawState.clear();
4120 mRawStatesPending.clear();
4124 // Drain any pending touch states. The invariant here is that the mCurrentRawState is always
4125 // valid and must go through the full cook and dispatch cycle. This ensures that anything
4126 // touching the current state will only observe the events that have been dispatched to the
4127 // rest of the pipeline.
4128 const size_t N = mRawStatesPending.size();
4130 for(count = 0; count < N; count++) {
4131 const RawState& next = mRawStatesPending[count];
4133 // A failure to assign the stylus id means that we're waiting on stylus data
4134 // and so should defer the rest of the pipeline.
4135 if (assignExternalStylusId(next, timeout)) {
4140 clearStylusDataPendingFlags();
4141 mCurrentRawState.copyFrom(next);
4142 if (mCurrentRawState.when < mLastRawState.when) {
4143 mCurrentRawState.when = mLastRawState.when;
4145 cookAndDispatch(mCurrentRawState.when);
4148 mRawStatesPending.removeItemsAt(0, count);
4151 if (mExternalStylusDataPending) {
4153 nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;
4154 clearStylusDataPendingFlags();
4155 mCurrentRawState.copyFrom(mLastRawState);
4156 #if DEBUG_STYLUS_FUSION
4157 ALOGD("Timeout expired, synthesizing event with new stylus data");
4159 cookAndDispatch(when);
4160 } else if (mExternalStylusFusionTimeout == LLONG_MAX) {
4161 mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
4162 getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
4167 void TouchInputMapper::cookAndDispatch(nsecs_t when) {
4168 // Always start with a clean state.
4169 mCurrentCookedState.clear();
4171 // Apply stylus buttons to current raw state.
4172 applyExternalStylusButtonState(when);
4174 // Handle policy on initial down or hover events.
4175 bool initialDown = mLastRawState.rawPointerData.pointerCount == 0
4176 && mCurrentRawState.rawPointerData.pointerCount != 0;
4178 uint32_t policyFlags = 0;
4179 bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
4180 if (initialDown || buttonsPressed) {
4181 // If this is a touch screen, hide the pointer on an initial down.
4182 if (mDeviceMode == DEVICE_MODE_DIRECT) {
4183 getContext()->fadePointer();
4186 if (mParameters.wake) {
4187 policyFlags |= POLICY_FLAG_WAKE;
4191 // Consume raw off-screen touches before cooking pointer data.
4192 // If touches are consumed, subsequent code will not receive any pointer data.
4193 if (consumeRawTouches(when, policyFlags)) {
4194 mCurrentRawState.rawPointerData.clear();
4197 // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure
4198 // with cooked pointer data that has the same ids and indices as the raw data.
4199 // The following code can use either the raw or cooked data, as needed.
4202 // Apply stylus pressure to current cooked state.
4203 applyExternalStylusTouchState(when);
4205 // Synthesize key down from raw buttons if needed.
4206 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
4207 policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
4209 // Dispatch the touches either directly or by translation through a pointer on screen.
4210 if (mDeviceMode == DEVICE_MODE_POINTER) {
4211 for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits);
4212 !idBits.isEmpty(); ) {
4213 uint32_t id = idBits.clearFirstMarkedBit();
4214 const RawPointerData::Pointer& pointer =
4215 mCurrentRawState.rawPointerData.pointerForId(id);
4216 if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
4217 || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
4218 mCurrentCookedState.stylusIdBits.markBit(id);
4219 } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
4220 || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
4221 mCurrentCookedState.fingerIdBits.markBit(id);
4222 } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
4223 mCurrentCookedState.mouseIdBits.markBit(id);
4226 for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits);
4227 !idBits.isEmpty(); ) {
4228 uint32_t id = idBits.clearFirstMarkedBit();
4229 const RawPointerData::Pointer& pointer =
4230 mCurrentRawState.rawPointerData.pointerForId(id);
4231 if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
4232 || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
4233 mCurrentCookedState.stylusIdBits.markBit(id);
4237 // Stylus takes precedence over all tools, then mouse, then finger.
4238 PointerUsage pointerUsage = mPointerUsage;
4239 if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
4240 mCurrentCookedState.mouseIdBits.clear();
4241 mCurrentCookedState.fingerIdBits.clear();
4242 pointerUsage = POINTER_USAGE_STYLUS;
4243 } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
4244 mCurrentCookedState.fingerIdBits.clear();
4245 pointerUsage = POINTER_USAGE_MOUSE;
4246 } else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||
4247 isPointerDown(mCurrentRawState.buttonState)) {
4248 pointerUsage = POINTER_USAGE_GESTURES;
4251 dispatchPointerUsage(when, policyFlags, pointerUsage);
4253 if (mDeviceMode == DEVICE_MODE_DIRECT
4254 && mConfig.showTouches && mPointerController != NULL) {
4255 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
4256 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
4258 mPointerController->setButtonState(mCurrentRawState.buttonState);
4259 mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
4260 mCurrentCookedState.cookedPointerData.idToIndex,
4261 mCurrentCookedState.cookedPointerData.touchingIdBits);
4264 if (!mCurrentMotionAborted) {
4265 dispatchButtonRelease(when, policyFlags);
4266 dispatchHoverExit(when, policyFlags);
4267 dispatchTouches(when, policyFlags);
4268 dispatchHoverEnterAndMove(when, policyFlags);
4269 dispatchButtonPress(when, policyFlags);
4272 if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
4273 mCurrentMotionAborted = false;
4277 // Synthesize key up from raw buttons if needed.
4278 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
4279 policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
4281 // Clear some transient state.
4282 mCurrentRawState.rawVScroll = 0;
4283 mCurrentRawState.rawHScroll = 0;
4285 // Copy current touch to last touch in preparation for the next cycle.
4286 mLastRawState.copyFrom(mCurrentRawState);
4287 mLastCookedState.copyFrom(mCurrentCookedState);
4290 void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
4291 if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
4292 mCurrentRawState.buttonState |= mExternalStylusState.buttons;
4296 void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) {
4297 CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData;
4298 const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData;
4300 if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) {
4301 float pressure = mExternalStylusState.pressure;
4302 if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) {
4303 const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId);
4304 pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
4306 PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId);
4307 coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
4309 PointerProperties& properties =
4310 currentPointerData.editPointerPropertiesWithId(mExternalStylusId);
4311 if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
4312 properties.toolType = mExternalStylusState.toolType;
4317 bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) {
4318 if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) {
4322 const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0
4323 && state.rawPointerData.pointerCount != 0;
4325 if (mExternalStylusState.pressure != 0.0f) {
4326 #if DEBUG_STYLUS_FUSION
4327 ALOGD("Have both stylus and touch data, beginning fusion");
4329 mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit();
4330 } else if (timeout) {
4331 #if DEBUG_STYLUS_FUSION
4332 ALOGD("Timeout expired, assuming touch is not a stylus.");
4334 resetExternalStylus();
4336 if (mExternalStylusFusionTimeout == LLONG_MAX) {
4337 mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT;
4339 #if DEBUG_STYLUS_FUSION
4340 ALOGD("No stylus data but stylus is connected, requesting timeout "
4341 "(%" PRId64 "ms)", mExternalStylusFusionTimeout);
4343 getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
4348 // Check if the stylus pointer has gone up.
4349 if (mExternalStylusId != -1 &&
4350 !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) {
4351 #if DEBUG_STYLUS_FUSION
4352 ALOGD("Stylus pointer is going up");
4354 mExternalStylusId = -1;
4360 void TouchInputMapper::timeoutExpired(nsecs_t when) {
4361 if (mDeviceMode == DEVICE_MODE_POINTER) {
4362 if (mPointerUsage == POINTER_USAGE_GESTURES) {
4363 dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
4365 } else if (mDeviceMode == DEVICE_MODE_DIRECT) {
4366 if (mExternalStylusFusionTimeout < when) {
4367 processRawTouches(true /*timeout*/);
4368 } else if (mExternalStylusFusionTimeout != LLONG_MAX) {
4369 getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
4374 void TouchInputMapper::updateExternalStylusState(const StylusState& state) {
4375 mExternalStylusState.copyFrom(state);
4376 if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) {
4377 // We're either in the middle of a fused stream of data or we're waiting on data before
4378 // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus
4380 mExternalStylusDataPending = true;
4381 processRawTouches(false /*timeout*/);
4385 bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
4386 // Check for release of a virtual key.
4387 if (mCurrentVirtualKey.down) {
4388 if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
4389 // Pointer went up while virtual key was down.
4390 mCurrentVirtualKey.down = false;
4391 if (!mCurrentVirtualKey.ignored) {
4392 #if DEBUG_VIRTUAL_KEYS
4393 ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
4394 mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
4396 dispatchVirtualKey(when, policyFlags,
4397 AKEY_EVENT_ACTION_UP,
4398 AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
4403 if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
4404 uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
4405 const RawPointerData::Pointer& pointer =
4406 mCurrentRawState.rawPointerData.pointerForId(id);
4407 const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
4408 if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
4409 // Pointer is still within the space of the virtual key.
4414 // Pointer left virtual key area or another pointer also went down.
4415 // Send key cancellation but do not consume the touch yet.
4416 // This is useful when the user swipes through from the virtual key area
4417 // into the main display surface.
4418 mCurrentVirtualKey.down = false;
4419 if (!mCurrentVirtualKey.ignored) {
4420 #if DEBUG_VIRTUAL_KEYS
4421 ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
4422 mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
4424 dispatchVirtualKey(when, policyFlags,
4425 AKEY_EVENT_ACTION_UP,
4426 AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
4427 | AKEY_EVENT_FLAG_CANCELED);
4431 if (mLastRawState.rawPointerData.touchingIdBits.isEmpty()
4432 && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
4433 // Pointer just went down. Check for virtual key press or off-screen touches.
4434 uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
4435 const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
4436 if (!isPointInsideSurface(pointer.x, pointer.y)) {
4437 // If exactly one pointer went down, check for virtual key hit.
4438 // Otherwise we will drop the entire stroke.
4439 if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
4440 const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
4442 mCurrentVirtualKey.down = true;
4443 mCurrentVirtualKey.downTime = when;
4444 mCurrentVirtualKey.keyCode = virtualKey->keyCode;
4445 mCurrentVirtualKey.scanCode = virtualKey->scanCode;
4446 mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey(
4447 when, getDevice(), virtualKey->keyCode, virtualKey->scanCode);
4449 if (!mCurrentVirtualKey.ignored) {
4450 #if DEBUG_VIRTUAL_KEYS
4451 ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
4452 mCurrentVirtualKey.keyCode,
4453 mCurrentVirtualKey.scanCode);
4455 dispatchVirtualKey(when, policyFlags,
4456 AKEY_EVENT_ACTION_DOWN,
4457 AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
4465 // Disable all virtual key touches that happen within a short time interval of the
4466 // most recent touch within the screen area. The idea is to filter out stray
4467 // virtual key presses when interacting with the touch screen.
4469 // Problems we're trying to solve:
4471 // 1. While scrolling a list or dragging the window shade, the user swipes down into a
4472 // virtual key area that is implemented by a separate touch panel and accidentally
4473 // triggers a virtual key.
4475 // 2. While typing in the on screen keyboard, the user taps slightly outside the screen
4476 // area and accidentally triggers a virtual key. This often happens when virtual keys
4477 // are layed out below the screen near to where the on screen keyboard's space bar
4479 if (mConfig.virtualKeyQuietTime > 0 &&
4480 !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
4481 mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
4486 void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
4487 int32_t keyEventAction, int32_t keyEventFlags) {
4488 int32_t keyCode = mCurrentVirtualKey.keyCode;
4489 int32_t scanCode = mCurrentVirtualKey.scanCode;
4490 nsecs_t downTime = mCurrentVirtualKey.downTime;
4491 int32_t metaState = mContext->getGlobalMetaState();
4492 policyFlags |= POLICY_FLAG_VIRTUAL;
4494 NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
4495 keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
4496 getListener()->notifyKey(&args);
4499 void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) {
4500 BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
4501 if (!currentIdBits.isEmpty()) {
4502 int32_t metaState = getContext()->getGlobalMetaState();
4503 int32_t buttonState = mCurrentCookedState.buttonState;
4504 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0,
4505 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
4506 mCurrentCookedState.cookedPointerData.pointerProperties,
4507 mCurrentCookedState.cookedPointerData.pointerCoords,
4508 mCurrentCookedState.cookedPointerData.idToIndex,
4510 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4511 mCurrentMotionAborted = true;
4515 void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
4516 BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
4517 BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
4518 int32_t metaState = getContext()->getGlobalMetaState();
4519 int32_t buttonState = mCurrentCookedState.buttonState;
4521 if (currentIdBits == lastIdBits) {
4522 if (!currentIdBits.isEmpty()) {
4523 // No pointer id changes so this is a move event.
4524 // The listener takes care of batching moves so we don't have to deal with that here.
4525 dispatchMotion(when, policyFlags, mSource,
4526 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
4527 AMOTION_EVENT_EDGE_FLAG_NONE,
4528 mCurrentCookedState.cookedPointerData.pointerProperties,
4529 mCurrentCookedState.cookedPointerData.pointerCoords,
4530 mCurrentCookedState.cookedPointerData.idToIndex,
4532 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4535 // There may be pointers going up and pointers going down and pointers moving
4536 // all at the same time.
4537 BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
4538 BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
4539 BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
4540 BitSet32 dispatchedIdBits(lastIdBits.value);
4542 // Update last coordinates of pointers that have moved so that we observe the new
4543 // pointer positions at the same time as other pointers that have just gone up.
4544 bool moveNeeded = updateMovedPointers(
4545 mCurrentCookedState.cookedPointerData.pointerProperties,
4546 mCurrentCookedState.cookedPointerData.pointerCoords,
4547 mCurrentCookedState.cookedPointerData.idToIndex,
4548 mLastCookedState.cookedPointerData.pointerProperties,
4549 mLastCookedState.cookedPointerData.pointerCoords,
4550 mLastCookedState.cookedPointerData.idToIndex,
4552 if (buttonState != mLastCookedState.buttonState) {
4556 // Dispatch pointer up events.
4557 while (!upIdBits.isEmpty()) {
4558 uint32_t upId = upIdBits.clearFirstMarkedBit();
4560 dispatchMotion(when, policyFlags, mSource,
4561 AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,
4562 mLastCookedState.cookedPointerData.pointerProperties,
4563 mLastCookedState.cookedPointerData.pointerCoords,
4564 mLastCookedState.cookedPointerData.idToIndex,
4565 dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4566 dispatchedIdBits.clearBit(upId);
4569 // Dispatch move events if any of the remaining pointers moved from their old locations.
4570 // Although applications receive new locations as part of individual pointer up
4571 // events, they do not generally handle them except when presented in a move event.
4572 if (moveNeeded && !moveIdBits.isEmpty()) {
4573 ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
4574 dispatchMotion(when, policyFlags, mSource,
4575 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,
4576 mCurrentCookedState.cookedPointerData.pointerProperties,
4577 mCurrentCookedState.cookedPointerData.pointerCoords,
4578 mCurrentCookedState.cookedPointerData.idToIndex,
4579 dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4582 // Dispatch pointer down events using the new pointer locations.
4583 while (!downIdBits.isEmpty()) {
4584 uint32_t downId = downIdBits.clearFirstMarkedBit();
4585 dispatchedIdBits.markBit(downId);
4587 if (dispatchedIdBits.count() == 1) {
4588 // First pointer is going down. Set down time.
4592 dispatchMotion(when, policyFlags, mSource,
4593 AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
4594 mCurrentCookedState.cookedPointerData.pointerProperties,
4595 mCurrentCookedState.cookedPointerData.pointerCoords,
4596 mCurrentCookedState.cookedPointerData.idToIndex,
4597 dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4602 void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) {
4603 if (mSentHoverEnter &&
4604 (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()
4605 || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) {
4606 int32_t metaState = getContext()->getGlobalMetaState();
4607 dispatchMotion(when, policyFlags, mSource,
4608 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0,
4609 mLastCookedState.cookedPointerData.pointerProperties,
4610 mLastCookedState.cookedPointerData.pointerCoords,
4611 mLastCookedState.cookedPointerData.idToIndex,
4612 mLastCookedState.cookedPointerData.hoveringIdBits, -1,
4613 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4614 mSentHoverEnter = false;
4618 void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) {
4619 if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty()
4620 && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) {
4621 int32_t metaState = getContext()->getGlobalMetaState();
4622 if (!mSentHoverEnter) {
4623 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER,
4624 0, 0, metaState, mCurrentRawState.buttonState, 0,
4625 mCurrentCookedState.cookedPointerData.pointerProperties,
4626 mCurrentCookedState.cookedPointerData.pointerCoords,
4627 mCurrentCookedState.cookedPointerData.idToIndex,
4628 mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
4629 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4630 mSentHoverEnter = true;
4633 dispatchMotion(when, policyFlags, mSource,
4634 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
4635 mCurrentRawState.buttonState, 0,
4636 mCurrentCookedState.cookedPointerData.pointerProperties,
4637 mCurrentCookedState.cookedPointerData.pointerCoords,
4638 mCurrentCookedState.cookedPointerData.idToIndex,
4639 mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
4640 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4644 void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) {
4645 BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState);
4646 const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData);
4647 const int32_t metaState = getContext()->getGlobalMetaState();
4648 int32_t buttonState = mLastCookedState.buttonState;
4649 while (!releasedButtons.isEmpty()) {
4650 int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit());
4651 buttonState &= ~actionButton;
4652 dispatchMotion(when, policyFlags, mSource,
4653 AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton,
4654 0, metaState, buttonState, 0,
4655 mCurrentCookedState.cookedPointerData.pointerProperties,
4656 mCurrentCookedState.cookedPointerData.pointerCoords,
4657 mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
4658 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4662 void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) {
4663 BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState);
4664 const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData);
4665 const int32_t metaState = getContext()->getGlobalMetaState();
4666 int32_t buttonState = mLastCookedState.buttonState;
4667 while (!pressedButtons.isEmpty()) {
4668 int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit());
4669 buttonState |= actionButton;
4670 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton,
4671 0, metaState, buttonState, 0,
4672 mCurrentCookedState.cookedPointerData.pointerProperties,
4673 mCurrentCookedState.cookedPointerData.pointerCoords,
4674 mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
4675 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
4679 const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) {
4680 if (!cookedPointerData.touchingIdBits.isEmpty()) {
4681 return cookedPointerData.touchingIdBits;
4683 return cookedPointerData.hoveringIdBits;
4686 void TouchInputMapper::cookPointerData() {
4687 uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
4689 mCurrentCookedState.cookedPointerData.clear();
4690 mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
4691 mCurrentCookedState.cookedPointerData.hoveringIdBits =
4692 mCurrentRawState.rawPointerData.hoveringIdBits;
4693 mCurrentCookedState.cookedPointerData.touchingIdBits =
4694 mCurrentRawState.rawPointerData.touchingIdBits;
4696 if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
4697 mCurrentCookedState.buttonState = 0;
4699 mCurrentCookedState.buttonState = mCurrentRawState.buttonState;
4702 // Walk through the the active pointers and map device coordinates onto
4703 // surface coordinates and adjust for display orientation.
4704 for (uint32_t i = 0; i < currentPointerCount; i++) {
4705 const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
4708 float touchMajor, touchMinor, toolMajor, toolMinor, size;
4709 switch (mCalibration.sizeCalibration) {
4710 case Calibration::SIZE_CALIBRATION_GEOMETRIC:
4711 case Calibration::SIZE_CALIBRATION_DIAMETER:
4712 case Calibration::SIZE_CALIBRATION_BOX:
4713 case Calibration::SIZE_CALIBRATION_AREA:
4714 if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) {
4715 touchMajor = in.touchMajor;
4716 touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
4717 toolMajor = in.toolMajor;
4718 toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor;
4719 size = mRawPointerAxes.touchMinor.valid
4720 ? avg(in.touchMajor, in.touchMinor) : in.touchMajor;
4721 } else if (mRawPointerAxes.touchMajor.valid) {
4722 toolMajor = touchMajor = in.touchMajor;
4723 toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid
4724 ? in.touchMinor : in.touchMajor;
4725 size = mRawPointerAxes.touchMinor.valid
4726 ? avg(in.touchMajor, in.touchMinor) : in.touchMajor;
4727 } else if (mRawPointerAxes.toolMajor.valid) {
4728 touchMajor = toolMajor = in.toolMajor;
4729 touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid
4730 ? in.toolMinor : in.toolMajor;
4731 size = mRawPointerAxes.toolMinor.valid
4732 ? avg(in.toolMajor, in.toolMinor) : in.toolMajor;
4734 ALOG_ASSERT(false, "No touch or tool axes. "
4735 "Size calibration should have been resolved to NONE.");
4743 if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) {
4744 uint32_t touchingCount =
4745 mCurrentRawState.rawPointerData.touchingIdBits.count();
4746 if (touchingCount > 1) {
4747 touchMajor /= touchingCount;
4748 touchMinor /= touchingCount;
4749 toolMajor /= touchingCount;
4750 toolMinor /= touchingCount;
4751 size /= touchingCount;
4755 if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) {
4756 touchMajor *= mGeometricScale;
4757 touchMinor *= mGeometricScale;
4758 toolMajor *= mGeometricScale;
4759 toolMinor *= mGeometricScale;
4760 } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) {
4761 touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0;
4762 touchMinor = touchMajor;
4763 toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0;
4764 toolMinor = toolMajor;
4765 } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) {
4766 touchMinor = touchMajor;
4767 toolMinor = toolMajor;
4770 mCalibration.applySizeScaleAndBias(&touchMajor);
4771 mCalibration.applySizeScaleAndBias(&touchMinor);
4772 mCalibration.applySizeScaleAndBias(&toolMajor);
4773 mCalibration.applySizeScaleAndBias(&toolMinor);
4787 switch (mCalibration.pressureCalibration) {
4788 case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
4789 case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
4790 pressure = in.pressure * mPressureScale;
4793 pressure = in.isHovering ? 0 : 1;
4797 // Tilt and Orientation
4801 float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale;
4802 float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale;
4803 orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle));
4804 tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle));
4808 switch (mCalibration.orientationCalibration) {
4809 case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
4810 orientation = in.orientation * mOrientationScale;
4812 case Calibration::ORIENTATION_CALIBRATION_VECTOR: {
4813 int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
4814 int32_t c2 = signExtendNybble(in.orientation & 0x0f);
4815 if (c1 != 0 || c2 != 0) {
4816 orientation = atan2f(c1, c2) * 0.5f;
4817 float confidence = hypotf(c1, c2);
4818 float scale = 1.0f + confidence / 16.0f;
4819 touchMajor *= scale;
4820 touchMinor /= scale;
4835 switch (mCalibration.distanceCalibration) {
4836 case Calibration::DISTANCE_CALIBRATION_SCALED:
4837 distance = in.distance * mDistanceScale;
4844 int32_t rawLeft, rawTop, rawRight, rawBottom;
4845 switch (mCalibration.coverageCalibration) {
4846 case Calibration::COVERAGE_CALIBRATION_BOX:
4847 rawLeft = (in.toolMinor & 0xffff0000) >> 16;
4848 rawRight = in.toolMinor & 0x0000ffff;
4849 rawBottom = in.toolMajor & 0x0000ffff;
4850 rawTop = (in.toolMajor & 0xffff0000) >> 16;
4853 rawLeft = rawTop = rawRight = rawBottom = 0;
4857 // Adjust X,Y coords for device calibration
4858 // TODO: Adjust coverage coords?
4859 float xTransformed = in.x, yTransformed = in.y;
4860 mAffineTransform.applyTo(xTransformed, yTransformed);
4862 // Adjust X, Y, and coverage coords for surface orientation.
4864 float left, top, right, bottom;
4866 switch (mSurfaceOrientation) {
4867 case DISPLAY_ORIENTATION_90:
4868 x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
4869 y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
4870 left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
4871 right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
4872 bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
4873 top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
4874 orientation -= M_PI_2;
4875 if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) {
4876 orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
4879 case DISPLAY_ORIENTATION_180:
4880 x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
4881 y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
4882 left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
4883 right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
4884 bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
4885 top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
4886 orientation -= M_PI;
4887 if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) {
4888 orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
4891 case DISPLAY_ORIENTATION_270:
4892 x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
4893 y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
4894 left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
4895 right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
4896 bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
4897 top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
4898 orientation += M_PI_2;
4899 if (mOrientedRanges.haveOrientation && orientation > mOrientedRanges.orientation.max) {
4900 orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
4904 x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
4905 y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
4906 left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
4907 right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
4908 bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
4909 top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
4913 // Write output coords.
4914 PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
4916 out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
4917 out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
4918 out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
4919 out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
4920 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
4921 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
4922 out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
4923 out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
4924 out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
4925 if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
4926 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);
4927 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);
4928 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);
4929 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom);
4931 out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
4932 out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
4935 // Write output properties.
4936 PointerProperties& properties =
4937 mCurrentCookedState.cookedPointerData.pointerProperties[i];
4938 uint32_t id = in.id;
4941 properties.toolType = in.toolType;
4944 mCurrentCookedState.cookedPointerData.idToIndex[id] = i;
4948 void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags,
4949 PointerUsage pointerUsage) {
4950 if (pointerUsage != mPointerUsage) {
4951 abortPointerUsage(when, policyFlags);
4952 mPointerUsage = pointerUsage;
4955 switch (mPointerUsage) {
4956 case POINTER_USAGE_GESTURES:
4957 dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
4959 case POINTER_USAGE_STYLUS:
4960 dispatchPointerStylus(when, policyFlags);
4962 case POINTER_USAGE_MOUSE:
4963 dispatchPointerMouse(when, policyFlags);
4970 void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) {
4971 switch (mPointerUsage) {
4972 case POINTER_USAGE_GESTURES:
4973 abortPointerGestures(when, policyFlags);
4975 case POINTER_USAGE_STYLUS:
4976 abortPointerStylus(when, policyFlags);
4978 case POINTER_USAGE_MOUSE:
4979 abortPointerMouse(when, policyFlags);
4985 mPointerUsage = POINTER_USAGE_NONE;
4988 void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags,
4990 // Update current gesture coordinates.
4991 bool cancelPreviousGesture, finishPreviousGesture;
4992 bool sendEvents = preparePointerGestures(when,
4993 &cancelPreviousGesture, &finishPreviousGesture, isTimeout);
4997 if (finishPreviousGesture) {
4998 cancelPreviousGesture = false;
5001 // Update the pointer presentation and spots.
5002 if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) {
5003 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
5004 if (finishPreviousGesture || cancelPreviousGesture) {
5005 mPointerController->clearSpots();
5008 if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
5009 mPointerController->setSpots(mPointerGesture.currentGestureCoords,
5010 mPointerGesture.currentGestureIdToIndex,
5011 mPointerGesture.currentGestureIdBits);
5014 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
5017 // Show or hide the pointer if needed.
5018 switch (mPointerGesture.currentGestureMode) {
5019 case PointerGesture::NEUTRAL:
5020 case PointerGesture::QUIET:
5021 if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH
5022 && mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) {
5023 // Remind the user of where the pointer is after finishing a gesture with spots.
5024 mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL);
5027 case PointerGesture::TAP:
5028 case PointerGesture::TAP_DRAG:
5029 case PointerGesture::BUTTON_CLICK_OR_DRAG:
5030 case PointerGesture::HOVER:
5031 case PointerGesture::PRESS:
5032 case PointerGesture::SWIPE:
5033 // Unfade the pointer when the current gesture manipulates the
5034 // area directly under the pointer.
5035 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
5037 case PointerGesture::FREEFORM:
5038 // Fade the pointer when the current gesture manipulates a different
5039 // area and there are spots to guide the user experience.
5040 if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) {
5041 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
5043 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
5049 int32_t metaState = getContext()->getGlobalMetaState();
5050 int32_t buttonState = mCurrentCookedState.buttonState;
5052 // Update last coordinates of pointers that have moved so that we observe the new
5053 // pointer positions at the same time as other pointers that have just gone up.
5054 bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP
5055 || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG
5056 || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
5057 || mPointerGesture.currentGestureMode == PointerGesture::PRESS
5058 || mPointerGesture.currentGestureMode == PointerGesture::SWIPE
5059 || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM;
5060 bool moveNeeded = false;
5061 if (down && !cancelPreviousGesture && !finishPreviousGesture
5062 && !mPointerGesture.lastGestureIdBits.isEmpty()
5063 && !mPointerGesture.currentGestureIdBits.isEmpty()) {
5064 BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value
5065 & mPointerGesture.lastGestureIdBits.value);
5066 moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties,
5067 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
5068 mPointerGesture.lastGestureProperties,
5069 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
5070 movedGestureIdBits);
5071 if (buttonState != mLastCookedState.buttonState) {
5076 // Send motion events for all pointers that went up or were canceled.
5077 BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits);
5078 if (!dispatchedGestureIdBits.isEmpty()) {
5079 if (cancelPreviousGesture) {
5080 dispatchMotion(when, policyFlags, mSource,
5081 AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
5082 AMOTION_EVENT_EDGE_FLAG_NONE,
5083 mPointerGesture.lastGestureProperties,
5084 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
5085 dispatchedGestureIdBits, -1, 0,
5086 0, mPointerGesture.downTime);
5088 dispatchedGestureIdBits.clear();
5090 BitSet32 upGestureIdBits;
5091 if (finishPreviousGesture) {
5092 upGestureIdBits = dispatchedGestureIdBits;
5094 upGestureIdBits.value = dispatchedGestureIdBits.value
5095 & ~mPointerGesture.currentGestureIdBits.value;
5097 while (!upGestureIdBits.isEmpty()) {
5098 uint32_t id = upGestureIdBits.clearFirstMarkedBit();
5100 dispatchMotion(when, policyFlags, mSource,
5101 AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
5102 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
5103 mPointerGesture.lastGestureProperties,
5104 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
5105 dispatchedGestureIdBits, id,
5106 0, 0, mPointerGesture.downTime);
5108 dispatchedGestureIdBits.clearBit(id);
5113 // Send motion events for all pointers that moved.
5115 dispatchMotion(when, policyFlags, mSource,
5116 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
5117 AMOTION_EVENT_EDGE_FLAG_NONE,
5118 mPointerGesture.currentGestureProperties,
5119 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
5120 dispatchedGestureIdBits, -1,
5121 0, 0, mPointerGesture.downTime);
5124 // Send motion events for all pointers that went down.
5126 BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value
5127 & ~dispatchedGestureIdBits.value);
5128 while (!downGestureIdBits.isEmpty()) {
5129 uint32_t id = downGestureIdBits.clearFirstMarkedBit();
5130 dispatchedGestureIdBits.markBit(id);
5132 if (dispatchedGestureIdBits.count() == 1) {
5133 mPointerGesture.downTime = when;
5136 dispatchMotion(when, policyFlags, mSource,
5137 AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
5138 mPointerGesture.currentGestureProperties,
5139 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
5140 dispatchedGestureIdBits, id,
5141 0, 0, mPointerGesture.downTime);
5145 // Send motion events for hover.
5146 if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
5147 dispatchMotion(when, policyFlags, mSource,
5148 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
5149 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
5150 mPointerGesture.currentGestureProperties,
5151 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
5152 mPointerGesture.currentGestureIdBits, -1,
5153 0, 0, mPointerGesture.downTime);
5154 } else if (dispatchedGestureIdBits.isEmpty()
5155 && !mPointerGesture.lastGestureIdBits.isEmpty()) {
5156 // Synthesize a hover move event after all pointers go up to indicate that
5157 // the pointer is hovering again even if the user is not currently touching
5158 // the touch pad. This ensures that a view will receive a fresh hover enter
5159 // event after a tap.
5161 mPointerController->getPosition(&x, &y);
5163 PointerProperties pointerProperties;
5164 pointerProperties.clear();
5165 pointerProperties.id = 0;
5166 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
5168 PointerCoords pointerCoords;
5169 pointerCoords.clear();
5170 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
5171 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
5173 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
5174 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
5175 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
5176 mViewport.displayId, 1, &pointerProperties, &pointerCoords,
5177 0, 0, mPointerGesture.downTime);
5178 getListener()->notifyMotion(&args);
5182 mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode;
5184 mPointerGesture.lastGestureIdBits.clear();
5186 mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits;
5187 for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) {
5188 uint32_t id = idBits.clearFirstMarkedBit();
5189 uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
5190 mPointerGesture.lastGestureProperties[index].copyFrom(
5191 mPointerGesture.currentGestureProperties[index]);
5192 mPointerGesture.lastGestureCoords[index].copyFrom(
5193 mPointerGesture.currentGestureCoords[index]);
5194 mPointerGesture.lastGestureIdToIndex[id] = index;
5199 void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) {
5200 // Cancel previously dispatches pointers.
5201 if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
5202 int32_t metaState = getContext()->getGlobalMetaState();
5203 int32_t buttonState = mCurrentRawState.buttonState;
5204 dispatchMotion(when, policyFlags, mSource,
5205 AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
5206 AMOTION_EVENT_EDGE_FLAG_NONE,
5207 mPointerGesture.lastGestureProperties,
5208 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
5209 mPointerGesture.lastGestureIdBits, -1,
5210 0, 0, mPointerGesture.downTime);
5213 // Reset the current pointer gesture.
5214 mPointerGesture.reset();
5215 mPointerVelocityControl.reset();
5217 // Remove any current spots.
5218 if (mPointerController != NULL) {
5219 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
5220 mPointerController->clearSpots();
5224 bool TouchInputMapper::preparePointerGestures(nsecs_t when,
5225 bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) {
5226 *outCancelPreviousGesture = false;
5227 *outFinishPreviousGesture = false;
5229 // Handle TAP timeout.
5232 ALOGD("Gestures: Processing timeout");
5235 if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
5236 if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
5237 // The tap/drag timeout has not yet expired.
5238 getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime
5239 + mConfig.pointerGestureTapDragInterval);
5241 // The tap is finished.
5243 ALOGD("Gestures: TAP finished");
5245 *outFinishPreviousGesture = true;
5247 mPointerGesture.activeGestureId = -1;
5248 mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
5249 mPointerGesture.currentGestureIdBits.clear();
5251 mPointerVelocityControl.reset();
5256 // We did not handle this timeout.
5260 const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count();
5261 const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count();
5263 // Update the velocity tracker.
5265 VelocityTracker::Position positions[MAX_POINTERS];
5267 for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) {
5268 uint32_t id = idBits.clearFirstMarkedBit();
5269 const RawPointerData::Pointer& pointer =
5270 mCurrentRawState.rawPointerData.pointerForId(id);
5271 positions[count].x = pointer.x * mPointerXMovementScale;
5272 positions[count].y = pointer.y * mPointerYMovementScale;
5274 mPointerGesture.velocityTracker.addMovement(when,
5275 mCurrentCookedState.fingerIdBits, positions);
5278 // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
5279 // to NEUTRAL, then we should not generate tap event.
5280 if (mPointerGesture.lastGestureMode != PointerGesture::HOVER
5281 && mPointerGesture.lastGestureMode != PointerGesture::TAP
5282 && mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) {
5283 mPointerGesture.resetTap();
5286 // Pick a new active touch id if needed.
5287 // Choose an arbitrary pointer that just went down, if there is one.
5288 // Otherwise choose an arbitrary remaining pointer.
5289 // This guarantees we always have an active touch id when there is at least one pointer.
5290 // We keep the same active touch id for as long as possible.
5291 bool activeTouchChanged = false;
5292 int32_t lastActiveTouchId = mPointerGesture.activeTouchId;
5293 int32_t activeTouchId = lastActiveTouchId;
5294 if (activeTouchId < 0) {
5295 if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
5296 activeTouchChanged = true;
5297 activeTouchId = mPointerGesture.activeTouchId =
5298 mCurrentCookedState.fingerIdBits.firstMarkedBit();
5299 mPointerGesture.firstTouchTime = when;
5301 } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) {
5302 activeTouchChanged = true;
5303 if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
5304 activeTouchId = mPointerGesture.activeTouchId =
5305 mCurrentCookedState.fingerIdBits.firstMarkedBit();
5307 activeTouchId = mPointerGesture.activeTouchId = -1;
5311 // Determine whether we are in quiet time.
5312 bool isQuietTime = false;
5313 if (activeTouchId < 0) {
5314 mPointerGesture.resetQuietTime();
5316 isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval;
5318 if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS
5319 || mPointerGesture.lastGestureMode == PointerGesture::SWIPE
5320 || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)
5321 && currentFingerCount < 2) {
5322 // Enter quiet time when exiting swipe or freeform state.
5323 // This is to prevent accidentally entering the hover state and flinging the
5324 // pointer when finishing a swipe and there is still one pointer left onscreen.
5326 } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
5327 && currentFingerCount >= 2
5328 && !isPointerDown(mCurrentRawState.buttonState)) {
5329 // Enter quiet time when releasing the button and there are still two or more
5330 // fingers down. This may indicate that one finger was used to press the button
5331 // but it has not gone up yet.
5335 mPointerGesture.quietTime = when;
5340 // Switch states based on button and pointer state.
5342 // Case 1: Quiet time. (QUIET)
5344 ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime
5345 + mConfig.pointerGestureQuietInterval - when) * 0.000001f);
5347 if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) {
5348 *outFinishPreviousGesture = true;
5351 mPointerGesture.activeGestureId = -1;
5352 mPointerGesture.currentGestureMode = PointerGesture::QUIET;
5353 mPointerGesture.currentGestureIdBits.clear();
5355 mPointerVelocityControl.reset();
5356 } else if (isPointerDown(mCurrentRawState.buttonState)) {
5357 // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
5358 // The pointer follows the active touch point.
5359 // Emit DOWN, MOVE, UP events at the pointer location.
5361 // Only the active touch matters; other fingers are ignored. This policy helps
5362 // to handle the case where the user places a second finger on the touch pad
5363 // to apply the necessary force to depress an integrated button below the surface.
5364 // We don't want the second finger to be delivered to applications.
5366 // For this to work well, we need to make sure to track the pointer that is really
5367 // active. If the user first puts one finger down to click then adds another
5368 // finger to drag then the active pointer should switch to the finger that is
5371 ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, "
5372 "currentFingerCount=%d", activeTouchId, currentFingerCount);
5374 // Reset state when just starting.
5375 if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) {
5376 *outFinishPreviousGesture = true;
5377 mPointerGesture.activeGestureId = 0;
5380 // Switch pointers if needed.
5381 // Find the fastest pointer and follow it.
5382 if (activeTouchId >= 0 && currentFingerCount > 1) {
5383 int32_t bestId = -1;
5384 float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
5385 for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) {
5386 uint32_t id = idBits.clearFirstMarkedBit();
5388 if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
5389 float speed = hypotf(vx, vy);
5390 if (speed > bestSpeed) {
5396 if (bestId >= 0 && bestId != activeTouchId) {
5397 mPointerGesture.activeTouchId = activeTouchId = bestId;
5398 activeTouchChanged = true;
5400 ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
5401 "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
5406 float deltaX = 0, deltaY = 0;
5407 if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
5408 const RawPointerData::Pointer& currentPointer =
5409 mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
5410 const RawPointerData::Pointer& lastPointer =
5411 mLastRawState.rawPointerData.pointerForId(activeTouchId);
5412 deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
5413 deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
5415 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
5416 mPointerVelocityControl.move(when, &deltaX, &deltaY);
5418 // Move the pointer using a relative motion.
5419 // When using spots, the click will occur at the position of the anchor
5420 // spot and all other spots will move there.
5421 mPointerController->move(deltaX, deltaY);
5423 mPointerVelocityControl.reset();
5427 mPointerController->getPosition(&x, &y);
5429 mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG;
5430 mPointerGesture.currentGestureIdBits.clear();
5431 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
5432 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
5433 mPointerGesture.currentGestureProperties[0].clear();
5434 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
5435 mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
5436 mPointerGesture.currentGestureCoords[0].clear();
5437 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
5438 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
5439 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
5440 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
5441 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
5442 } else if (currentFingerCount == 0) {
5443 // Case 3. No fingers down and button is not pressed. (NEUTRAL)
5444 if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) {
5445 *outFinishPreviousGesture = true;
5448 // Watch for taps coming out of HOVER or TAP_DRAG mode.
5449 // Checking for taps after TAP_DRAG allows us to detect double-taps.
5450 bool tapped = false;
5451 if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER
5452 || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG)
5453 && lastFingerCount == 1) {
5454 if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
5456 mPointerController->getPosition(&x, &y);
5457 if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop
5458 && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
5460 ALOGD("Gestures: TAP");
5463 mPointerGesture.tapUpTime = when;
5464 getContext()->requestTimeoutAtTime(when
5465 + mConfig.pointerGestureTapDragInterval);
5467 mPointerGesture.activeGestureId = 0;
5468 mPointerGesture.currentGestureMode = PointerGesture::TAP;
5469 mPointerGesture.currentGestureIdBits.clear();
5470 mPointerGesture.currentGestureIdBits.markBit(
5471 mPointerGesture.activeGestureId);
5472 mPointerGesture.currentGestureIdToIndex[
5473 mPointerGesture.activeGestureId] = 0;
5474 mPointerGesture.currentGestureProperties[0].clear();
5475 mPointerGesture.currentGestureProperties[0].id =
5476 mPointerGesture.activeGestureId;
5477 mPointerGesture.currentGestureProperties[0].toolType =
5478 AMOTION_EVENT_TOOL_TYPE_FINGER;
5479 mPointerGesture.currentGestureCoords[0].clear();
5480 mPointerGesture.currentGestureCoords[0].setAxisValue(
5481 AMOTION_EVENT_AXIS_X, mPointerGesture.tapX);
5482 mPointerGesture.currentGestureCoords[0].setAxisValue(
5483 AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY);
5484 mPointerGesture.currentGestureCoords[0].setAxisValue(
5485 AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
5490 ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f",
5491 x - mPointerGesture.tapX,
5492 y - mPointerGesture.tapY);
5497 if (mPointerGesture.tapDownTime != LLONG_MIN) {
5498 ALOGD("Gestures: Not a TAP, %0.3fms since down",
5499 (when - mPointerGesture.tapDownTime) * 0.000001f);
5501 ALOGD("Gestures: Not a TAP, incompatible mode transitions");
5507 mPointerVelocityControl.reset();
5511 ALOGD("Gestures: NEUTRAL");
5513 mPointerGesture.activeGestureId = -1;
5514 mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
5515 mPointerGesture.currentGestureIdBits.clear();
5517 } else if (currentFingerCount == 1) {
5518 // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG)
5519 // The pointer follows the active touch point.
5520 // When in HOVER, emit HOVER_MOVE events at the pointer location.
5521 // When in TAP_DRAG, emit MOVE events at the pointer location.
5522 ALOG_ASSERT(activeTouchId >= 0);
5524 mPointerGesture.currentGestureMode = PointerGesture::HOVER;
5525 if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
5526 if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
5528 mPointerController->getPosition(&x, &y);
5529 if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop
5530 && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
5531 mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
5534 ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
5535 x - mPointerGesture.tapX,
5536 y - mPointerGesture.tapY);
5541 ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up",
5542 (when - mPointerGesture.tapUpTime) * 0.000001f);
5545 } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) {
5546 mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
5549 float deltaX = 0, deltaY = 0;
5550 if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
5551 const RawPointerData::Pointer& currentPointer =
5552 mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
5553 const RawPointerData::Pointer& lastPointer =
5554 mLastRawState.rawPointerData.pointerForId(activeTouchId);
5555 deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
5556 deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
5558 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
5559 mPointerVelocityControl.move(when, &deltaX, &deltaY);
5561 // Move the pointer using a relative motion.
5562 // When using spots, the hover or drag will occur at the position of the anchor spot.
5563 mPointerController->move(deltaX, deltaY);
5565 mPointerVelocityControl.reset();
5569 if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) {
5571 ALOGD("Gestures: TAP_DRAG");
5576 ALOGD("Gestures: HOVER");
5578 if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) {
5579 *outFinishPreviousGesture = true;
5581 mPointerGesture.activeGestureId = 0;
5586 mPointerController->getPosition(&x, &y);
5588 mPointerGesture.currentGestureIdBits.clear();
5589 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
5590 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
5591 mPointerGesture.currentGestureProperties[0].clear();
5592 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
5593 mPointerGesture.currentGestureProperties[0].toolType =
5594 AMOTION_EVENT_TOOL_TYPE_FINGER;
5595 mPointerGesture.currentGestureCoords[0].clear();
5596 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
5597 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
5598 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
5599 down ? 1.0f : 0.0f);
5600 mPointerGesture.currentGestureCoords[0].setAxisValue(
5601 AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
5602 mPointerGesture.currentGestureCoords[0].setAxisValue(
5603 AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
5605 if (lastFingerCount == 0 && currentFingerCount != 0) {
5606 mPointerGesture.resetTap();
5607 mPointerGesture.tapDownTime = when;
5608 mPointerGesture.tapX = x;
5609 mPointerGesture.tapY = y;
5612 // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM)
5613 // We need to provide feedback for each finger that goes down so we cannot wait
5614 // for the fingers to move before deciding what to do.
5616 // The ambiguous case is deciding what to do when there are two fingers down but they
5617 // have not moved enough to determine whether they are part of a drag or part of a
5618 // freeform gesture, or just a press or long-press at the pointer location.
5620 // When there are two fingers we start with the PRESS hypothesis and we generate a
5621 // down at the pointer location.
5623 // When the two fingers move enough or when additional fingers are added, we make
5624 // a decision to transition into SWIPE or FREEFORM mode accordingly.
5625 ALOG_ASSERT(activeTouchId >= 0);
5627 bool settled = when >= mPointerGesture.firstTouchTime
5628 + mConfig.pointerGestureMultitouchSettleInterval;
5629 if (mPointerGesture.lastGestureMode != PointerGesture::PRESS
5630 && mPointerGesture.lastGestureMode != PointerGesture::SWIPE
5631 && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
5632 *outFinishPreviousGesture = true;
5633 } else if (!settled && currentFingerCount > lastFingerCount) {
5634 // Additional pointers have gone down but not yet settled.
5635 // Reset the gesture.
5637 ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, "
5638 "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
5639 + mConfig.pointerGestureMultitouchSettleInterval - when)
5642 *outCancelPreviousGesture = true;
5644 // Continue previous gesture.
5645 mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode;
5648 if (*outFinishPreviousGesture || *outCancelPreviousGesture) {
5649 mPointerGesture.currentGestureMode = PointerGesture::PRESS;
5650 mPointerGesture.activeGestureId = 0;
5651 mPointerGesture.referenceIdBits.clear();
5652 mPointerVelocityControl.reset();
5654 // Use the centroid and pointer location as the reference points for the gesture.
5656 ALOGD("Gestures: Using centroid as reference for MULTITOUCH, "
5657 "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
5658 + mConfig.pointerGestureMultitouchSettleInterval - when)
5661 mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers(
5662 &mPointerGesture.referenceTouchX,
5663 &mPointerGesture.referenceTouchY);
5664 mPointerController->getPosition(&mPointerGesture.referenceGestureX,
5665 &mPointerGesture.referenceGestureY);
5668 // Clear the reference deltas for fingers not yet included in the reference calculation.
5669 for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value
5670 & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) {
5671 uint32_t id = idBits.clearFirstMarkedBit();
5672 mPointerGesture.referenceDeltas[id].dx = 0;
5673 mPointerGesture.referenceDeltas[id].dy = 0;
5675 mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits;
5677 // Add delta for all fingers and calculate a common movement delta.
5678 float commonDeltaX = 0, commonDeltaY = 0;
5679 BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value
5680 & mCurrentCookedState.fingerIdBits.value);
5681 for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
5682 bool first = (idBits == commonIdBits);
5683 uint32_t id = idBits.clearFirstMarkedBit();
5684 const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id);
5685 const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id);
5686 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
5687 delta.dx += cpd.x - lpd.x;
5688 delta.dy += cpd.y - lpd.y;
5691 commonDeltaX = delta.dx;
5692 commonDeltaY = delta.dy;
5694 commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
5695 commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
5699 // Consider transitions from PRESS to SWIPE or MULTITOUCH.
5700 if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
5701 float dist[MAX_POINTER_ID + 1];
5702 int32_t distOverThreshold = 0;
5703 for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
5704 uint32_t id = idBits.clearFirstMarkedBit();
5705 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
5706 dist[id] = hypotf(delta.dx * mPointerXZoomScale,
5707 delta.dy * mPointerYZoomScale);
5708 if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) {
5709 distOverThreshold += 1;
5713 // Only transition when at least two pointers have moved further than
5714 // the minimum distance threshold.
5715 if (distOverThreshold >= 2) {
5716 if (currentFingerCount > 2) {
5717 // There are more than two pointers, switch to FREEFORM.
5719 ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2",
5720 currentFingerCount);
5722 *outCancelPreviousGesture = true;
5723 mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
5725 // There are exactly two pointers.
5726 BitSet32 idBits(mCurrentCookedState.fingerIdBits);
5727 uint32_t id1 = idBits.clearFirstMarkedBit();
5728 uint32_t id2 = idBits.firstMarkedBit();
5729 const RawPointerData::Pointer& p1 =
5730 mCurrentRawState.rawPointerData.pointerForId(id1);
5731 const RawPointerData::Pointer& p2 =
5732 mCurrentRawState.rawPointerData.pointerForId(id2);
5733 float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y);
5734 if (mutualDistance > mPointerGestureMaxSwipeWidth) {
5735 // There are two pointers but they are too far apart for a SWIPE,
5736 // switch to FREEFORM.
5738 ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f",
5739 mutualDistance, mPointerGestureMaxSwipeWidth);
5741 *outCancelPreviousGesture = true;
5742 mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
5744 // There are two pointers. Wait for both pointers to start moving
5745 // before deciding whether this is a SWIPE or FREEFORM gesture.
5746 float dist1 = dist[id1];
5747 float dist2 = dist[id2];
5748 if (dist1 >= mConfig.pointerGestureMultitouchMinDistance
5749 && dist2 >= mConfig.pointerGestureMultitouchMinDistance) {
5750 // Calculate the dot product of the displacement vectors.
5751 // When the vectors are oriented in approximately the same direction,
5752 // the angle betweeen them is near zero and the cosine of the angle
5753 // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
5754 PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1];
5755 PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2];
5756 float dx1 = delta1.dx * mPointerXZoomScale;
5757 float dy1 = delta1.dy * mPointerYZoomScale;
5758 float dx2 = delta2.dx * mPointerXZoomScale;
5759 float dy2 = delta2.dy * mPointerYZoomScale;
5760 float dot = dx1 * dx2 + dy1 * dy2;
5761 float cosine = dot / (dist1 * dist2); // denominator always > 0
5762 if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) {
5763 // Pointers are moving in the same direction. Switch to SWIPE.
5765 ALOGD("Gestures: PRESS transitioned to SWIPE, "
5766 "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
5767 "cosine %0.3f >= %0.3f",
5768 dist1, mConfig.pointerGestureMultitouchMinDistance,
5769 dist2, mConfig.pointerGestureMultitouchMinDistance,
5770 cosine, mConfig.pointerGestureSwipeTransitionAngleCosine);
5772 mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
5774 // Pointers are moving in different directions. Switch to FREEFORM.
5776 ALOGD("Gestures: PRESS transitioned to FREEFORM, "
5777 "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
5778 "cosine %0.3f < %0.3f",
5779 dist1, mConfig.pointerGestureMultitouchMinDistance,
5780 dist2, mConfig.pointerGestureMultitouchMinDistance,
5781 cosine, mConfig.pointerGestureSwipeTransitionAngleCosine);
5783 *outCancelPreviousGesture = true;
5784 mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
5790 } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
5791 // Switch from SWIPE to FREEFORM if additional pointers go down.
5792 // Cancel previous gesture.
5793 if (currentFingerCount > 2) {
5795 ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2",
5796 currentFingerCount);
5798 *outCancelPreviousGesture = true;
5799 mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
5803 // Move the reference points based on the overall group motion of the fingers
5804 // except in PRESS mode while waiting for a transition to occur.
5805 if (mPointerGesture.currentGestureMode != PointerGesture::PRESS
5806 && (commonDeltaX || commonDeltaY)) {
5807 for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
5808 uint32_t id = idBits.clearFirstMarkedBit();
5809 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
5814 mPointerGesture.referenceTouchX += commonDeltaX;
5815 mPointerGesture.referenceTouchY += commonDeltaY;
5817 commonDeltaX *= mPointerXMovementScale;
5818 commonDeltaY *= mPointerYMovementScale;
5820 rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY);
5821 mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
5823 mPointerGesture.referenceGestureX += commonDeltaX;
5824 mPointerGesture.referenceGestureY += commonDeltaY;
5828 if (mPointerGesture.currentGestureMode == PointerGesture::PRESS
5829 || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
5830 // PRESS or SWIPE mode.
5832 ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d,"
5833 "activeGestureId=%d, currentTouchPointerCount=%d",
5834 activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
5836 ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
5838 mPointerGesture.currentGestureIdBits.clear();
5839 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
5840 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
5841 mPointerGesture.currentGestureProperties[0].clear();
5842 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
5843 mPointerGesture.currentGestureProperties[0].toolType =
5844 AMOTION_EVENT_TOOL_TYPE_FINGER;
5845 mPointerGesture.currentGestureCoords[0].clear();
5846 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
5847 mPointerGesture.referenceGestureX);
5848 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
5849 mPointerGesture.referenceGestureY);
5850 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X,
5852 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y,
5854 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
5855 } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
5858 ALOGD("Gestures: FREEFORM activeTouchId=%d,"
5859 "activeGestureId=%d, currentTouchPointerCount=%d",
5860 activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
5862 ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
5864 mPointerGesture.currentGestureIdBits.clear();
5866 BitSet32 mappedTouchIdBits;
5867 BitSet32 usedGestureIdBits;
5868 if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
5869 // Initially, assign the active gesture id to the active touch point
5870 // if there is one. No other touch id bits are mapped yet.
5871 if (!*outCancelPreviousGesture) {
5872 mappedTouchIdBits.markBit(activeTouchId);
5873 usedGestureIdBits.markBit(mPointerGesture.activeGestureId);
5874 mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] =
5875 mPointerGesture.activeGestureId;
5877 mPointerGesture.activeGestureId = -1;
5880 // Otherwise, assume we mapped all touches from the previous frame.
5881 // Reuse all mappings that are still applicable.
5882 mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value
5883 & mCurrentCookedState.fingerIdBits.value;
5884 usedGestureIdBits = mPointerGesture.lastGestureIdBits;
5886 // Check whether we need to choose a new active gesture id because the
5887 // current went went up.
5888 for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value
5889 & ~mCurrentCookedState.fingerIdBits.value);
5890 !upTouchIdBits.isEmpty(); ) {
5891 uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit();
5892 uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
5893 if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) {
5894 mPointerGesture.activeGestureId = -1;
5901 ALOGD("Gestures: FREEFORM follow up "
5902 "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, "
5903 "activeGestureId=%d",
5904 mappedTouchIdBits.value, usedGestureIdBits.value,
5905 mPointerGesture.activeGestureId);
5908 BitSet32 idBits(mCurrentCookedState.fingerIdBits);
5909 for (uint32_t i = 0; i < currentFingerCount; i++) {
5910 uint32_t touchId = idBits.clearFirstMarkedBit();
5912 if (!mappedTouchIdBits.hasBit(touchId)) {
5913 gestureId = usedGestureIdBits.markFirstUnmarkedBit();
5914 mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId;
5916 ALOGD("Gestures: FREEFORM "
5917 "new mapping for touch id %d -> gesture id %d",
5918 touchId, gestureId);
5921 gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId];
5923 ALOGD("Gestures: FREEFORM "
5924 "existing mapping for touch id %d -> gesture id %d",
5925 touchId, gestureId);
5928 mPointerGesture.currentGestureIdBits.markBit(gestureId);
5929 mPointerGesture.currentGestureIdToIndex[gestureId] = i;
5931 const RawPointerData::Pointer& pointer =
5932 mCurrentRawState.rawPointerData.pointerForId(touchId);
5933 float deltaX = (pointer.x - mPointerGesture.referenceTouchX)
5934 * mPointerXZoomScale;
5935 float deltaY = (pointer.y - mPointerGesture.referenceTouchY)
5936 * mPointerYZoomScale;
5937 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
5939 mPointerGesture.currentGestureProperties[i].clear();
5940 mPointerGesture.currentGestureProperties[i].id = gestureId;
5941 mPointerGesture.currentGestureProperties[i].toolType =
5942 AMOTION_EVENT_TOOL_TYPE_FINGER;
5943 mPointerGesture.currentGestureCoords[i].clear();
5944 mPointerGesture.currentGestureCoords[i].setAxisValue(
5945 AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX);
5946 mPointerGesture.currentGestureCoords[i].setAxisValue(
5947 AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY);
5948 mPointerGesture.currentGestureCoords[i].setAxisValue(
5949 AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
5950 mPointerGesture.currentGestureCoords[i].setAxisValue(
5951 AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
5952 mPointerGesture.currentGestureCoords[i].setAxisValue(
5953 AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
5956 if (mPointerGesture.activeGestureId < 0) {
5957 mPointerGesture.activeGestureId =
5958 mPointerGesture.currentGestureIdBits.firstMarkedBit();
5960 ALOGD("Gestures: FREEFORM new "
5961 "activeGestureId=%d", mPointerGesture.activeGestureId);
5967 mPointerController->setButtonState(mCurrentRawState.buttonState);
5970 ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
5971 "currentGestureMode=%d, currentGestureIdBits=0x%08x, "
5972 "lastGestureMode=%d, lastGestureIdBits=0x%08x",
5973 toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture),
5974 mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value,
5975 mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value);
5976 for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) {
5977 uint32_t id = idBits.clearFirstMarkedBit();
5978 uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
5979 const PointerProperties& properties = mPointerGesture.currentGestureProperties[index];
5980 const PointerCoords& coords = mPointerGesture.currentGestureCoords[index];
5981 ALOGD(" currentGesture[%d]: index=%d, toolType=%d, "
5982 "x=%0.3f, y=%0.3f, pressure=%0.3f",
5983 id, index, properties.toolType,
5984 coords.getAxisValue(AMOTION_EVENT_AXIS_X),
5985 coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
5986 coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
5988 for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) {
5989 uint32_t id = idBits.clearFirstMarkedBit();
5990 uint32_t index = mPointerGesture.lastGestureIdToIndex[id];
5991 const PointerProperties& properties = mPointerGesture.lastGestureProperties[index];
5992 const PointerCoords& coords = mPointerGesture.lastGestureCoords[index];
5993 ALOGD(" lastGesture[%d]: index=%d, toolType=%d, "
5994 "x=%0.3f, y=%0.3f, pressure=%0.3f",
5995 id, index, properties.toolType,
5996 coords.getAxisValue(AMOTION_EVENT_AXIS_X),
5997 coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
5998 coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
6004 void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) {
6005 mPointerSimple.currentCoords.clear();
6006 mPointerSimple.currentProperties.clear();
6008 bool down, hovering;
6009 if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
6010 uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit();
6011 uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id];
6012 float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX();
6013 float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY();
6014 mPointerController->setPosition(x, y);
6016 hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id);
6019 mPointerController->getPosition(&x, &y);
6020 mPointerSimple.currentCoords.copyFrom(
6021 mCurrentCookedState.cookedPointerData.pointerCoords[index]);
6022 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
6023 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
6024 mPointerSimple.currentProperties.id = 0;
6025 mPointerSimple.currentProperties.toolType =
6026 mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType;
6027 mLastStylusTime = when;
6033 dispatchPointerSimple(when, policyFlags, down, hovering);
6036 void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) {
6037 abortPointerSimple(when, policyFlags);
6040 void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) {
6041 mPointerSimple.currentCoords.clear();
6042 mPointerSimple.currentProperties.clear();
6044 bool down, hovering;
6045 if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
6046 uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit();
6047 uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
6048 float deltaX = 0, deltaY = 0;
6049 if (mLastCookedState.mouseIdBits.hasBit(id)) {
6050 uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id];
6051 deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x
6052 - mLastRawState.rawPointerData.pointers[lastIndex].x)
6053 * mPointerXMovementScale;
6054 deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y
6055 - mLastRawState.rawPointerData.pointers[lastIndex].y)
6056 * mPointerYMovementScale;
6058 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
6059 mPointerVelocityControl.move(when, &deltaX, &deltaY);
6061 mPointerController->move(deltaX, deltaY);
6063 mPointerVelocityControl.reset();
6066 down = isPointerDown(mCurrentRawState.buttonState);
6070 mPointerController->getPosition(&x, &y);
6071 mPointerSimple.currentCoords.copyFrom(
6072 mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]);
6073 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
6074 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
6075 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
6076 hovering ? 0.0f : 1.0f);
6077 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, x);
6078 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, y);
6079 mPointerSimple.currentProperties.id = 0;
6080 mPointerSimple.currentProperties.toolType =
6081 mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType;
6083 mPointerVelocityControl.reset();
6089 dispatchPointerSimple(when, policyFlags, down, hovering);
6092 void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) {
6093 abortPointerSimple(when, policyFlags);
6095 mPointerVelocityControl.reset();
6098 void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
6099 bool down, bool hovering) {
6100 int32_t metaState = getContext()->getGlobalMetaState();
6102 if (mPointerController != NULL) {
6103 if (down || hovering) {
6104 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
6105 mPointerController->clearSpots();
6106 mPointerController->setButtonState(mCurrentRawState.buttonState);
6107 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
6108 } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
6109 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
6113 if (rejectPalm(when)) { // stylus is currently active
6114 mPointerSimple.reset();
6118 if (mPointerSimple.down && !down) {
6119 mPointerSimple.down = false;
6122 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
6123 AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
6124 mViewport.displayId,
6125 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
6126 mOrientedXPrecision, mOrientedYPrecision,
6127 mPointerSimple.downTime);
6128 getListener()->notifyMotion(&args);
6131 if (mPointerSimple.hovering && !hovering) {
6132 mPointerSimple.hovering = false;
6135 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
6136 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
6137 mViewport.displayId,
6138 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
6139 mOrientedXPrecision, mOrientedYPrecision,
6140 mPointerSimple.downTime);
6141 getListener()->notifyMotion(&args);
6145 if (!mPointerSimple.down) {
6146 mPointerSimple.down = true;
6147 mPointerSimple.downTime = when;
6150 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
6151 AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
6152 mViewport.displayId,
6153 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
6154 mOrientedXPrecision, mOrientedYPrecision,
6155 mPointerSimple.downTime);
6156 getListener()->notifyMotion(&args);
6160 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
6161 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
6162 mViewport.displayId,
6163 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
6164 mOrientedXPrecision, mOrientedYPrecision,
6165 mPointerSimple.downTime);
6166 getListener()->notifyMotion(&args);
6170 if (!mPointerSimple.hovering) {
6171 mPointerSimple.hovering = true;
6173 // Send hover enter.
6174 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
6175 AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
6176 mCurrentRawState.buttonState, 0,
6177 mViewport.displayId,
6178 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
6179 mOrientedXPrecision, mOrientedYPrecision,
6180 mPointerSimple.downTime);
6181 getListener()->notifyMotion(&args);
6185 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
6186 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
6187 mCurrentRawState.buttonState, 0,
6188 mViewport.displayId,
6189 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
6190 mOrientedXPrecision, mOrientedYPrecision,
6191 mPointerSimple.downTime);
6192 getListener()->notifyMotion(&args);
6195 if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
6196 float vscroll = mCurrentRawState.rawVScroll;
6197 float hscroll = mCurrentRawState.rawHScroll;
6198 mWheelYVelocityControl.move(when, NULL, &vscroll);
6199 mWheelXVelocityControl.move(when, &hscroll, NULL);
6202 PointerCoords pointerCoords;
6203 pointerCoords.copyFrom(mPointerSimple.currentCoords);
6204 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
6205 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
6207 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
6208 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
6209 mViewport.displayId,
6210 1, &mPointerSimple.currentProperties, &pointerCoords,
6211 mOrientedXPrecision, mOrientedYPrecision,
6212 mPointerSimple.downTime);
6213 getListener()->notifyMotion(&args);
6217 if (down || hovering) {
6218 mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords);
6219 mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties);
6221 mPointerSimple.reset();
6225 void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) {
6226 mPointerSimple.currentCoords.clear();
6227 mPointerSimple.currentProperties.clear();
6229 dispatchPointerSimple(when, policyFlags, false, false);
6232 void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
6233 int32_t action, int32_t actionButton, int32_t flags,
6234 int32_t metaState, int32_t buttonState, int32_t edgeFlags,
6235 const PointerProperties* properties, const PointerCoords* coords,
6236 const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
6237 float xPrecision, float yPrecision, nsecs_t downTime) {
6239 if (rejectPalm(when)) return;
6241 PointerCoords pointerCoords[MAX_POINTERS];
6242 PointerProperties pointerProperties[MAX_POINTERS];
6243 uint32_t pointerCount = 0;
6244 while (!idBits.isEmpty()) {
6245 uint32_t id = idBits.clearFirstMarkedBit();
6246 uint32_t index = idToIndex[id];
6247 pointerProperties[pointerCount].copyFrom(properties[index]);
6248 pointerCoords[pointerCount].copyFrom(coords[index]);
6250 if (changedId >= 0 && id == uint32_t(changedId)) {
6251 action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
6257 ALOG_ASSERT(pointerCount != 0);
6259 if (changedId >= 0 && pointerCount == 1) {
6260 // Replace initial down and final up action.
6261 // We can compare the action without masking off the changed pointer index
6262 // because we know the index is 0.
6263 if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
6264 action = AMOTION_EVENT_ACTION_DOWN;
6265 } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
6266 action = AMOTION_EVENT_ACTION_UP;
6273 NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
6274 action, actionButton, flags, metaState, buttonState, edgeFlags,
6275 mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
6276 xPrecision, yPrecision, downTime);
6277 getListener()->notifyMotion(&args);
6280 bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties,
6281 const PointerCoords* inCoords, const uint32_t* inIdToIndex,
6282 PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex,
6283 BitSet32 idBits) const {
6284 bool changed = false;
6285 while (!idBits.isEmpty()) {
6286 uint32_t id = idBits.clearFirstMarkedBit();
6287 uint32_t inIndex = inIdToIndex[id];
6288 uint32_t outIndex = outIdToIndex[id];
6290 const PointerProperties& curInProperties = inProperties[inIndex];
6291 const PointerCoords& curInCoords = inCoords[inIndex];
6292 PointerProperties& curOutProperties = outProperties[outIndex];
6293 PointerCoords& curOutCoords = outCoords[outIndex];
6295 if (curInProperties != curOutProperties) {
6296 curOutProperties.copyFrom(curInProperties);
6300 if (curInCoords != curOutCoords) {
6301 curOutCoords.copyFrom(curInCoords);
6308 void TouchInputMapper::fadePointer() {
6309 if (mPointerController != NULL) {
6310 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
6314 nsecs_t TouchInputMapper::mLastStylusTime = 0;
6316 bool TouchInputMapper::rejectPalm(nsecs_t when) {
6317 return (when - mLastStylusTime < mConfig.stylusPalmRejectionTime) &&
6318 mPointerSimple.currentProperties.toolType != AMOTION_EVENT_TOOL_TYPE_STYLUS;
6321 void TouchInputMapper::cancelTouch(nsecs_t when) {
6322 abortPointerUsage(when, 0 /*policyFlags*/);
6323 abortTouches(when, 0 /* policyFlags*/);
6326 bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
6327 return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue
6328 && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue;
6331 const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(
6332 int32_t x, int32_t y) {
6333 size_t numVirtualKeys = mVirtualKeys.size();
6334 for (size_t i = 0; i < numVirtualKeys; i++) {
6335 const VirtualKey& virtualKey = mVirtualKeys[i];
6337 #if DEBUG_VIRTUAL_KEYS
6338 ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
6339 "left=%d, top=%d, right=%d, bottom=%d",
6341 virtualKey.keyCode, virtualKey.scanCode,
6342 virtualKey.hitLeft, virtualKey.hitTop,
6343 virtualKey.hitRight, virtualKey.hitBottom);
6346 if (virtualKey.isHit(x, y)) {
6347 return & virtualKey;
6354 void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) {
6355 uint32_t currentPointerCount = current->rawPointerData.pointerCount;
6356 uint32_t lastPointerCount = last->rawPointerData.pointerCount;
6358 current->rawPointerData.clearIdBits();
6360 if (currentPointerCount == 0) {
6361 // No pointers to assign.
6365 if (lastPointerCount == 0) {
6366 // All pointers are new.
6367 for (uint32_t i = 0; i < currentPointerCount; i++) {
6369 current->rawPointerData.pointers[i].id = id;
6370 current->rawPointerData.idToIndex[id] = i;
6371 current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i));
6376 if (currentPointerCount == 1 && lastPointerCount == 1
6377 && current->rawPointerData.pointers[0].toolType
6378 == last->rawPointerData.pointers[0].toolType) {
6379 // Only one pointer and no change in count so it must have the same id as before.
6380 uint32_t id = last->rawPointerData.pointers[0].id;
6381 current->rawPointerData.pointers[0].id = id;
6382 current->rawPointerData.idToIndex[id] = 0;
6383 current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0));
6388 // We build a heap of squared euclidean distances between current and last pointers
6389 // associated with the current and last pointer indices. Then, we find the best
6390 // match (by distance) for each current pointer.
6391 // The pointers must have the same tool type but it is possible for them to
6392 // transition from hovering to touching or vice-versa while retaining the same id.
6393 PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
6395 uint32_t heapSize = 0;
6396 for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
6397 currentPointerIndex++) {
6398 for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
6399 lastPointerIndex++) {
6400 const RawPointerData::Pointer& currentPointer =
6401 current->rawPointerData.pointers[currentPointerIndex];
6402 const RawPointerData::Pointer& lastPointer =
6403 last->rawPointerData.pointers[lastPointerIndex];
6404 if (currentPointer.toolType == lastPointer.toolType) {
6405 int64_t deltaX = currentPointer.x - lastPointer.x;
6406 int64_t deltaY = currentPointer.y - lastPointer.y;
6408 uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
6410 // Insert new element into the heap (sift up).
6411 heap[heapSize].currentPointerIndex = currentPointerIndex;
6412 heap[heapSize].lastPointerIndex = lastPointerIndex;
6413 heap[heapSize].distance = distance;
6420 for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
6422 for (uint32_t parentIndex = startIndex; ;) {
6423 uint32_t childIndex = parentIndex * 2 + 1;
6424 if (childIndex >= heapSize) {
6428 if (childIndex + 1 < heapSize
6429 && heap[childIndex + 1].distance < heap[childIndex].distance) {
6433 if (heap[parentIndex].distance <= heap[childIndex].distance) {
6437 swap(heap[parentIndex], heap[childIndex]);
6438 parentIndex = childIndex;
6442 #if DEBUG_POINTER_ASSIGNMENT
6443 ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize);
6444 for (size_t i = 0; i < heapSize; i++) {
6445 ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
6446 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
6451 // Pull matches out by increasing order of distance.
6452 // To avoid reassigning pointers that have already been matched, the loop keeps track
6453 // of which last and current pointers have been matched using the matchedXXXBits variables.
6454 // It also tracks the used pointer id bits.
6455 BitSet32 matchedLastBits(0);
6456 BitSet32 matchedCurrentBits(0);
6457 BitSet32 usedIdBits(0);
6459 for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) {
6460 while (heapSize > 0) {
6462 // The first time through the loop, we just consume the root element of
6463 // the heap (the one with smallest distance).
6466 // Previous iterations consumed the root element of the heap.
6467 // Pop root element off of the heap (sift down).
6468 heap[0] = heap[heapSize];
6469 for (uint32_t parentIndex = 0; ;) {
6470 uint32_t childIndex = parentIndex * 2 + 1;
6471 if (childIndex >= heapSize) {
6475 if (childIndex + 1 < heapSize
6476 && heap[childIndex + 1].distance < heap[childIndex].distance) {
6480 if (heap[parentIndex].distance <= heap[childIndex].distance) {
6484 swap(heap[parentIndex], heap[childIndex]);
6485 parentIndex = childIndex;
6488 #if DEBUG_POINTER_ASSIGNMENT
6489 ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize);
6490 for (size_t i = 0; i < heapSize; i++) {
6491 ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
6492 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
6500 uint32_t currentPointerIndex = heap[0].currentPointerIndex;
6501 if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
6503 uint32_t lastPointerIndex = heap[0].lastPointerIndex;
6504 if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
6506 matchedCurrentBits.markBit(currentPointerIndex);
6507 matchedLastBits.markBit(lastPointerIndex);
6509 uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id;
6510 current->rawPointerData.pointers[currentPointerIndex].id = id;
6511 current->rawPointerData.idToIndex[id] = currentPointerIndex;
6512 current->rawPointerData.markIdBit(id,
6513 current->rawPointerData.isHovering(currentPointerIndex));
6514 usedIdBits.markBit(id);
6516 #if DEBUG_POINTER_ASSIGNMENT
6517 ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
6518 lastPointerIndex, currentPointerIndex, id, heap[0].distance);
6524 // Assign fresh ids to pointers that were not matched in the process.
6525 for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) {
6526 uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit();
6527 uint32_t id = usedIdBits.markFirstUnmarkedBit();
6529 current->rawPointerData.pointers[currentPointerIndex].id = id;
6530 current->rawPointerData.idToIndex[id] = currentPointerIndex;
6531 current->rawPointerData.markIdBit(id,
6532 current->rawPointerData.isHovering(currentPointerIndex));
6534 #if DEBUG_POINTER_ASSIGNMENT
6535 ALOGD("assignPointerIds - assigned: cur=%d, id=%d",
6536 currentPointerIndex, id);
6541 int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
6542 if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) {
6543 return AKEY_STATE_VIRTUAL;
6546 size_t numVirtualKeys = mVirtualKeys.size();
6547 for (size_t i = 0; i < numVirtualKeys; i++) {
6548 const VirtualKey& virtualKey = mVirtualKeys[i];
6549 if (virtualKey.keyCode == keyCode) {
6550 return AKEY_STATE_UP;
6554 return AKEY_STATE_UNKNOWN;
6557 int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
6558 if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) {
6559 return AKEY_STATE_VIRTUAL;
6562 size_t numVirtualKeys = mVirtualKeys.size();
6563 for (size_t i = 0; i < numVirtualKeys; i++) {
6564 const VirtualKey& virtualKey = mVirtualKeys[i];
6565 if (virtualKey.scanCode == scanCode) {
6566 return AKEY_STATE_UP;
6570 return AKEY_STATE_UNKNOWN;
6573 bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
6574 const int32_t* keyCodes, uint8_t* outFlags) {
6575 size_t numVirtualKeys = mVirtualKeys.size();
6576 for (size_t i = 0; i < numVirtualKeys; i++) {
6577 const VirtualKey& virtualKey = mVirtualKeys[i];
6579 for (size_t i = 0; i < numCodes; i++) {
6580 if (virtualKey.keyCode == keyCodes[i]) {
6590 // --- SingleTouchInputMapper ---
6592 SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) :
6593 TouchInputMapper(device) {
6596 SingleTouchInputMapper::~SingleTouchInputMapper() {
6599 void SingleTouchInputMapper::reset(nsecs_t when) {
6600 mSingleTouchMotionAccumulator.reset(getDevice());
6602 TouchInputMapper::reset(when);
6605 void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
6606 TouchInputMapper::process(rawEvent);
6608 mSingleTouchMotionAccumulator.process(rawEvent);
6611 void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
6612 if (mTouchButtonAccumulator.isToolActive()) {
6613 outState->rawPointerData.pointerCount = 1;
6614 outState->rawPointerData.idToIndex[0] = 0;
6616 bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
6617 && (mTouchButtonAccumulator.isHovering()
6618 || (mRawPointerAxes.pressure.valid
6619 && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0));
6620 outState->rawPointerData.markIdBit(0, isHovering);
6622 RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0];
6624 outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();
6625 outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();
6626 outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
6627 outPointer.touchMajor = 0;
6628 outPointer.touchMinor = 0;
6629 outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
6630 outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
6631 outPointer.orientation = 0;
6632 outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance();
6633 outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX();
6634 outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY();
6635 outPointer.toolType = mTouchButtonAccumulator.getToolType();
6636 if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
6637 outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
6639 outPointer.isHovering = isHovering;
6643 void SingleTouchInputMapper::configureRawPointerAxes() {
6644 TouchInputMapper::configureRawPointerAxes();
6646 getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x);
6647 getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y);
6648 getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure);
6649 getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor);
6650 getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance);
6651 getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX);
6652 getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY);
6655 bool SingleTouchInputMapper::hasStylus() const {
6656 return mTouchButtonAccumulator.hasStylus();
6660 // --- MultiTouchInputMapper ---
6662 MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) :
6663 TouchInputMapper(device) {
6666 MultiTouchInputMapper::~MultiTouchInputMapper() {
6669 void MultiTouchInputMapper::reset(nsecs_t when) {
6670 mMultiTouchMotionAccumulator.reset(getDevice());
6672 mPointerIdBits.clear();
6674 TouchInputMapper::reset(when);
6677 void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
6678 TouchInputMapper::process(rawEvent);
6680 mMultiTouchMotionAccumulator.process(rawEvent);
6683 void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
6684 size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
6685 size_t outCount = 0;
6686 BitSet32 newPointerIdBits;
6688 for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
6689 const MultiTouchMotionAccumulator::Slot* inSlot =
6690 mMultiTouchMotionAccumulator.getSlot(inIndex);
6691 if (!inSlot->isInUse()) {
6695 if (outCount >= MAX_POINTERS) {
6697 ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
6698 "ignoring the rest.",
6699 getDeviceName().string(), MAX_POINTERS);
6701 break; // too many fingers!
6704 RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
6705 outPointer.x = inSlot->getX();
6706 outPointer.y = inSlot->getY();
6707 outPointer.pressure = inSlot->getPressure();
6708 outPointer.touchMajor = inSlot->getTouchMajor();
6709 outPointer.touchMinor = inSlot->getTouchMinor();
6710 outPointer.toolMajor = inSlot->getToolMajor();
6711 outPointer.toolMinor = inSlot->getToolMinor();
6712 outPointer.orientation = inSlot->getOrientation();
6713 outPointer.distance = inSlot->getDistance();
6714 outPointer.tiltX = 0;
6715 outPointer.tiltY = 0;
6717 outPointer.toolType = inSlot->getToolType();
6718 if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
6719 outPointer.toolType = mTouchButtonAccumulator.getToolType();
6720 if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
6721 outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
6725 bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
6726 && (mTouchButtonAccumulator.isHovering()
6727 || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0));
6728 outPointer.isHovering = isHovering;
6730 // Assign pointer id using tracking id if available.
6731 mHavePointerIds = true;
6732 int32_t trackingId = inSlot->getTrackingId();
6734 if (trackingId >= 0) {
6735 for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
6736 uint32_t n = idBits.clearFirstMarkedBit();
6737 if (mPointerTrackingIdMap[n] == trackingId) {
6742 if (id < 0 && !mPointerIdBits.isFull()) {
6743 id = mPointerIdBits.markFirstUnmarkedBit();
6744 mPointerTrackingIdMap[id] = trackingId;
6748 mHavePointerIds = false;
6749 outState->rawPointerData.clearIdBits();
6750 newPointerIdBits.clear();
6753 outState->rawPointerData.idToIndex[id] = outCount;
6754 outState->rawPointerData.markIdBit(id, isHovering);
6755 newPointerIdBits.markBit(id);
6761 outState->rawPointerData.pointerCount = outCount;
6762 mPointerIdBits = newPointerIdBits;
6764 mMultiTouchMotionAccumulator.finishSync();
6767 void MultiTouchInputMapper::configureRawPointerAxes() {
6768 TouchInputMapper::configureRawPointerAxes();
6770 getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x);
6771 getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y);
6772 getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor);
6773 getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor);
6774 getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor);
6775 getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor);
6776 getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation);
6777 getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure);
6778 getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance);
6779 getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId);
6780 getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot);
6782 if (mRawPointerAxes.trackingId.valid
6783 && mRawPointerAxes.slot.valid
6784 && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) {
6785 size_t slotCount = mRawPointerAxes.slot.maxValue + 1;
6786 if (slotCount > MAX_SLOTS) {
6787 ALOGW("MultiTouch Device %s reported %zu slots but the framework "
6788 "only supports a maximum of %zu slots at this time.",
6789 getDeviceName().string(), slotCount, MAX_SLOTS);
6790 slotCount = MAX_SLOTS;
6792 mMultiTouchMotionAccumulator.configure(getDevice(),
6793 slotCount, true /*usingSlotsProtocol*/);
6795 mMultiTouchMotionAccumulator.configure(getDevice(),
6796 MAX_POINTERS, false /*usingSlotsProtocol*/);
6800 bool MultiTouchInputMapper::hasStylus() const {
6801 return mMultiTouchMotionAccumulator.hasStylus()
6802 || mTouchButtonAccumulator.hasStylus();
6805 // --- ExternalStylusInputMapper
6807 ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) :
6808 InputMapper(device) {
6812 uint32_t ExternalStylusInputMapper::getSources() {
6813 return AINPUT_SOURCE_STYLUS;
6816 void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
6817 InputMapper::populateDeviceInfo(info);
6818 info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS,
6819 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
6822 void ExternalStylusInputMapper::dump(String8& dump) {
6823 dump.append(INDENT2 "External Stylus Input Mapper:\n");
6824 dump.append(INDENT3 "Raw Stylus Axes:\n");
6825 dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure");
6826 dump.append(INDENT3 "Stylus State:\n");
6827 dumpStylusState(dump, mStylusState);
6830 void ExternalStylusInputMapper::configure(nsecs_t when,
6831 const InputReaderConfiguration* config, uint32_t changes) {
6832 getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis);
6833 mTouchButtonAccumulator.configure(getDevice());
6836 void ExternalStylusInputMapper::reset(nsecs_t when) {
6837 InputDevice* device = getDevice();
6838 mSingleTouchMotionAccumulator.reset(device);
6839 mTouchButtonAccumulator.reset(device);
6840 InputMapper::reset(when);
6843 void ExternalStylusInputMapper::process(const RawEvent* rawEvent) {
6844 mSingleTouchMotionAccumulator.process(rawEvent);
6845 mTouchButtonAccumulator.process(rawEvent);
6847 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
6848 sync(rawEvent->when);
6852 void ExternalStylusInputMapper::sync(nsecs_t when) {
6853 mStylusState.clear();
6855 mStylusState.when = when;
6857 mStylusState.toolType = mTouchButtonAccumulator.getToolType();
6858 if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
6859 mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
6862 int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
6863 if (mRawPressureAxis.valid) {
6864 mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue;
6865 } else if (mTouchButtonAccumulator.isToolActive()) {
6866 mStylusState.pressure = 1.0f;
6868 mStylusState.pressure = 0.0f;
6871 mStylusState.buttons = mTouchButtonAccumulator.getButtonState();
6873 mContext->dispatchExternalStylusState(mStylusState);
6877 // --- JoystickInputMapper ---
6879 JoystickInputMapper::JoystickInputMapper(InputDevice* device) :
6880 InputMapper(device) {
6883 JoystickInputMapper::~JoystickInputMapper() {
6886 uint32_t JoystickInputMapper::getSources() {
6887 return AINPUT_SOURCE_JOYSTICK;
6890 void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
6891 InputMapper::populateDeviceInfo(info);
6893 for (size_t i = 0; i < mAxes.size(); i++) {
6894 const Axis& axis = mAxes.valueAt(i);
6895 addMotionRange(axis.axisInfo.axis, axis, info);
6897 if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
6898 addMotionRange(axis.axisInfo.highAxis, axis, info);
6904 void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis,
6905 InputDeviceInfo* info) {
6906 info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK,
6907 axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
6908 /* In order to ease the transition for developers from using the old axes
6909 * to the newer, more semantically correct axes, we'll continue to register
6910 * the old axes as duplicates of their corresponding new ones. */
6911 int32_t compatAxis = getCompatAxis(axisId);
6912 if (compatAxis >= 0) {
6913 info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK,
6914 axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
6918 /* A mapping from axes the joystick actually has to the axes that should be
6919 * artificially created for compatibility purposes.
6920 * Returns -1 if no compatibility axis is needed. */
6921 int32_t JoystickInputMapper::getCompatAxis(int32_t axis) {
6923 case AMOTION_EVENT_AXIS_LTRIGGER:
6924 return AMOTION_EVENT_AXIS_BRAKE;
6925 case AMOTION_EVENT_AXIS_RTRIGGER:
6926 return AMOTION_EVENT_AXIS_GAS;
6931 void JoystickInputMapper::dump(String8& dump) {
6932 dump.append(INDENT2 "Joystick Input Mapper:\n");
6934 dump.append(INDENT3 "Axes:\n");
6935 size_t numAxes = mAxes.size();
6936 for (size_t i = 0; i < numAxes; i++) {
6937 const Axis& axis = mAxes.valueAt(i);
6938 const char* label = getAxisLabel(axis.axisInfo.axis);
6940 dump.appendFormat(INDENT4 "%s", label);
6942 dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis);
6944 if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
6945 label = getAxisLabel(axis.axisInfo.highAxis);
6947 dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue);
6949 dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis,
6950 axis.axisInfo.splitValue);
6952 } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) {
6953 dump.append(" (invert)");
6956 dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n",
6957 axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
6958 dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, "
6959 "highScale=%0.5f, highOffset=%0.5f\n",
6960 axis.scale, axis.offset, axis.highScale, axis.highOffset);
6961 dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, "
6962 "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n",
6963 mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
6964 axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution);
6968 void JoystickInputMapper::configure(nsecs_t when,
6969 const InputReaderConfiguration* config, uint32_t changes) {
6970 InputMapper::configure(when, config, changes);
6972 if (!changes) { // first time only
6973 // Collect all axes.
6974 for (int32_t abs = 0; abs <= ABS_MAX; abs++) {
6975 if (!(getAbsAxisUsage(abs, getDevice()->getClasses())
6976 & INPUT_DEVICE_CLASS_JOYSTICK)) {
6977 continue; // axis must be claimed by a different device
6980 RawAbsoluteAxisInfo rawAxisInfo;
6981 getAbsoluteAxisInfo(abs, &rawAxisInfo);
6982 if (rawAxisInfo.valid) {
6985 bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo);
6986 if (!explicitlyMapped) {
6987 // Axis is not explicitly mapped, will choose a generic axis later.
6988 axisInfo.mode = AxisInfo::MODE_NORMAL;
6992 // Apply flat override.
6993 int32_t rawFlat = axisInfo.flatOverride < 0
6994 ? rawAxisInfo.flat : axisInfo.flatOverride;
6996 // Calculate scaling factors and limits.
6998 if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
6999 float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
7000 float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
7001 axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
7002 scale, 0.0f, highScale, 0.0f,
7003 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
7004 rawAxisInfo.resolution * scale);
7005 } else if (isCenteredAxis(axisInfo.axis)) {
7006 float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
7007 float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
7008 axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
7009 scale, offset, scale, offset,
7010 -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
7011 rawAxisInfo.resolution * scale);
7013 float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
7014 axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
7015 scale, 0.0f, scale, 0.0f,
7016 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
7017 rawAxisInfo.resolution * scale);
7020 // To eliminate noise while the joystick is at rest, filter out small variations
7021 // in axis values up front.
7022 axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f;
7024 mAxes.add(abs, axis);
7028 // If there are too many axes, start dropping them.
7029 // Prefer to keep explicitly mapped axes.
7030 if (mAxes.size() > PointerCoords::MAX_AXES) {
7031 ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.",
7032 getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES);
7037 // Assign generic axis ids to remaining axes.
7038 int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1;
7039 size_t numAxes = mAxes.size();
7040 for (size_t i = 0; i < numAxes; i++) {
7041 Axis& axis = mAxes.editValueAt(i);
7042 if (axis.axisInfo.axis < 0) {
7043 while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16
7044 && haveAxis(nextGenericAxisId)) {
7045 nextGenericAxisId += 1;
7048 if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) {
7049 axis.axisInfo.axis = nextGenericAxisId;
7050 nextGenericAxisId += 1;
7052 ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
7053 "have already been assigned to other axes.",
7054 getDeviceName().string(), mAxes.keyAt(i));
7055 mAxes.removeItemsAt(i--);
7063 bool JoystickInputMapper::haveAxis(int32_t axisId) {
7064 size_t numAxes = mAxes.size();
7065 for (size_t i = 0; i < numAxes; i++) {
7066 const Axis& axis = mAxes.valueAt(i);
7067 if (axis.axisInfo.axis == axisId
7068 || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT
7069 && axis.axisInfo.highAxis == axisId)) {
7076 void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) {
7077 size_t i = mAxes.size();
7078 while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) {
7079 if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) {
7082 ALOGI("Discarding joystick '%s' axis %d because there are too many axes.",
7083 getDeviceName().string(), mAxes.keyAt(i));
7084 mAxes.removeItemsAt(i);
7088 bool JoystickInputMapper::isCenteredAxis(int32_t axis) {
7090 case AMOTION_EVENT_AXIS_X:
7091 case AMOTION_EVENT_AXIS_Y:
7092 case AMOTION_EVENT_AXIS_Z:
7093 case AMOTION_EVENT_AXIS_RX:
7094 case AMOTION_EVENT_AXIS_RY:
7095 case AMOTION_EVENT_AXIS_RZ:
7096 case AMOTION_EVENT_AXIS_HAT_X:
7097 case AMOTION_EVENT_AXIS_HAT_Y:
7098 case AMOTION_EVENT_AXIS_ORIENTATION:
7099 case AMOTION_EVENT_AXIS_RUDDER:
7100 case AMOTION_EVENT_AXIS_WHEEL:
7107 void JoystickInputMapper::reset(nsecs_t when) {
7108 // Recenter all axes.
7109 size_t numAxes = mAxes.size();
7110 for (size_t i = 0; i < numAxes; i++) {
7111 Axis& axis = mAxes.editValueAt(i);
7115 InputMapper::reset(when);
7118 void JoystickInputMapper::process(const RawEvent* rawEvent) {
7119 switch (rawEvent->type) {
7121 ssize_t index = mAxes.indexOfKey(rawEvent->code);
7123 Axis& axis = mAxes.editValueAt(index);
7124 float newValue, highNewValue;
7125 switch (axis.axisInfo.mode) {
7126 case AxisInfo::MODE_INVERT:
7127 newValue = (axis.rawAxisInfo.maxValue - rawEvent->value)
7128 * axis.scale + axis.offset;
7129 highNewValue = 0.0f;
7131 case AxisInfo::MODE_SPLIT:
7132 if (rawEvent->value < axis.axisInfo.splitValue) {
7133 newValue = (axis.axisInfo.splitValue - rawEvent->value)
7134 * axis.scale + axis.offset;
7135 highNewValue = 0.0f;
7136 } else if (rawEvent->value > axis.axisInfo.splitValue) {
7138 highNewValue = (rawEvent->value - axis.axisInfo.splitValue)
7139 * axis.highScale + axis.highOffset;
7142 highNewValue = 0.0f;
7146 newValue = rawEvent->value * axis.scale + axis.offset;
7147 highNewValue = 0.0f;
7150 axis.newValue = newValue;
7151 axis.highNewValue = highNewValue;
7157 switch (rawEvent->code) {
7159 sync(rawEvent->when, false /*force*/);
7166 void JoystickInputMapper::sync(nsecs_t when, bool force) {
7167 if (!filterAxes(force)) {
7171 int32_t metaState = mContext->getGlobalMetaState();
7172 int32_t buttonState = 0;
7174 PointerProperties pointerProperties;
7175 pointerProperties.clear();
7176 pointerProperties.id = 0;
7177 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
7179 PointerCoords pointerCoords;
7180 pointerCoords.clear();
7182 size_t numAxes = mAxes.size();
7183 for (size_t i = 0; i < numAxes; i++) {
7184 const Axis& axis = mAxes.valueAt(i);
7185 setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue);
7186 if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
7187 setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis,
7188 axis.highCurrentValue);
7192 // Moving a joystick axis should not wake the device because joysticks can
7193 // be fairly noisy even when not in use. On the other hand, pushing a gamepad
7194 // button will likely wake the device.
7195 // TODO: Use the input device configuration to control this behavior more finely.
7196 uint32_t policyFlags = 0;
7198 NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
7199 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
7200 ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0);
7201 getListener()->notifyMotion(&args);
7204 void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords,
7205 int32_t axis, float value) {
7206 pointerCoords->setAxisValue(axis, value);
7207 /* In order to ease the transition for developers from using the old axes
7208 * to the newer, more semantically correct axes, we'll continue to produce
7209 * values for the old axes as mirrors of the value of their corresponding
7211 int32_t compatAxis = getCompatAxis(axis);
7212 if (compatAxis >= 0) {
7213 pointerCoords->setAxisValue(compatAxis, value);
7217 bool JoystickInputMapper::filterAxes(bool force) {
7218 bool atLeastOneSignificantChange = force;
7219 size_t numAxes = mAxes.size();
7220 for (size_t i = 0; i < numAxes; i++) {
7221 Axis& axis = mAxes.editValueAt(i);
7222 if (force || hasValueChangedSignificantly(axis.filter,
7223 axis.newValue, axis.currentValue, axis.min, axis.max)) {
7224 axis.currentValue = axis.newValue;
7225 atLeastOneSignificantChange = true;
7227 if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
7228 if (force || hasValueChangedSignificantly(axis.filter,
7229 axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) {
7230 axis.highCurrentValue = axis.highNewValue;
7231 atLeastOneSignificantChange = true;
7235 return atLeastOneSignificantChange;
7238 bool JoystickInputMapper::hasValueChangedSignificantly(
7239 float filter, float newValue, float currentValue, float min, float max) {
7240 if (newValue != currentValue) {
7241 // Filter out small changes in value unless the value is converging on the axis
7242 // bounds or center point. This is intended to reduce the amount of information
7243 // sent to applications by particularly noisy joysticks (such as PS3).
7244 if (fabs(newValue - currentValue) > filter
7245 || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min)
7246 || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max)
7247 || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) {
7254 bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange(
7255 float filter, float newValue, float currentValue, float thresholdValue) {
7256 float newDistance = fabs(newValue - thresholdValue);
7257 if (newDistance < filter) {
7258 float oldDistance = fabs(currentValue - thresholdValue);
7259 if (newDistance < oldDistance) {
7266 } // namespace android