widget/gonk/libui/InputReader.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 * Copyright (C) 2010 The Android Open Source Project
michael@0 3 *
michael@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 5 * you may not use this file except in compliance with the License.
michael@0 6 * You may obtain a copy of the License at
michael@0 7 *
michael@0 8 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 9 *
michael@0 10 * Unless required by applicable law or agreed to in writing, software
michael@0 11 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 13 * See the License for the specific language governing permissions and
michael@0 14 * limitations under the License.
michael@0 15 */
michael@0 16
michael@0 17 #define LOG_TAG "InputReader"
michael@0 18
michael@0 19 //#define LOG_NDEBUG 0
michael@0 20 #include "cutils_log.h"
michael@0 21
michael@0 22 // Log debug messages for each raw event received from the EventHub.
michael@0 23 #define DEBUG_RAW_EVENTS 0
michael@0 24
michael@0 25 // Log debug messages about touch screen filtering hacks.
michael@0 26 #define DEBUG_HACKS 0
michael@0 27
michael@0 28 // Log debug messages about virtual key processing.
michael@0 29 #define DEBUG_VIRTUAL_KEYS 0
michael@0 30
michael@0 31 // Log debug messages about pointers.
michael@0 32 #define DEBUG_POINTERS 0
michael@0 33
michael@0 34 // Log debug messages about pointer assignment calculations.
michael@0 35 #define DEBUG_POINTER_ASSIGNMENT 0
michael@0 36
michael@0 37 // Log debug messages about gesture detection.
michael@0 38 #define DEBUG_GESTURES 0
michael@0 39
michael@0 40 // Log debug messages about the vibrator.
michael@0 41 #define DEBUG_VIBRATOR 0
michael@0 42
michael@0 43 #include "InputReader.h"
michael@0 44
michael@0 45 #include "Keyboard.h"
michael@0 46 #include "VirtualKeyMap.h"
michael@0 47
michael@0 48 #include <stddef.h>
michael@0 49 #include <stdlib.h>
michael@0 50 #include <unistd.h>
michael@0 51 #include <errno.h>
michael@0 52 #include <limits.h>
michael@0 53 #include <math.h>
michael@0 54
michael@0 55 #define INDENT " "
michael@0 56 #define INDENT2 " "
michael@0 57 #define INDENT3 " "
michael@0 58 #define INDENT4 " "
michael@0 59 #define INDENT5 " "
michael@0 60
michael@0 61 namespace android {
michael@0 62
michael@0 63 // --- Constants ---
michael@0 64
michael@0 65 // Maximum number of slots supported when using the slot-based Multitouch Protocol B.
michael@0 66 static const size_t MAX_SLOTS = 32;
michael@0 67
michael@0 68 // --- Static Functions ---
michael@0 69
michael@0 70 template<typename T>
michael@0 71 inline static T abs(const T& value) {
michael@0 72 return value < 0 ? - value : value;
michael@0 73 }
michael@0 74
michael@0 75 template<typename T>
michael@0 76 inline static T min(const T& a, const T& b) {
michael@0 77 return a < b ? a : b;
michael@0 78 }
michael@0 79
michael@0 80 template<typename T>
michael@0 81 inline static void swap(T& a, T& b) {
michael@0 82 T temp = a;
michael@0 83 a = b;
michael@0 84 b = temp;
michael@0 85 }
michael@0 86
michael@0 87 inline static float avg(float x, float y) {
michael@0 88 return (x + y) / 2;
michael@0 89 }
michael@0 90
michael@0 91 inline static float distance(float x1, float y1, float x2, float y2) {
michael@0 92 return hypotf(x1 - x2, y1 - y2);
michael@0 93 }
michael@0 94
michael@0 95 inline static int32_t signExtendNybble(int32_t value) {
michael@0 96 return value >= 8 ? value - 16 : value;
michael@0 97 }
michael@0 98
michael@0 99 static inline const char* toString(bool value) {
michael@0 100 return value ? "true" : "false";
michael@0 101 }
michael@0 102
michael@0 103 static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation,
michael@0 104 const int32_t map[][4], size_t mapSize) {
michael@0 105 if (orientation != DISPLAY_ORIENTATION_0) {
michael@0 106 for (size_t i = 0; i < mapSize; i++) {
michael@0 107 if (value == map[i][0]) {
michael@0 108 return map[i][orientation];
michael@0 109 }
michael@0 110 }
michael@0 111 }
michael@0 112 return value;
michael@0 113 }
michael@0 114
michael@0 115 static const int32_t keyCodeRotationMap[][4] = {
michael@0 116 // key codes enumerated counter-clockwise with the original (unrotated) key first
michael@0 117 // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
michael@0 118 { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT },
michael@0 119 { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN },
michael@0 120 { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT },
michael@0 121 { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP },
michael@0 122 };
michael@0 123 static const size_t keyCodeRotationMapSize =
michael@0 124 sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
michael@0 125
michael@0 126 static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
michael@0 127 return rotateValueUsingRotationMap(keyCode, orientation,
michael@0 128 keyCodeRotationMap, keyCodeRotationMapSize);
michael@0 129 }
michael@0 130
michael@0 131 static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) {
michael@0 132 float temp;
michael@0 133 switch (orientation) {
michael@0 134 case DISPLAY_ORIENTATION_90:
michael@0 135 temp = *deltaX;
michael@0 136 *deltaX = *deltaY;
michael@0 137 *deltaY = -temp;
michael@0 138 break;
michael@0 139
michael@0 140 case DISPLAY_ORIENTATION_180:
michael@0 141 *deltaX = -*deltaX;
michael@0 142 *deltaY = -*deltaY;
michael@0 143 break;
michael@0 144
michael@0 145 case DISPLAY_ORIENTATION_270:
michael@0 146 temp = *deltaX;
michael@0 147 *deltaX = -*deltaY;
michael@0 148 *deltaY = temp;
michael@0 149 break;
michael@0 150 }
michael@0 151 }
michael@0 152
michael@0 153 static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
michael@0 154 return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0;
michael@0 155 }
michael@0 156
michael@0 157 // Returns true if the pointer should be reported as being down given the specified
michael@0 158 // button states. This determines whether the event is reported as a touch event.
michael@0 159 static bool isPointerDown(int32_t buttonState) {
michael@0 160 return buttonState &
michael@0 161 (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY
michael@0 162 | AMOTION_EVENT_BUTTON_TERTIARY);
michael@0 163 }
michael@0 164
michael@0 165 static float calculateCommonVector(float a, float b) {
michael@0 166 if (a > 0 && b > 0) {
michael@0 167 return a < b ? a : b;
michael@0 168 } else if (a < 0 && b < 0) {
michael@0 169 return a > b ? a : b;
michael@0 170 } else {
michael@0 171 return 0;
michael@0 172 }
michael@0 173 }
michael@0 174
michael@0 175 static void synthesizeButtonKey(InputReaderContext* context, int32_t action,
michael@0 176 nsecs_t when, int32_t deviceId, uint32_t source,
michael@0 177 uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState,
michael@0 178 int32_t buttonState, int32_t keyCode) {
michael@0 179 if (
michael@0 180 (action == AKEY_EVENT_ACTION_DOWN
michael@0 181 && !(lastButtonState & buttonState)
michael@0 182 && (currentButtonState & buttonState))
michael@0 183 || (action == AKEY_EVENT_ACTION_UP
michael@0 184 && (lastButtonState & buttonState)
michael@0 185 && !(currentButtonState & buttonState))) {
michael@0 186 NotifyKeyArgs args(when, deviceId, source, policyFlags,
michael@0 187 action, 0, keyCode, 0, context->getGlobalMetaState(), when);
michael@0 188 context->getListener()->notifyKey(&args);
michael@0 189 }
michael@0 190 }
michael@0 191
michael@0 192 static void synthesizeButtonKeys(InputReaderContext* context, int32_t action,
michael@0 193 nsecs_t when, int32_t deviceId, uint32_t source,
michael@0 194 uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) {
michael@0 195 synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
michael@0 196 lastButtonState, currentButtonState,
michael@0 197 AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK);
michael@0 198 synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
michael@0 199 lastButtonState, currentButtonState,
michael@0 200 AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD);
michael@0 201 }
michael@0 202
michael@0 203
michael@0 204 // --- InputReaderConfiguration ---
michael@0 205
michael@0 206 bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const {
michael@0 207 const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay;
michael@0 208 if (viewport.displayId >= 0) {
michael@0 209 *outViewport = viewport;
michael@0 210 return true;
michael@0 211 }
michael@0 212 return false;
michael@0 213 }
michael@0 214
michael@0 215 void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) {
michael@0 216 DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay;
michael@0 217 v = viewport;
michael@0 218 }
michael@0 219
michael@0 220
michael@0 221 // --- InputReader ---
michael@0 222
michael@0 223 InputReader::InputReader(const sp<EventHubInterface>& eventHub,
michael@0 224 const sp<InputReaderPolicyInterface>& policy,
michael@0 225 const sp<InputListenerInterface>& listener) :
michael@0 226 mContext(this), mEventHub(eventHub), mPolicy(policy),
michael@0 227 mGlobalMetaState(0), mGeneration(1),
michael@0 228 mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
michael@0 229 mConfigurationChangesToRefresh(0) {
michael@0 230 mQueuedListener = new QueuedInputListener(listener);
michael@0 231
michael@0 232 { // acquire lock
michael@0 233 AutoMutex _l(mLock);
michael@0 234
michael@0 235 refreshConfigurationLocked(0);
michael@0 236 updateGlobalMetaStateLocked();
michael@0 237 } // release lock
michael@0 238 }
michael@0 239
michael@0 240 InputReader::~InputReader() {
michael@0 241 for (size_t i = 0; i < mDevices.size(); i++) {
michael@0 242 delete mDevices.valueAt(i);
michael@0 243 }
michael@0 244 }
michael@0 245
michael@0 246 void InputReader::loopOnce() {
michael@0 247 int32_t oldGeneration;
michael@0 248 int32_t timeoutMillis;
michael@0 249 bool inputDevicesChanged = false;
michael@0 250 Vector<InputDeviceInfo> inputDevices;
michael@0 251 { // acquire lock
michael@0 252 AutoMutex _l(mLock);
michael@0 253
michael@0 254 oldGeneration = mGeneration;
michael@0 255 timeoutMillis = -1;
michael@0 256
michael@0 257 uint32_t changes = mConfigurationChangesToRefresh;
michael@0 258 if (changes) {
michael@0 259 mConfigurationChangesToRefresh = 0;
michael@0 260 timeoutMillis = 0;
michael@0 261 refreshConfigurationLocked(changes);
michael@0 262 } else if (mNextTimeout != LLONG_MAX) {
michael@0 263 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
michael@0 264 timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
michael@0 265 }
michael@0 266 } // release lock
michael@0 267
michael@0 268 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
michael@0 269
michael@0 270 { // acquire lock
michael@0 271 AutoMutex _l(mLock);
michael@0 272 mReaderIsAliveCondition.broadcast();
michael@0 273
michael@0 274 if (count) {
michael@0 275 processEventsLocked(mEventBuffer, count);
michael@0 276 }
michael@0 277
michael@0 278 if (mNextTimeout != LLONG_MAX) {
michael@0 279 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
michael@0 280 if (now >= mNextTimeout) {
michael@0 281 #if DEBUG_RAW_EVENTS
michael@0 282 ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
michael@0 283 #endif
michael@0 284 mNextTimeout = LLONG_MAX;
michael@0 285 timeoutExpiredLocked(now);
michael@0 286 }
michael@0 287 }
michael@0 288
michael@0 289 if (oldGeneration != mGeneration) {
michael@0 290 inputDevicesChanged = true;
michael@0 291 getInputDevicesLocked(inputDevices);
michael@0 292 }
michael@0 293 } // release lock
michael@0 294
michael@0 295 // Send out a message that the describes the changed input devices.
michael@0 296 if (inputDevicesChanged) {
michael@0 297 mPolicy->notifyInputDevicesChanged(inputDevices);
michael@0 298 }
michael@0 299
michael@0 300 // Flush queued events out to the listener.
michael@0 301 // This must happen outside of the lock because the listener could potentially call
michael@0 302 // back into the InputReader's methods, such as getScanCodeState, or become blocked
michael@0 303 // on another thread similarly waiting to acquire the InputReader lock thereby
michael@0 304 // resulting in a deadlock. This situation is actually quite plausible because the
michael@0 305 // listener is actually the input dispatcher, which calls into the window manager,
michael@0 306 // which occasionally calls into the input reader.
michael@0 307 mQueuedListener->flush();
michael@0 308 }
michael@0 309
michael@0 310 void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
michael@0 311 for (const RawEvent* rawEvent = rawEvents; count;) {
michael@0 312 int32_t type = rawEvent->type;
michael@0 313 size_t batchSize = 1;
michael@0 314 if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
michael@0 315 int32_t deviceId = rawEvent->deviceId;
michael@0 316 while (batchSize < count) {
michael@0 317 if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
michael@0 318 || rawEvent[batchSize].deviceId != deviceId) {
michael@0 319 break;
michael@0 320 }
michael@0 321 batchSize += 1;
michael@0 322 }
michael@0 323 #if DEBUG_RAW_EVENTS
michael@0 324 ALOGD("BatchSize: %d Count: %d", batchSize, count);
michael@0 325 #endif
michael@0 326 processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
michael@0 327 } else {
michael@0 328 switch (rawEvent->type) {
michael@0 329 case EventHubInterface::DEVICE_ADDED:
michael@0 330 addDeviceLocked(rawEvent->when, rawEvent->deviceId);
michael@0 331 break;
michael@0 332 case EventHubInterface::DEVICE_REMOVED:
michael@0 333 removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
michael@0 334 break;
michael@0 335 case EventHubInterface::FINISHED_DEVICE_SCAN:
michael@0 336 handleConfigurationChangedLocked(rawEvent->when);
michael@0 337 break;
michael@0 338 default:
michael@0 339 ALOG_ASSERT(false); // can't happen
michael@0 340 break;
michael@0 341 }
michael@0 342 }
michael@0 343 count -= batchSize;
michael@0 344 rawEvent += batchSize;
michael@0 345 }
michael@0 346 }
michael@0 347
michael@0 348 void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
michael@0 349 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
michael@0 350 if (deviceIndex >= 0) {
michael@0 351 ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
michael@0 352 return;
michael@0 353 }
michael@0 354
michael@0 355 InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
michael@0 356 uint32_t classes = mEventHub->getDeviceClasses(deviceId);
michael@0 357
michael@0 358 InputDevice* device = createDeviceLocked(deviceId, identifier, classes);
michael@0 359 device->configure(when, &mConfig, 0);
michael@0 360 device->reset(when);
michael@0 361
michael@0 362 if (device->isIgnored()) {
michael@0 363 ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
michael@0 364 identifier.name.string());
michael@0 365 } else {
michael@0 366 ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
michael@0 367 identifier.name.string(), device->getSources());
michael@0 368 }
michael@0 369
michael@0 370 mDevices.add(deviceId, device);
michael@0 371 bumpGenerationLocked();
michael@0 372 }
michael@0 373
michael@0 374 void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
michael@0 375 InputDevice* device = NULL;
michael@0 376 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
michael@0 377 if (deviceIndex < 0) {
michael@0 378 ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
michael@0 379 return;
michael@0 380 }
michael@0 381
michael@0 382 device = mDevices.valueAt(deviceIndex);
michael@0 383 mDevices.removeItemsAt(deviceIndex, 1);
michael@0 384 bumpGenerationLocked();
michael@0 385
michael@0 386 if (device->isIgnored()) {
michael@0 387 ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)",
michael@0 388 device->getId(), device->getName().string());
michael@0 389 } else {
michael@0 390 ALOGI("Device removed: id=%d, name='%s', sources=0x%08x",
michael@0 391 device->getId(), device->getName().string(), device->getSources());
michael@0 392 }
michael@0 393
michael@0 394 device->reset(when);
michael@0 395 delete device;
michael@0 396 }
michael@0 397
michael@0 398 InputDevice* InputReader::createDeviceLocked(int32_t deviceId,
michael@0 399 const InputDeviceIdentifier& identifier, uint32_t classes) {
michael@0 400 InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
michael@0 401 identifier, classes);
michael@0 402
michael@0 403 // External devices.
michael@0 404 if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
michael@0 405 device->setExternal(true);
michael@0 406 }
michael@0 407
michael@0 408 // Switch-like devices.
michael@0 409 if (classes & INPUT_DEVICE_CLASS_SWITCH) {
michael@0 410 device->addMapper(new SwitchInputMapper(device));
michael@0 411 }
michael@0 412
michael@0 413 // Vibrator-like devices.
michael@0 414 if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
michael@0 415 device->addMapper(new VibratorInputMapper(device));
michael@0 416 }
michael@0 417
michael@0 418 // Keyboard-like devices.
michael@0 419 uint32_t keyboardSource = 0;
michael@0 420 int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
michael@0 421 if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
michael@0 422 keyboardSource |= AINPUT_SOURCE_KEYBOARD;
michael@0 423 }
michael@0 424 if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
michael@0 425 keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
michael@0 426 }
michael@0 427 if (classes & INPUT_DEVICE_CLASS_DPAD) {
michael@0 428 keyboardSource |= AINPUT_SOURCE_DPAD;
michael@0 429 }
michael@0 430 if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
michael@0 431 keyboardSource |= AINPUT_SOURCE_GAMEPAD;
michael@0 432 }
michael@0 433
michael@0 434 if (keyboardSource != 0) {
michael@0 435 device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
michael@0 436 }
michael@0 437
michael@0 438 // Cursor-like devices.
michael@0 439 if (classes & INPUT_DEVICE_CLASS_CURSOR) {
michael@0 440 device->addMapper(new CursorInputMapper(device));
michael@0 441 }
michael@0 442
michael@0 443 // Touchscreens and touchpad devices.
michael@0 444 if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
michael@0 445 device->addMapper(new MultiTouchInputMapper(device));
michael@0 446 } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
michael@0 447 device->addMapper(new SingleTouchInputMapper(device));
michael@0 448 }
michael@0 449
michael@0 450 // Joystick-like devices.
michael@0 451 if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
michael@0 452 device->addMapper(new JoystickInputMapper(device));
michael@0 453 }
michael@0 454
michael@0 455 return device;
michael@0 456 }
michael@0 457
michael@0 458 void InputReader::processEventsForDeviceLocked(int32_t deviceId,
michael@0 459 const RawEvent* rawEvents, size_t count) {
michael@0 460 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
michael@0 461 if (deviceIndex < 0) {
michael@0 462 ALOGW("Discarding event for unknown deviceId %d.", deviceId);
michael@0 463 return;
michael@0 464 }
michael@0 465
michael@0 466 InputDevice* device = mDevices.valueAt(deviceIndex);
michael@0 467 if (device->isIgnored()) {
michael@0 468 //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
michael@0 469 return;
michael@0 470 }
michael@0 471
michael@0 472 device->process(rawEvents, count);
michael@0 473 }
michael@0 474
michael@0 475 void InputReader::timeoutExpiredLocked(nsecs_t when) {
michael@0 476 for (size_t i = 0; i < mDevices.size(); i++) {
michael@0 477 InputDevice* device = mDevices.valueAt(i);
michael@0 478 if (!device->isIgnored()) {
michael@0 479 device->timeoutExpired(when);
michael@0 480 }
michael@0 481 }
michael@0 482 }
michael@0 483
michael@0 484 void InputReader::handleConfigurationChangedLocked(nsecs_t when) {
michael@0 485 // Reset global meta state because it depends on the list of all configured devices.
michael@0 486 updateGlobalMetaStateLocked();
michael@0 487
michael@0 488 // Enqueue configuration changed.
michael@0 489 NotifyConfigurationChangedArgs args(when);
michael@0 490 mQueuedListener->notifyConfigurationChanged(&args);
michael@0 491 }
michael@0 492
michael@0 493 void InputReader::refreshConfigurationLocked(uint32_t changes) {
michael@0 494 mPolicy->getReaderConfiguration(&mConfig);
michael@0 495 mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
michael@0 496
michael@0 497 if (changes) {
michael@0 498 ALOGI("Reconfiguring input devices. changes=0x%08x", changes);
michael@0 499 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
michael@0 500
michael@0 501 if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
michael@0 502 mEventHub->requestReopenDevices();
michael@0 503 } else {
michael@0 504 for (size_t i = 0; i < mDevices.size(); i++) {
michael@0 505 InputDevice* device = mDevices.valueAt(i);
michael@0 506 device->configure(now, &mConfig, changes);
michael@0 507 }
michael@0 508 }
michael@0 509 }
michael@0 510 }
michael@0 511
michael@0 512 void InputReader::updateGlobalMetaStateLocked() {
michael@0 513 mGlobalMetaState = 0;
michael@0 514
michael@0 515 for (size_t i = 0; i < mDevices.size(); i++) {
michael@0 516 InputDevice* device = mDevices.valueAt(i);
michael@0 517 mGlobalMetaState |= device->getMetaState();
michael@0 518 }
michael@0 519 }
michael@0 520
michael@0 521 int32_t InputReader::getGlobalMetaStateLocked() {
michael@0 522 return mGlobalMetaState;
michael@0 523 }
michael@0 524
michael@0 525 void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) {
michael@0 526 mDisableVirtualKeysTimeout = time;
michael@0 527 }
michael@0 528
michael@0 529 bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now,
michael@0 530 InputDevice* device, int32_t keyCode, int32_t scanCode) {
michael@0 531 if (now < mDisableVirtualKeysTimeout) {
michael@0 532 ALOGI("Dropping virtual key from device %s because virtual keys are "
michael@0 533 "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d",
michael@0 534 device->getName().string(),
michael@0 535 (mDisableVirtualKeysTimeout - now) * 0.000001,
michael@0 536 keyCode, scanCode);
michael@0 537 return true;
michael@0 538 } else {
michael@0 539 return false;
michael@0 540 }
michael@0 541 }
michael@0 542
michael@0 543 void InputReader::fadePointerLocked() {
michael@0 544 for (size_t i = 0; i < mDevices.size(); i++) {
michael@0 545 InputDevice* device = mDevices.valueAt(i);
michael@0 546 device->fadePointer();
michael@0 547 }
michael@0 548 }
michael@0 549
michael@0 550 void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) {
michael@0 551 if (when < mNextTimeout) {
michael@0 552 mNextTimeout = when;
michael@0 553 mEventHub->wake();
michael@0 554 }
michael@0 555 }
michael@0 556
michael@0 557 int32_t InputReader::bumpGenerationLocked() {
michael@0 558 return ++mGeneration;
michael@0 559 }
michael@0 560
michael@0 561 void InputReader::getInputDevices(Vector<InputDeviceInfo>& outInputDevices) {
michael@0 562 AutoMutex _l(mLock);
michael@0 563 getInputDevicesLocked(outInputDevices);
michael@0 564 }
michael@0 565
michael@0 566 void InputReader::getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices) {
michael@0 567 outInputDevices.clear();
michael@0 568
michael@0 569 size_t numDevices = mDevices.size();
michael@0 570 for (size_t i = 0; i < numDevices; i++) {
michael@0 571 InputDevice* device = mDevices.valueAt(i);
michael@0 572 if (!device->isIgnored()) {
michael@0 573 outInputDevices.push();
michael@0 574 device->getDeviceInfo(&outInputDevices.editTop());
michael@0 575 }
michael@0 576 }
michael@0 577 }
michael@0 578
michael@0 579 int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
michael@0 580 int32_t keyCode) {
michael@0 581 AutoMutex _l(mLock);
michael@0 582
michael@0 583 return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState);
michael@0 584 }
michael@0 585
michael@0 586 int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask,
michael@0 587 int32_t scanCode) {
michael@0 588 AutoMutex _l(mLock);
michael@0 589
michael@0 590 return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState);
michael@0 591 }
michael@0 592
michael@0 593 int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) {
michael@0 594 AutoMutex _l(mLock);
michael@0 595
michael@0 596 return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState);
michael@0 597 }
michael@0 598
michael@0 599 int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code,
michael@0 600 GetStateFunc getStateFunc) {
michael@0 601 int32_t result = AKEY_STATE_UNKNOWN;
michael@0 602 if (deviceId >= 0) {
michael@0 603 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
michael@0 604 if (deviceIndex >= 0) {
michael@0 605 InputDevice* device = mDevices.valueAt(deviceIndex);
michael@0 606 if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
michael@0 607 result = (device->*getStateFunc)(sourceMask, code);
michael@0 608 }
michael@0 609 }
michael@0 610 } else {
michael@0 611 size_t numDevices = mDevices.size();
michael@0 612 for (size_t i = 0; i < numDevices; i++) {
michael@0 613 InputDevice* device = mDevices.valueAt(i);
michael@0 614 if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
michael@0 615 // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
michael@0 616 // value. Otherwise, return AKEY_STATE_UP as long as one device reports it.
michael@0 617 int32_t currentResult = (device->*getStateFunc)(sourceMask, code);
michael@0 618 if (currentResult >= AKEY_STATE_DOWN) {
michael@0 619 return currentResult;
michael@0 620 } else if (currentResult == AKEY_STATE_UP) {
michael@0 621 result = currentResult;
michael@0 622 }
michael@0 623 }
michael@0 624 }
michael@0 625 }
michael@0 626 return result;
michael@0 627 }
michael@0 628
michael@0 629 bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask,
michael@0 630 size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
michael@0 631 AutoMutex _l(mLock);
michael@0 632
michael@0 633 memset(outFlags, 0, numCodes);
michael@0 634 return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags);
michael@0 635 }
michael@0 636
michael@0 637 bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask,
michael@0 638 size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
michael@0 639 bool result = false;
michael@0 640 if (deviceId >= 0) {
michael@0 641 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
michael@0 642 if (deviceIndex >= 0) {
michael@0 643 InputDevice* device = mDevices.valueAt(deviceIndex);
michael@0 644 if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
michael@0 645 result = device->markSupportedKeyCodes(sourceMask,
michael@0 646 numCodes, keyCodes, outFlags);
michael@0 647 }
michael@0 648 }
michael@0 649 } else {
michael@0 650 size_t numDevices = mDevices.size();
michael@0 651 for (size_t i = 0; i < numDevices; i++) {
michael@0 652 InputDevice* device = mDevices.valueAt(i);
michael@0 653 if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
michael@0 654 result |= device->markSupportedKeyCodes(sourceMask,
michael@0 655 numCodes, keyCodes, outFlags);
michael@0 656 }
michael@0 657 }
michael@0 658 }
michael@0 659 return result;
michael@0 660 }
michael@0 661
michael@0 662 void InputReader::requestRefreshConfiguration(uint32_t changes) {
michael@0 663 AutoMutex _l(mLock);
michael@0 664
michael@0 665 if (changes) {
michael@0 666 bool needWake = !mConfigurationChangesToRefresh;
michael@0 667 mConfigurationChangesToRefresh |= changes;
michael@0 668
michael@0 669 if (needWake) {
michael@0 670 mEventHub->wake();
michael@0 671 }
michael@0 672 }
michael@0 673 }
michael@0 674
michael@0 675 void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
michael@0 676 ssize_t repeat, int32_t token) {
michael@0 677 AutoMutex _l(mLock);
michael@0 678
michael@0 679 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
michael@0 680 if (deviceIndex >= 0) {
michael@0 681 InputDevice* device = mDevices.valueAt(deviceIndex);
michael@0 682 device->vibrate(pattern, patternSize, repeat, token);
michael@0 683 }
michael@0 684 }
michael@0 685
michael@0 686 void InputReader::cancelVibrate(int32_t deviceId, int32_t token) {
michael@0 687 AutoMutex _l(mLock);
michael@0 688
michael@0 689 ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
michael@0 690 if (deviceIndex >= 0) {
michael@0 691 InputDevice* device = mDevices.valueAt(deviceIndex);
michael@0 692 device->cancelVibrate(token);
michael@0 693 }
michael@0 694 }
michael@0 695
michael@0 696 void InputReader::dump(String8& dump) {
michael@0 697 AutoMutex _l(mLock);
michael@0 698
michael@0 699 mEventHub->dump(dump);
michael@0 700 dump.append("\n");
michael@0 701
michael@0 702 dump.append("Input Reader State:\n");
michael@0 703
michael@0 704 for (size_t i = 0; i < mDevices.size(); i++) {
michael@0 705 mDevices.valueAt(i)->dump(dump);
michael@0 706 }
michael@0 707
michael@0 708 dump.append(INDENT "Configuration:\n");
michael@0 709 dump.append(INDENT2 "ExcludedDeviceNames: [");
michael@0 710 for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) {
michael@0 711 if (i != 0) {
michael@0 712 dump.append(", ");
michael@0 713 }
michael@0 714 dump.append(mConfig.excludedDeviceNames.itemAt(i).string());
michael@0 715 }
michael@0 716 dump.append("]\n");
michael@0 717 dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
michael@0 718 mConfig.virtualKeyQuietTime * 0.000001f);
michael@0 719
michael@0 720 dump.appendFormat(INDENT2 "PointerVelocityControlParameters: "
michael@0 721 "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
michael@0 722 mConfig.pointerVelocityControlParameters.scale,
michael@0 723 mConfig.pointerVelocityControlParameters.lowThreshold,
michael@0 724 mConfig.pointerVelocityControlParameters.highThreshold,
michael@0 725 mConfig.pointerVelocityControlParameters.acceleration);
michael@0 726
michael@0 727 dump.appendFormat(INDENT2 "WheelVelocityControlParameters: "
michael@0 728 "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
michael@0 729 mConfig.wheelVelocityControlParameters.scale,
michael@0 730 mConfig.wheelVelocityControlParameters.lowThreshold,
michael@0 731 mConfig.wheelVelocityControlParameters.highThreshold,
michael@0 732 mConfig.wheelVelocityControlParameters.acceleration);
michael@0 733
michael@0 734 dump.appendFormat(INDENT2 "PointerGesture:\n");
michael@0 735 dump.appendFormat(INDENT3 "Enabled: %s\n",
michael@0 736 toString(mConfig.pointerGesturesEnabled));
michael@0 737 dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n",
michael@0 738 mConfig.pointerGestureQuietInterval * 0.000001f);
michael@0 739 dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n",
michael@0 740 mConfig.pointerGestureDragMinSwitchSpeed);
michael@0 741 dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n",
michael@0 742 mConfig.pointerGestureTapInterval * 0.000001f);
michael@0 743 dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n",
michael@0 744 mConfig.pointerGestureTapDragInterval * 0.000001f);
michael@0 745 dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n",
michael@0 746 mConfig.pointerGestureTapSlop);
michael@0 747 dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
michael@0 748 mConfig.pointerGestureMultitouchSettleInterval * 0.000001f);
michael@0 749 dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n",
michael@0 750 mConfig.pointerGestureMultitouchMinDistance);
michael@0 751 dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
michael@0 752 mConfig.pointerGestureSwipeTransitionAngleCosine);
michael@0 753 dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
michael@0 754 mConfig.pointerGestureSwipeMaxWidthRatio);
michael@0 755 dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n",
michael@0 756 mConfig.pointerGestureMovementSpeedRatio);
michael@0 757 dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n",
michael@0 758 mConfig.pointerGestureZoomSpeedRatio);
michael@0 759 }
michael@0 760
michael@0 761 void InputReader::monitor() {
michael@0 762 // Acquire and release the lock to ensure that the reader has not deadlocked.
michael@0 763 mLock.lock();
michael@0 764 mEventHub->wake();
michael@0 765 mReaderIsAliveCondition.wait(mLock);
michael@0 766 mLock.unlock();
michael@0 767
michael@0 768 // Check the EventHub
michael@0 769 mEventHub->monitor();
michael@0 770 }
michael@0 771
michael@0 772
michael@0 773 // --- InputReader::ContextImpl ---
michael@0 774
michael@0 775 InputReader::ContextImpl::ContextImpl(InputReader* reader) :
michael@0 776 mReader(reader) {
michael@0 777 }
michael@0 778
michael@0 779 void InputReader::ContextImpl::updateGlobalMetaState() {
michael@0 780 // lock is already held by the input loop
michael@0 781 mReader->updateGlobalMetaStateLocked();
michael@0 782 }
michael@0 783
michael@0 784 int32_t InputReader::ContextImpl::getGlobalMetaState() {
michael@0 785 // lock is already held by the input loop
michael@0 786 return mReader->getGlobalMetaStateLocked();
michael@0 787 }
michael@0 788
michael@0 789 void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) {
michael@0 790 // lock is already held by the input loop
michael@0 791 mReader->disableVirtualKeysUntilLocked(time);
michael@0 792 }
michael@0 793
michael@0 794 bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now,
michael@0 795 InputDevice* device, int32_t keyCode, int32_t scanCode) {
michael@0 796 // lock is already held by the input loop
michael@0 797 return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode);
michael@0 798 }
michael@0 799
michael@0 800 void InputReader::ContextImpl::fadePointer() {
michael@0 801 // lock is already held by the input loop
michael@0 802 mReader->fadePointerLocked();
michael@0 803 }
michael@0 804
michael@0 805 void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) {
michael@0 806 // lock is already held by the input loop
michael@0 807 mReader->requestTimeoutAtTimeLocked(when);
michael@0 808 }
michael@0 809
michael@0 810 int32_t InputReader::ContextImpl::bumpGeneration() {
michael@0 811 // lock is already held by the input loop
michael@0 812 return mReader->bumpGenerationLocked();
michael@0 813 }
michael@0 814
michael@0 815 InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() {
michael@0 816 return mReader->mPolicy.get();
michael@0 817 }
michael@0 818
michael@0 819 InputListenerInterface* InputReader::ContextImpl::getListener() {
michael@0 820 return mReader->mQueuedListener.get();
michael@0 821 }
michael@0 822
michael@0 823 EventHubInterface* InputReader::ContextImpl::getEventHub() {
michael@0 824 return mReader->mEventHub.get();
michael@0 825 }
michael@0 826
michael@0 827
michael@0 828 // --- InputReaderThread ---
michael@0 829
michael@0 830 InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
michael@0 831 Thread(/*canCallJava*/ true), mReader(reader) {
michael@0 832 }
michael@0 833
michael@0 834 InputReaderThread::~InputReaderThread() {
michael@0 835 }
michael@0 836
michael@0 837 bool InputReaderThread::threadLoop() {
michael@0 838 mReader->loopOnce();
michael@0 839 return true;
michael@0 840 }
michael@0 841
michael@0 842
michael@0 843 // --- InputDevice ---
michael@0 844
michael@0 845 InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
michael@0 846 const InputDeviceIdentifier& identifier, uint32_t classes) :
michael@0 847 mContext(context), mId(id), mGeneration(generation),
michael@0 848 mIdentifier(identifier), mClasses(classes),
michael@0 849 mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
michael@0 850 }
michael@0 851
michael@0 852 InputDevice::~InputDevice() {
michael@0 853 size_t numMappers = mMappers.size();
michael@0 854 for (size_t i = 0; i < numMappers; i++) {
michael@0 855 delete mMappers[i];
michael@0 856 }
michael@0 857 mMappers.clear();
michael@0 858 }
michael@0 859
michael@0 860 void InputDevice::dump(String8& dump) {
michael@0 861 InputDeviceInfo deviceInfo;
michael@0 862 getDeviceInfo(& deviceInfo);
michael@0 863
michael@0 864 dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(),
michael@0 865 deviceInfo.getDisplayName().string());
michael@0 866 dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration);
michael@0 867 dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
michael@0 868 dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
michael@0 869 dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
michael@0 870
michael@0 871 const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
michael@0 872 if (!ranges.isEmpty()) {
michael@0 873 dump.append(INDENT2 "Motion Ranges:\n");
michael@0 874 for (size_t i = 0; i < ranges.size(); i++) {
michael@0 875 const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
michael@0 876 const char* label = getAxisLabel(range.axis);
michael@0 877 char name[32];
michael@0 878 if (label) {
michael@0 879 strncpy(name, label, sizeof(name));
michael@0 880 name[sizeof(name) - 1] = '\0';
michael@0 881 } else {
michael@0 882 snprintf(name, sizeof(name), "%d", range.axis);
michael@0 883 }
michael@0 884 dump.appendFormat(INDENT3 "%s: source=0x%08x, "
michael@0 885 "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
michael@0 886 name, range.source, range.min, range.max, range.flat, range.fuzz,
michael@0 887 range.resolution);
michael@0 888 }
michael@0 889 }
michael@0 890
michael@0 891 size_t numMappers = mMappers.size();
michael@0 892 for (size_t i = 0; i < numMappers; i++) {
michael@0 893 InputMapper* mapper = mMappers[i];
michael@0 894 mapper->dump(dump);
michael@0 895 }
michael@0 896 }
michael@0 897
michael@0 898 void InputDevice::addMapper(InputMapper* mapper) {
michael@0 899 mMappers.add(mapper);
michael@0 900 }
michael@0 901
michael@0 902 void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) {
michael@0 903 mSources = 0;
michael@0 904
michael@0 905 if (!isIgnored()) {
michael@0 906 if (!changes) { // first time only
michael@0 907 mContext->getEventHub()->getConfiguration(mId, &mConfiguration);
michael@0 908 }
michael@0 909
michael@0 910 if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
michael@0 911 if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
michael@0 912 sp<KeyCharacterMap> keyboardLayout =
michael@0 913 mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor);
michael@0 914 if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) {
michael@0 915 bumpGeneration();
michael@0 916 }
michael@0 917 }
michael@0 918 }
michael@0 919
michael@0 920 if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) {
michael@0 921 if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
michael@0 922 String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
michael@0 923 if (mAlias != alias) {
michael@0 924 mAlias = alias;
michael@0 925 bumpGeneration();
michael@0 926 }
michael@0 927 }
michael@0 928 }
michael@0 929
michael@0 930 size_t numMappers = mMappers.size();
michael@0 931 for (size_t i = 0; i < numMappers; i++) {
michael@0 932 InputMapper* mapper = mMappers[i];
michael@0 933 mapper->configure(when, config, changes);
michael@0 934 mSources |= mapper->getSources();
michael@0 935 }
michael@0 936 }
michael@0 937 }
michael@0 938
michael@0 939 void InputDevice::reset(nsecs_t when) {
michael@0 940 size_t numMappers = mMappers.size();
michael@0 941 for (size_t i = 0; i < numMappers; i++) {
michael@0 942 InputMapper* mapper = mMappers[i];
michael@0 943 mapper->reset(when);
michael@0 944 }
michael@0 945
michael@0 946 mContext->updateGlobalMetaState();
michael@0 947
michael@0 948 notifyReset(when);
michael@0 949 }
michael@0 950
michael@0 951 void InputDevice::process(const RawEvent* rawEvents, size_t count) {
michael@0 952 // Process all of the events in order for each mapper.
michael@0 953 // We cannot simply ask each mapper to process them in bulk because mappers may
michael@0 954 // have side-effects that must be interleaved. For example, joystick movement events and
michael@0 955 // gamepad button presses are handled by different mappers but they should be dispatched
michael@0 956 // in the order received.
michael@0 957 size_t numMappers = mMappers.size();
michael@0 958 for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
michael@0 959 #if DEBUG_RAW_EVENTS
michael@0 960 ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
michael@0 961 rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
michael@0 962 rawEvent->when);
michael@0 963 #endif
michael@0 964
michael@0 965 if (mDropUntilNextSync) {
michael@0 966 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
michael@0 967 mDropUntilNextSync = false;
michael@0 968 #if DEBUG_RAW_EVENTS
michael@0 969 ALOGD("Recovered from input event buffer overrun.");
michael@0 970 #endif
michael@0 971 } else {
michael@0 972 #if DEBUG_RAW_EVENTS
michael@0 973 ALOGD("Dropped input event while waiting for next input sync.");
michael@0 974 #endif
michael@0 975 }
michael@0 976 } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
michael@0 977 ALOGI("Detected input event buffer overrun for device %s.", getName().string());
michael@0 978 mDropUntilNextSync = true;
michael@0 979 reset(rawEvent->when);
michael@0 980 } else {
michael@0 981 for (size_t i = 0; i < numMappers; i++) {
michael@0 982 InputMapper* mapper = mMappers[i];
michael@0 983 mapper->process(rawEvent);
michael@0 984 }
michael@0 985 }
michael@0 986 }
michael@0 987 }
michael@0 988
michael@0 989 void InputDevice::timeoutExpired(nsecs_t when) {
michael@0 990 size_t numMappers = mMappers.size();
michael@0 991 for (size_t i = 0; i < numMappers; i++) {
michael@0 992 InputMapper* mapper = mMappers[i];
michael@0 993 mapper->timeoutExpired(when);
michael@0 994 }
michael@0 995 }
michael@0 996
michael@0 997 void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
michael@0 998 outDeviceInfo->initialize(mId, mGeneration, mIdentifier, mAlias, mIsExternal);
michael@0 999
michael@0 1000 size_t numMappers = mMappers.size();
michael@0 1001 for (size_t i = 0; i < numMappers; i++) {
michael@0 1002 InputMapper* mapper = mMappers[i];
michael@0 1003 mapper->populateDeviceInfo(outDeviceInfo);
michael@0 1004 }
michael@0 1005 }
michael@0 1006
michael@0 1007 int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
michael@0 1008 return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState);
michael@0 1009 }
michael@0 1010
michael@0 1011 int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
michael@0 1012 return getState(sourceMask, scanCode, & InputMapper::getScanCodeState);
michael@0 1013 }
michael@0 1014
michael@0 1015 int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
michael@0 1016 return getState(sourceMask, switchCode, & InputMapper::getSwitchState);
michael@0 1017 }
michael@0 1018
michael@0 1019 int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
michael@0 1020 int32_t result = AKEY_STATE_UNKNOWN;
michael@0 1021 size_t numMappers = mMappers.size();
michael@0 1022 for (size_t i = 0; i < numMappers; i++) {
michael@0 1023 InputMapper* mapper = mMappers[i];
michael@0 1024 if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
michael@0 1025 // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
michael@0 1026 // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
michael@0 1027 int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code);
michael@0 1028 if (currentResult >= AKEY_STATE_DOWN) {
michael@0 1029 return currentResult;
michael@0 1030 } else if (currentResult == AKEY_STATE_UP) {
michael@0 1031 result = currentResult;
michael@0 1032 }
michael@0 1033 }
michael@0 1034 }
michael@0 1035 return result;
michael@0 1036 }
michael@0 1037
michael@0 1038 bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
michael@0 1039 const int32_t* keyCodes, uint8_t* outFlags) {
michael@0 1040 bool result = false;
michael@0 1041 size_t numMappers = mMappers.size();
michael@0 1042 for (size_t i = 0; i < numMappers; i++) {
michael@0 1043 InputMapper* mapper = mMappers[i];
michael@0 1044 if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
michael@0 1045 result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
michael@0 1046 }
michael@0 1047 }
michael@0 1048 return result;
michael@0 1049 }
michael@0 1050
michael@0 1051 void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
michael@0 1052 int32_t token) {
michael@0 1053 size_t numMappers = mMappers.size();
michael@0 1054 for (size_t i = 0; i < numMappers; i++) {
michael@0 1055 InputMapper* mapper = mMappers[i];
michael@0 1056 mapper->vibrate(pattern, patternSize, repeat, token);
michael@0 1057 }
michael@0 1058 }
michael@0 1059
michael@0 1060 void InputDevice::cancelVibrate(int32_t token) {
michael@0 1061 size_t numMappers = mMappers.size();
michael@0 1062 for (size_t i = 0; i < numMappers; i++) {
michael@0 1063 InputMapper* mapper = mMappers[i];
michael@0 1064 mapper->cancelVibrate(token);
michael@0 1065 }
michael@0 1066 }
michael@0 1067
michael@0 1068 int32_t InputDevice::getMetaState() {
michael@0 1069 int32_t result = 0;
michael@0 1070 size_t numMappers = mMappers.size();
michael@0 1071 for (size_t i = 0; i < numMappers; i++) {
michael@0 1072 InputMapper* mapper = mMappers[i];
michael@0 1073 result |= mapper->getMetaState();
michael@0 1074 }
michael@0 1075 return result;
michael@0 1076 }
michael@0 1077
michael@0 1078 void InputDevice::fadePointer() {
michael@0 1079 size_t numMappers = mMappers.size();
michael@0 1080 for (size_t i = 0; i < numMappers; i++) {
michael@0 1081 InputMapper* mapper = mMappers[i];
michael@0 1082 mapper->fadePointer();
michael@0 1083 }
michael@0 1084 }
michael@0 1085
michael@0 1086 void InputDevice::bumpGeneration() {
michael@0 1087 mGeneration = mContext->bumpGeneration();
michael@0 1088 }
michael@0 1089
michael@0 1090 void InputDevice::notifyReset(nsecs_t when) {
michael@0 1091 NotifyDeviceResetArgs args(when, mId);
michael@0 1092 mContext->getListener()->notifyDeviceReset(&args);
michael@0 1093 }
michael@0 1094
michael@0 1095
michael@0 1096 // --- CursorButtonAccumulator ---
michael@0 1097
michael@0 1098 CursorButtonAccumulator::CursorButtonAccumulator() {
michael@0 1099 clearButtons();
michael@0 1100 }
michael@0 1101
michael@0 1102 void CursorButtonAccumulator::reset(InputDevice* device) {
michael@0 1103 mBtnLeft = device->isKeyPressed(BTN_LEFT);
michael@0 1104 mBtnRight = device->isKeyPressed(BTN_RIGHT);
michael@0 1105 mBtnMiddle = device->isKeyPressed(BTN_MIDDLE);
michael@0 1106 mBtnBack = device->isKeyPressed(BTN_BACK);
michael@0 1107 mBtnSide = device->isKeyPressed(BTN_SIDE);
michael@0 1108 mBtnForward = device->isKeyPressed(BTN_FORWARD);
michael@0 1109 mBtnExtra = device->isKeyPressed(BTN_EXTRA);
michael@0 1110 mBtnTask = device->isKeyPressed(BTN_TASK);
michael@0 1111 }
michael@0 1112
michael@0 1113 void CursorButtonAccumulator::clearButtons() {
michael@0 1114 mBtnLeft = 0;
michael@0 1115 mBtnRight = 0;
michael@0 1116 mBtnMiddle = 0;
michael@0 1117 mBtnBack = 0;
michael@0 1118 mBtnSide = 0;
michael@0 1119 mBtnForward = 0;
michael@0 1120 mBtnExtra = 0;
michael@0 1121 mBtnTask = 0;
michael@0 1122 }
michael@0 1123
michael@0 1124 void CursorButtonAccumulator::process(const RawEvent* rawEvent) {
michael@0 1125 if (rawEvent->type == EV_KEY) {
michael@0 1126 switch (rawEvent->code) {
michael@0 1127 case BTN_LEFT:
michael@0 1128 mBtnLeft = rawEvent->value;
michael@0 1129 break;
michael@0 1130 case BTN_RIGHT:
michael@0 1131 mBtnRight = rawEvent->value;
michael@0 1132 break;
michael@0 1133 case BTN_MIDDLE:
michael@0 1134 mBtnMiddle = rawEvent->value;
michael@0 1135 break;
michael@0 1136 case BTN_BACK:
michael@0 1137 mBtnBack = rawEvent->value;
michael@0 1138 break;
michael@0 1139 case BTN_SIDE:
michael@0 1140 mBtnSide = rawEvent->value;
michael@0 1141 break;
michael@0 1142 case BTN_FORWARD:
michael@0 1143 mBtnForward = rawEvent->value;
michael@0 1144 break;
michael@0 1145 case BTN_EXTRA:
michael@0 1146 mBtnExtra = rawEvent->value;
michael@0 1147 break;
michael@0 1148 case BTN_TASK:
michael@0 1149 mBtnTask = rawEvent->value;
michael@0 1150 break;
michael@0 1151 }
michael@0 1152 }
michael@0 1153 }
michael@0 1154
michael@0 1155 uint32_t CursorButtonAccumulator::getButtonState() const {
michael@0 1156 uint32_t result = 0;
michael@0 1157 if (mBtnLeft) {
michael@0 1158 result |= AMOTION_EVENT_BUTTON_PRIMARY;
michael@0 1159 }
michael@0 1160 if (mBtnRight) {
michael@0 1161 result |= AMOTION_EVENT_BUTTON_SECONDARY;
michael@0 1162 }
michael@0 1163 if (mBtnMiddle) {
michael@0 1164 result |= AMOTION_EVENT_BUTTON_TERTIARY;
michael@0 1165 }
michael@0 1166 if (mBtnBack || mBtnSide) {
michael@0 1167 result |= AMOTION_EVENT_BUTTON_BACK;
michael@0 1168 }
michael@0 1169 if (mBtnForward || mBtnExtra) {
michael@0 1170 result |= AMOTION_EVENT_BUTTON_FORWARD;
michael@0 1171 }
michael@0 1172 return result;
michael@0 1173 }
michael@0 1174
michael@0 1175
michael@0 1176 // --- CursorMotionAccumulator ---
michael@0 1177
michael@0 1178 CursorMotionAccumulator::CursorMotionAccumulator() {
michael@0 1179 clearRelativeAxes();
michael@0 1180 }
michael@0 1181
michael@0 1182 void CursorMotionAccumulator::reset(InputDevice* device) {
michael@0 1183 clearRelativeAxes();
michael@0 1184 }
michael@0 1185
michael@0 1186 void CursorMotionAccumulator::clearRelativeAxes() {
michael@0 1187 mRelX = 0;
michael@0 1188 mRelY = 0;
michael@0 1189 }
michael@0 1190
michael@0 1191 void CursorMotionAccumulator::process(const RawEvent* rawEvent) {
michael@0 1192 if (rawEvent->type == EV_REL) {
michael@0 1193 switch (rawEvent->code) {
michael@0 1194 case REL_X:
michael@0 1195 mRelX = rawEvent->value;
michael@0 1196 break;
michael@0 1197 case REL_Y:
michael@0 1198 mRelY = rawEvent->value;
michael@0 1199 break;
michael@0 1200 }
michael@0 1201 }
michael@0 1202 }
michael@0 1203
michael@0 1204 void CursorMotionAccumulator::finishSync() {
michael@0 1205 clearRelativeAxes();
michael@0 1206 }
michael@0 1207
michael@0 1208
michael@0 1209 // --- CursorScrollAccumulator ---
michael@0 1210
michael@0 1211 CursorScrollAccumulator::CursorScrollAccumulator() :
michael@0 1212 mHaveRelWheel(false), mHaveRelHWheel(false) {
michael@0 1213 clearRelativeAxes();
michael@0 1214 }
michael@0 1215
michael@0 1216 void CursorScrollAccumulator::configure(InputDevice* device) {
michael@0 1217 mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL);
michael@0 1218 mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL);
michael@0 1219 }
michael@0 1220
michael@0 1221 void CursorScrollAccumulator::reset(InputDevice* device) {
michael@0 1222 clearRelativeAxes();
michael@0 1223 }
michael@0 1224
michael@0 1225 void CursorScrollAccumulator::clearRelativeAxes() {
michael@0 1226 mRelWheel = 0;
michael@0 1227 mRelHWheel = 0;
michael@0 1228 }
michael@0 1229
michael@0 1230 void CursorScrollAccumulator::process(const RawEvent* rawEvent) {
michael@0 1231 if (rawEvent->type == EV_REL) {
michael@0 1232 switch (rawEvent->code) {
michael@0 1233 case REL_WHEEL:
michael@0 1234 mRelWheel = rawEvent->value;
michael@0 1235 break;
michael@0 1236 case REL_HWHEEL:
michael@0 1237 mRelHWheel = rawEvent->value;
michael@0 1238 break;
michael@0 1239 }
michael@0 1240 }
michael@0 1241 }
michael@0 1242
michael@0 1243 void CursorScrollAccumulator::finishSync() {
michael@0 1244 clearRelativeAxes();
michael@0 1245 }
michael@0 1246
michael@0 1247
michael@0 1248 // --- TouchButtonAccumulator ---
michael@0 1249
michael@0 1250 TouchButtonAccumulator::TouchButtonAccumulator() :
michael@0 1251 mHaveBtnTouch(false), mHaveStylus(false) {
michael@0 1252 clearButtons();
michael@0 1253 }
michael@0 1254
michael@0 1255 void TouchButtonAccumulator::configure(InputDevice* device) {
michael@0 1256 mHaveBtnTouch = device->hasKey(BTN_TOUCH);
michael@0 1257 mHaveStylus = device->hasKey(BTN_TOOL_PEN)
michael@0 1258 || device->hasKey(BTN_TOOL_RUBBER)
michael@0 1259 || device->hasKey(BTN_TOOL_BRUSH)
michael@0 1260 || device->hasKey(BTN_TOOL_PENCIL)
michael@0 1261 || device->hasKey(BTN_TOOL_AIRBRUSH);
michael@0 1262 }
michael@0 1263
michael@0 1264 void TouchButtonAccumulator::reset(InputDevice* device) {
michael@0 1265 mBtnTouch = device->isKeyPressed(BTN_TOUCH);
michael@0 1266 mBtnStylus = device->isKeyPressed(BTN_STYLUS);
michael@0 1267 mBtnStylus2 = device->isKeyPressed(BTN_STYLUS);
michael@0 1268 mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER);
michael@0 1269 mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN);
michael@0 1270 mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER);
michael@0 1271 mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH);
michael@0 1272 mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL);
michael@0 1273 mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH);
michael@0 1274 mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE);
michael@0 1275 mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS);
michael@0 1276 mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP);
michael@0 1277 mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP);
michael@0 1278 mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP);
michael@0 1279 }
michael@0 1280
michael@0 1281 void TouchButtonAccumulator::clearButtons() {
michael@0 1282 mBtnTouch = 0;
michael@0 1283 mBtnStylus = 0;
michael@0 1284 mBtnStylus2 = 0;
michael@0 1285 mBtnToolFinger = 0;
michael@0 1286 mBtnToolPen = 0;
michael@0 1287 mBtnToolRubber = 0;
michael@0 1288 mBtnToolBrush = 0;
michael@0 1289 mBtnToolPencil = 0;
michael@0 1290 mBtnToolAirbrush = 0;
michael@0 1291 mBtnToolMouse = 0;
michael@0 1292 mBtnToolLens = 0;
michael@0 1293 mBtnToolDoubleTap = 0;
michael@0 1294 mBtnToolTripleTap = 0;
michael@0 1295 mBtnToolQuadTap = 0;
michael@0 1296 }
michael@0 1297
michael@0 1298 void TouchButtonAccumulator::process(const RawEvent* rawEvent) {
michael@0 1299 if (rawEvent->type == EV_KEY) {
michael@0 1300 switch (rawEvent->code) {
michael@0 1301 case BTN_TOUCH:
michael@0 1302 mBtnTouch = rawEvent->value;
michael@0 1303 break;
michael@0 1304 case BTN_STYLUS:
michael@0 1305 mBtnStylus = rawEvent->value;
michael@0 1306 break;
michael@0 1307 case BTN_STYLUS2:
michael@0 1308 mBtnStylus2 = rawEvent->value;
michael@0 1309 break;
michael@0 1310 case BTN_TOOL_FINGER:
michael@0 1311 mBtnToolFinger = rawEvent->value;
michael@0 1312 break;
michael@0 1313 case BTN_TOOL_PEN:
michael@0 1314 mBtnToolPen = rawEvent->value;
michael@0 1315 break;
michael@0 1316 case BTN_TOOL_RUBBER:
michael@0 1317 mBtnToolRubber = rawEvent->value;
michael@0 1318 break;
michael@0 1319 case BTN_TOOL_BRUSH:
michael@0 1320 mBtnToolBrush = rawEvent->value;
michael@0 1321 break;
michael@0 1322 case BTN_TOOL_PENCIL:
michael@0 1323 mBtnToolPencil = rawEvent->value;
michael@0 1324 break;
michael@0 1325 case BTN_TOOL_AIRBRUSH:
michael@0 1326 mBtnToolAirbrush = rawEvent->value;
michael@0 1327 break;
michael@0 1328 case BTN_TOOL_MOUSE:
michael@0 1329 mBtnToolMouse = rawEvent->value;
michael@0 1330 break;
michael@0 1331 case BTN_TOOL_LENS:
michael@0 1332 mBtnToolLens = rawEvent->value;
michael@0 1333 break;
michael@0 1334 case BTN_TOOL_DOUBLETAP:
michael@0 1335 mBtnToolDoubleTap = rawEvent->value;
michael@0 1336 break;
michael@0 1337 case BTN_TOOL_TRIPLETAP:
michael@0 1338 mBtnToolTripleTap = rawEvent->value;
michael@0 1339 break;
michael@0 1340 case BTN_TOOL_QUADTAP:
michael@0 1341 mBtnToolQuadTap = rawEvent->value;
michael@0 1342 break;
michael@0 1343 }
michael@0 1344 }
michael@0 1345 }
michael@0 1346
michael@0 1347 uint32_t TouchButtonAccumulator::getButtonState() const {
michael@0 1348 uint32_t result = 0;
michael@0 1349 if (mBtnStylus) {
michael@0 1350 result |= AMOTION_EVENT_BUTTON_SECONDARY;
michael@0 1351 }
michael@0 1352 if (mBtnStylus2) {
michael@0 1353 result |= AMOTION_EVENT_BUTTON_TERTIARY;
michael@0 1354 }
michael@0 1355 return result;
michael@0 1356 }
michael@0 1357
michael@0 1358 int32_t TouchButtonAccumulator::getToolType() const {
michael@0 1359 if (mBtnToolMouse || mBtnToolLens) {
michael@0 1360 return AMOTION_EVENT_TOOL_TYPE_MOUSE;
michael@0 1361 }
michael@0 1362 if (mBtnToolRubber) {
michael@0 1363 return AMOTION_EVENT_TOOL_TYPE_ERASER;
michael@0 1364 }
michael@0 1365 if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) {
michael@0 1366 return AMOTION_EVENT_TOOL_TYPE_STYLUS;
michael@0 1367 }
michael@0 1368 if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) {
michael@0 1369 return AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 1370 }
michael@0 1371 return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
michael@0 1372 }
michael@0 1373
michael@0 1374 bool TouchButtonAccumulator::isToolActive() const {
michael@0 1375 return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber
michael@0 1376 || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush
michael@0 1377 || mBtnToolMouse || mBtnToolLens
michael@0 1378 || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap;
michael@0 1379 }
michael@0 1380
michael@0 1381 bool TouchButtonAccumulator::isHovering() const {
michael@0 1382 return mHaveBtnTouch && !mBtnTouch;
michael@0 1383 }
michael@0 1384
michael@0 1385 bool TouchButtonAccumulator::hasStylus() const {
michael@0 1386 return mHaveStylus;
michael@0 1387 }
michael@0 1388
michael@0 1389
michael@0 1390 // --- RawPointerAxes ---
michael@0 1391
michael@0 1392 RawPointerAxes::RawPointerAxes() {
michael@0 1393 clear();
michael@0 1394 }
michael@0 1395
michael@0 1396 void RawPointerAxes::clear() {
michael@0 1397 x.clear();
michael@0 1398 y.clear();
michael@0 1399 pressure.clear();
michael@0 1400 touchMajor.clear();
michael@0 1401 touchMinor.clear();
michael@0 1402 toolMajor.clear();
michael@0 1403 toolMinor.clear();
michael@0 1404 orientation.clear();
michael@0 1405 distance.clear();
michael@0 1406 tiltX.clear();
michael@0 1407 tiltY.clear();
michael@0 1408 trackingId.clear();
michael@0 1409 slot.clear();
michael@0 1410 }
michael@0 1411
michael@0 1412
michael@0 1413 // --- RawPointerData ---
michael@0 1414
michael@0 1415 RawPointerData::RawPointerData() {
michael@0 1416 clear();
michael@0 1417 }
michael@0 1418
michael@0 1419 void RawPointerData::clear() {
michael@0 1420 pointerCount = 0;
michael@0 1421 clearIdBits();
michael@0 1422 }
michael@0 1423
michael@0 1424 void RawPointerData::copyFrom(const RawPointerData& other) {
michael@0 1425 pointerCount = other.pointerCount;
michael@0 1426 hoveringIdBits = other.hoveringIdBits;
michael@0 1427 touchingIdBits = other.touchingIdBits;
michael@0 1428
michael@0 1429 for (uint32_t i = 0; i < pointerCount; i++) {
michael@0 1430 pointers[i] = other.pointers[i];
michael@0 1431
michael@0 1432 int id = pointers[i].id;
michael@0 1433 idToIndex[id] = other.idToIndex[id];
michael@0 1434 }
michael@0 1435 }
michael@0 1436
michael@0 1437 void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const {
michael@0 1438 float x = 0, y = 0;
michael@0 1439 uint32_t count = touchingIdBits.count();
michael@0 1440 if (count) {
michael@0 1441 for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty(); ) {
michael@0 1442 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 1443 const Pointer& pointer = pointerForId(id);
michael@0 1444 x += pointer.x;
michael@0 1445 y += pointer.y;
michael@0 1446 }
michael@0 1447 x /= count;
michael@0 1448 y /= count;
michael@0 1449 }
michael@0 1450 *outX = x;
michael@0 1451 *outY = y;
michael@0 1452 }
michael@0 1453
michael@0 1454
michael@0 1455 // --- CookedPointerData ---
michael@0 1456
michael@0 1457 CookedPointerData::CookedPointerData() {
michael@0 1458 clear();
michael@0 1459 }
michael@0 1460
michael@0 1461 void CookedPointerData::clear() {
michael@0 1462 pointerCount = 0;
michael@0 1463 hoveringIdBits.clear();
michael@0 1464 touchingIdBits.clear();
michael@0 1465 }
michael@0 1466
michael@0 1467 void CookedPointerData::copyFrom(const CookedPointerData& other) {
michael@0 1468 pointerCount = other.pointerCount;
michael@0 1469 hoveringIdBits = other.hoveringIdBits;
michael@0 1470 touchingIdBits = other.touchingIdBits;
michael@0 1471
michael@0 1472 for (uint32_t i = 0; i < pointerCount; i++) {
michael@0 1473 pointerProperties[i].copyFrom(other.pointerProperties[i]);
michael@0 1474 pointerCoords[i].copyFrom(other.pointerCoords[i]);
michael@0 1475
michael@0 1476 int id = pointerProperties[i].id;
michael@0 1477 idToIndex[id] = other.idToIndex[id];
michael@0 1478 }
michael@0 1479 }
michael@0 1480
michael@0 1481
michael@0 1482 // --- SingleTouchMotionAccumulator ---
michael@0 1483
michael@0 1484 SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() {
michael@0 1485 clearAbsoluteAxes();
michael@0 1486 }
michael@0 1487
michael@0 1488 void SingleTouchMotionAccumulator::reset(InputDevice* device) {
michael@0 1489 mAbsX = device->getAbsoluteAxisValue(ABS_X);
michael@0 1490 mAbsY = device->getAbsoluteAxisValue(ABS_Y);
michael@0 1491 mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE);
michael@0 1492 mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH);
michael@0 1493 mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE);
michael@0 1494 mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X);
michael@0 1495 mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y);
michael@0 1496 }
michael@0 1497
michael@0 1498 void SingleTouchMotionAccumulator::clearAbsoluteAxes() {
michael@0 1499 mAbsX = 0;
michael@0 1500 mAbsY = 0;
michael@0 1501 mAbsPressure = 0;
michael@0 1502 mAbsToolWidth = 0;
michael@0 1503 mAbsDistance = 0;
michael@0 1504 mAbsTiltX = 0;
michael@0 1505 mAbsTiltY = 0;
michael@0 1506 }
michael@0 1507
michael@0 1508 void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) {
michael@0 1509 if (rawEvent->type == EV_ABS) {
michael@0 1510 switch (rawEvent->code) {
michael@0 1511 case ABS_X:
michael@0 1512 mAbsX = rawEvent->value;
michael@0 1513 break;
michael@0 1514 case ABS_Y:
michael@0 1515 mAbsY = rawEvent->value;
michael@0 1516 break;
michael@0 1517 case ABS_PRESSURE:
michael@0 1518 mAbsPressure = rawEvent->value;
michael@0 1519 break;
michael@0 1520 case ABS_TOOL_WIDTH:
michael@0 1521 mAbsToolWidth = rawEvent->value;
michael@0 1522 break;
michael@0 1523 case ABS_DISTANCE:
michael@0 1524 mAbsDistance = rawEvent->value;
michael@0 1525 break;
michael@0 1526 case ABS_TILT_X:
michael@0 1527 mAbsTiltX = rawEvent->value;
michael@0 1528 break;
michael@0 1529 case ABS_TILT_Y:
michael@0 1530 mAbsTiltY = rawEvent->value;
michael@0 1531 break;
michael@0 1532 }
michael@0 1533 }
michael@0 1534 }
michael@0 1535
michael@0 1536
michael@0 1537 // --- MultiTouchMotionAccumulator ---
michael@0 1538
michael@0 1539 MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() :
michael@0 1540 mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false),
michael@0 1541 mHaveStylus(false) {
michael@0 1542 }
michael@0 1543
michael@0 1544 MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() {
michael@0 1545 delete[] mSlots;
michael@0 1546 }
michael@0 1547
michael@0 1548 void MultiTouchMotionAccumulator::configure(InputDevice* device,
michael@0 1549 size_t slotCount, bool usingSlotsProtocol) {
michael@0 1550 mSlotCount = slotCount;
michael@0 1551 mUsingSlotsProtocol = usingSlotsProtocol;
michael@0 1552 mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
michael@0 1553
michael@0 1554 delete[] mSlots;
michael@0 1555 mSlots = new Slot[slotCount];
michael@0 1556 }
michael@0 1557
michael@0 1558 void MultiTouchMotionAccumulator::reset(InputDevice* device) {
michael@0 1559 // Unfortunately there is no way to read the initial contents of the slots.
michael@0 1560 // So when we reset the accumulator, we must assume they are all zeroes.
michael@0 1561 if (mUsingSlotsProtocol) {
michael@0 1562 // Query the driver for the current slot index and use it as the initial slot
michael@0 1563 // before we start reading events from the device. It is possible that the
michael@0 1564 // current slot index will not be the same as it was when the first event was
michael@0 1565 // written into the evdev buffer, which means the input mapper could start
michael@0 1566 // out of sync with the initial state of the events in the evdev buffer.
michael@0 1567 // In the extremely unlikely case that this happens, the data from
michael@0 1568 // two slots will be confused until the next ABS_MT_SLOT event is received.
michael@0 1569 // This can cause the touch point to "jump", but at least there will be
michael@0 1570 // no stuck touches.
michael@0 1571 int32_t initialSlot;
michael@0 1572 status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(),
michael@0 1573 ABS_MT_SLOT, &initialSlot);
michael@0 1574 if (status) {
michael@0 1575 ALOGD("Could not retrieve current multitouch slot index. status=%d", status);
michael@0 1576 initialSlot = -1;
michael@0 1577 }
michael@0 1578 clearSlots(initialSlot);
michael@0 1579 } else {
michael@0 1580 clearSlots(-1);
michael@0 1581 }
michael@0 1582 }
michael@0 1583
michael@0 1584 void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
michael@0 1585 if (mSlots) {
michael@0 1586 for (size_t i = 0; i < mSlotCount; i++) {
michael@0 1587 mSlots[i].clear();
michael@0 1588 }
michael@0 1589 }
michael@0 1590 mCurrentSlot = initialSlot;
michael@0 1591 }
michael@0 1592
michael@0 1593 void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
michael@0 1594 if (rawEvent->type == EV_ABS) {
michael@0 1595 bool newSlot = false;
michael@0 1596 if (mUsingSlotsProtocol) {
michael@0 1597 if (rawEvent->code == ABS_MT_SLOT) {
michael@0 1598 mCurrentSlot = rawEvent->value;
michael@0 1599 newSlot = true;
michael@0 1600 }
michael@0 1601 } else if (mCurrentSlot < 0) {
michael@0 1602 mCurrentSlot = 0;
michael@0 1603 }
michael@0 1604
michael@0 1605 if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
michael@0 1606 #if DEBUG_POINTERS
michael@0 1607 if (newSlot) {
michael@0 1608 ALOGW("MultiTouch device emitted invalid slot index %d but it "
michael@0 1609 "should be between 0 and %d; ignoring this slot.",
michael@0 1610 mCurrentSlot, mSlotCount - 1);
michael@0 1611 }
michael@0 1612 #endif
michael@0 1613 } else {
michael@0 1614 Slot* slot = &mSlots[mCurrentSlot];
michael@0 1615
michael@0 1616 switch (rawEvent->code) {
michael@0 1617 case ABS_MT_POSITION_X:
michael@0 1618 slot->mInUse = true;
michael@0 1619 slot->mAbsMTPositionX = rawEvent->value;
michael@0 1620 break;
michael@0 1621 case ABS_MT_POSITION_Y:
michael@0 1622 slot->mInUse = true;
michael@0 1623 slot->mAbsMTPositionY = rawEvent->value;
michael@0 1624 break;
michael@0 1625 case ABS_MT_TOUCH_MAJOR:
michael@0 1626 slot->mInUse = true;
michael@0 1627 slot->mAbsMTTouchMajor = rawEvent->value;
michael@0 1628 break;
michael@0 1629 case ABS_MT_TOUCH_MINOR:
michael@0 1630 slot->mInUse = true;
michael@0 1631 slot->mAbsMTTouchMinor = rawEvent->value;
michael@0 1632 slot->mHaveAbsMTTouchMinor = true;
michael@0 1633 break;
michael@0 1634 case ABS_MT_WIDTH_MAJOR:
michael@0 1635 slot->mInUse = true;
michael@0 1636 slot->mAbsMTWidthMajor = rawEvent->value;
michael@0 1637 break;
michael@0 1638 case ABS_MT_WIDTH_MINOR:
michael@0 1639 slot->mInUse = true;
michael@0 1640 slot->mAbsMTWidthMinor = rawEvent->value;
michael@0 1641 slot->mHaveAbsMTWidthMinor = true;
michael@0 1642 break;
michael@0 1643 case ABS_MT_ORIENTATION:
michael@0 1644 slot->mInUse = true;
michael@0 1645 slot->mAbsMTOrientation = rawEvent->value;
michael@0 1646 break;
michael@0 1647 case ABS_MT_TRACKING_ID:
michael@0 1648 if (mUsingSlotsProtocol && rawEvent->value < 0) {
michael@0 1649 // The slot is no longer in use but it retains its previous contents,
michael@0 1650 // which may be reused for subsequent touches.
michael@0 1651 slot->mInUse = false;
michael@0 1652 } else {
michael@0 1653 slot->mInUse = true;
michael@0 1654 slot->mAbsMTTrackingId = rawEvent->value;
michael@0 1655 }
michael@0 1656 break;
michael@0 1657 case ABS_MT_PRESSURE:
michael@0 1658 slot->mInUse = true;
michael@0 1659 slot->mAbsMTPressure = rawEvent->value;
michael@0 1660 break;
michael@0 1661 case ABS_MT_DISTANCE:
michael@0 1662 slot->mInUse = true;
michael@0 1663 slot->mAbsMTDistance = rawEvent->value;
michael@0 1664 break;
michael@0 1665 case ABS_MT_TOOL_TYPE:
michael@0 1666 slot->mInUse = true;
michael@0 1667 slot->mAbsMTToolType = rawEvent->value;
michael@0 1668 slot->mHaveAbsMTToolType = true;
michael@0 1669 break;
michael@0 1670 }
michael@0 1671 }
michael@0 1672 } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
michael@0 1673 // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
michael@0 1674 mCurrentSlot += 1;
michael@0 1675 }
michael@0 1676 }
michael@0 1677
michael@0 1678 void MultiTouchMotionAccumulator::finishSync() {
michael@0 1679 if (!mUsingSlotsProtocol) {
michael@0 1680 clearSlots(-1);
michael@0 1681 }
michael@0 1682 }
michael@0 1683
michael@0 1684 bool MultiTouchMotionAccumulator::hasStylus() const {
michael@0 1685 return mHaveStylus;
michael@0 1686 }
michael@0 1687
michael@0 1688
michael@0 1689 // --- MultiTouchMotionAccumulator::Slot ---
michael@0 1690
michael@0 1691 MultiTouchMotionAccumulator::Slot::Slot() {
michael@0 1692 clear();
michael@0 1693 }
michael@0 1694
michael@0 1695 void MultiTouchMotionAccumulator::Slot::clear() {
michael@0 1696 mInUse = false;
michael@0 1697 mHaveAbsMTTouchMinor = false;
michael@0 1698 mHaveAbsMTWidthMinor = false;
michael@0 1699 mHaveAbsMTToolType = false;
michael@0 1700 mAbsMTPositionX = 0;
michael@0 1701 mAbsMTPositionY = 0;
michael@0 1702 mAbsMTTouchMajor = 0;
michael@0 1703 mAbsMTTouchMinor = 0;
michael@0 1704 mAbsMTWidthMajor = 0;
michael@0 1705 mAbsMTWidthMinor = 0;
michael@0 1706 mAbsMTOrientation = 0;
michael@0 1707 mAbsMTTrackingId = -1;
michael@0 1708 mAbsMTPressure = 0;
michael@0 1709 mAbsMTDistance = 0;
michael@0 1710 mAbsMTToolType = 0;
michael@0 1711 }
michael@0 1712
michael@0 1713 int32_t MultiTouchMotionAccumulator::Slot::getToolType() const {
michael@0 1714 if (mHaveAbsMTToolType) {
michael@0 1715 switch (mAbsMTToolType) {
michael@0 1716 case MT_TOOL_FINGER:
michael@0 1717 return AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 1718 case MT_TOOL_PEN:
michael@0 1719 return AMOTION_EVENT_TOOL_TYPE_STYLUS;
michael@0 1720 }
michael@0 1721 }
michael@0 1722 return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
michael@0 1723 }
michael@0 1724
michael@0 1725
michael@0 1726 // --- InputMapper ---
michael@0 1727
michael@0 1728 InputMapper::InputMapper(InputDevice* device) :
michael@0 1729 mDevice(device), mContext(device->getContext()) {
michael@0 1730 }
michael@0 1731
michael@0 1732 InputMapper::~InputMapper() {
michael@0 1733 }
michael@0 1734
michael@0 1735 void InputMapper::populateDeviceInfo(InputDeviceInfo* info) {
michael@0 1736 info->addSource(getSources());
michael@0 1737 }
michael@0 1738
michael@0 1739 void InputMapper::dump(String8& dump) {
michael@0 1740 }
michael@0 1741
michael@0 1742 void InputMapper::configure(nsecs_t when,
michael@0 1743 const InputReaderConfiguration* config, uint32_t changes) {
michael@0 1744 }
michael@0 1745
michael@0 1746 void InputMapper::reset(nsecs_t when) {
michael@0 1747 }
michael@0 1748
michael@0 1749 void InputMapper::timeoutExpired(nsecs_t when) {
michael@0 1750 }
michael@0 1751
michael@0 1752 int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
michael@0 1753 return AKEY_STATE_UNKNOWN;
michael@0 1754 }
michael@0 1755
michael@0 1756 int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
michael@0 1757 return AKEY_STATE_UNKNOWN;
michael@0 1758 }
michael@0 1759
michael@0 1760 int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
michael@0 1761 return AKEY_STATE_UNKNOWN;
michael@0 1762 }
michael@0 1763
michael@0 1764 bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
michael@0 1765 const int32_t* keyCodes, uint8_t* outFlags) {
michael@0 1766 return false;
michael@0 1767 }
michael@0 1768
michael@0 1769 void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
michael@0 1770 int32_t token) {
michael@0 1771 }
michael@0 1772
michael@0 1773 void InputMapper::cancelVibrate(int32_t token) {
michael@0 1774 }
michael@0 1775
michael@0 1776 int32_t InputMapper::getMetaState() {
michael@0 1777 return 0;
michael@0 1778 }
michael@0 1779
michael@0 1780 void InputMapper::fadePointer() {
michael@0 1781 }
michael@0 1782
michael@0 1783 status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) {
michael@0 1784 return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo);
michael@0 1785 }
michael@0 1786
michael@0 1787 void InputMapper::bumpGeneration() {
michael@0 1788 mDevice->bumpGeneration();
michael@0 1789 }
michael@0 1790
michael@0 1791 void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump,
michael@0 1792 const RawAbsoluteAxisInfo& axis, const char* name) {
michael@0 1793 if (axis.valid) {
michael@0 1794 dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n",
michael@0 1795 name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution);
michael@0 1796 } else {
michael@0 1797 dump.appendFormat(INDENT4 "%s: unknown range\n", name);
michael@0 1798 }
michael@0 1799 }
michael@0 1800
michael@0 1801
michael@0 1802 // --- SwitchInputMapper ---
michael@0 1803
michael@0 1804 SwitchInputMapper::SwitchInputMapper(InputDevice* device) :
michael@0 1805 InputMapper(device), mUpdatedSwitchValues(0), mUpdatedSwitchMask(0) {
michael@0 1806 }
michael@0 1807
michael@0 1808 SwitchInputMapper::~SwitchInputMapper() {
michael@0 1809 }
michael@0 1810
michael@0 1811 uint32_t SwitchInputMapper::getSources() {
michael@0 1812 return AINPUT_SOURCE_SWITCH;
michael@0 1813 }
michael@0 1814
michael@0 1815 void SwitchInputMapper::process(const RawEvent* rawEvent) {
michael@0 1816 switch (rawEvent->type) {
michael@0 1817 case EV_SW:
michael@0 1818 processSwitch(rawEvent->code, rawEvent->value);
michael@0 1819 break;
michael@0 1820
michael@0 1821 case EV_SYN:
michael@0 1822 if (rawEvent->code == SYN_REPORT) {
michael@0 1823 sync(rawEvent->when);
michael@0 1824 }
michael@0 1825 }
michael@0 1826 }
michael@0 1827
michael@0 1828 void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
michael@0 1829 if (switchCode >= 0 && switchCode < 32) {
michael@0 1830 if (switchValue) {
michael@0 1831 mUpdatedSwitchValues |= 1 << switchCode;
michael@0 1832 }
michael@0 1833 mUpdatedSwitchMask |= 1 << switchCode;
michael@0 1834 }
michael@0 1835 }
michael@0 1836
michael@0 1837 void SwitchInputMapper::sync(nsecs_t when) {
michael@0 1838 if (mUpdatedSwitchMask) {
michael@0 1839 NotifySwitchArgs args(when, 0, mUpdatedSwitchValues, mUpdatedSwitchMask);
michael@0 1840 getListener()->notifySwitch(&args);
michael@0 1841
michael@0 1842 mUpdatedSwitchValues = 0;
michael@0 1843 mUpdatedSwitchMask = 0;
michael@0 1844 }
michael@0 1845 }
michael@0 1846
michael@0 1847 int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
michael@0 1848 return getEventHub()->getSwitchState(getDeviceId(), switchCode);
michael@0 1849 }
michael@0 1850
michael@0 1851
michael@0 1852 // --- VibratorInputMapper ---
michael@0 1853
michael@0 1854 VibratorInputMapper::VibratorInputMapper(InputDevice* device) :
michael@0 1855 InputMapper(device), mVibrating(false) {
michael@0 1856 }
michael@0 1857
michael@0 1858 VibratorInputMapper::~VibratorInputMapper() {
michael@0 1859 }
michael@0 1860
michael@0 1861 uint32_t VibratorInputMapper::getSources() {
michael@0 1862 return 0;
michael@0 1863 }
michael@0 1864
michael@0 1865 void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
michael@0 1866 InputMapper::populateDeviceInfo(info);
michael@0 1867
michael@0 1868 info->setVibrator(true);
michael@0 1869 }
michael@0 1870
michael@0 1871 void VibratorInputMapper::process(const RawEvent* rawEvent) {
michael@0 1872 // TODO: Handle FF_STATUS, although it does not seem to be widely supported.
michael@0 1873 }
michael@0 1874
michael@0 1875 void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
michael@0 1876 int32_t token) {
michael@0 1877 #if DEBUG_VIBRATOR
michael@0 1878 String8 patternStr;
michael@0 1879 for (size_t i = 0; i < patternSize; i++) {
michael@0 1880 if (i != 0) {
michael@0 1881 patternStr.append(", ");
michael@0 1882 }
michael@0 1883 patternStr.appendFormat("%lld", pattern[i]);
michael@0 1884 }
michael@0 1885 ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d",
michael@0 1886 getDeviceId(), patternStr.string(), repeat, token);
michael@0 1887 #endif
michael@0 1888
michael@0 1889 mVibrating = true;
michael@0 1890 memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t));
michael@0 1891 mPatternSize = patternSize;
michael@0 1892 mRepeat = repeat;
michael@0 1893 mToken = token;
michael@0 1894 mIndex = -1;
michael@0 1895
michael@0 1896 nextStep();
michael@0 1897 }
michael@0 1898
michael@0 1899 void VibratorInputMapper::cancelVibrate(int32_t token) {
michael@0 1900 #if DEBUG_VIBRATOR
michael@0 1901 ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token);
michael@0 1902 #endif
michael@0 1903
michael@0 1904 if (mVibrating && mToken == token) {
michael@0 1905 stopVibrating();
michael@0 1906 }
michael@0 1907 }
michael@0 1908
michael@0 1909 void VibratorInputMapper::timeoutExpired(nsecs_t when) {
michael@0 1910 if (mVibrating) {
michael@0 1911 if (when >= mNextStepTime) {
michael@0 1912 nextStep();
michael@0 1913 } else {
michael@0 1914 getContext()->requestTimeoutAtTime(mNextStepTime);
michael@0 1915 }
michael@0 1916 }
michael@0 1917 }
michael@0 1918
michael@0 1919 void VibratorInputMapper::nextStep() {
michael@0 1920 mIndex += 1;
michael@0 1921 if (size_t(mIndex) >= mPatternSize) {
michael@0 1922 if (mRepeat < 0) {
michael@0 1923 // We are done.
michael@0 1924 stopVibrating();
michael@0 1925 return;
michael@0 1926 }
michael@0 1927 mIndex = mRepeat;
michael@0 1928 }
michael@0 1929
michael@0 1930 bool vibratorOn = mIndex & 1;
michael@0 1931 nsecs_t duration = mPattern[mIndex];
michael@0 1932 if (vibratorOn) {
michael@0 1933 #if DEBUG_VIBRATOR
michael@0 1934 ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld",
michael@0 1935 getDeviceId(), duration);
michael@0 1936 #endif
michael@0 1937 getEventHub()->vibrate(getDeviceId(), duration);
michael@0 1938 } else {
michael@0 1939 #if DEBUG_VIBRATOR
michael@0 1940 ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId());
michael@0 1941 #endif
michael@0 1942 getEventHub()->cancelVibrate(getDeviceId());
michael@0 1943 }
michael@0 1944 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
michael@0 1945 mNextStepTime = now + duration;
michael@0 1946 getContext()->requestTimeoutAtTime(mNextStepTime);
michael@0 1947 #if DEBUG_VIBRATOR
michael@0 1948 ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f);
michael@0 1949 #endif
michael@0 1950 }
michael@0 1951
michael@0 1952 void VibratorInputMapper::stopVibrating() {
michael@0 1953 mVibrating = false;
michael@0 1954 #if DEBUG_VIBRATOR
michael@0 1955 ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId());
michael@0 1956 #endif
michael@0 1957 getEventHub()->cancelVibrate(getDeviceId());
michael@0 1958 }
michael@0 1959
michael@0 1960 void VibratorInputMapper::dump(String8& dump) {
michael@0 1961 dump.append(INDENT2 "Vibrator Input Mapper:\n");
michael@0 1962 dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating));
michael@0 1963 }
michael@0 1964
michael@0 1965
michael@0 1966 // --- KeyboardInputMapper ---
michael@0 1967
michael@0 1968 KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
michael@0 1969 uint32_t source, int32_t keyboardType) :
michael@0 1970 InputMapper(device), mSource(source),
michael@0 1971 mKeyboardType(keyboardType) {
michael@0 1972 }
michael@0 1973
michael@0 1974 KeyboardInputMapper::~KeyboardInputMapper() {
michael@0 1975 }
michael@0 1976
michael@0 1977 uint32_t KeyboardInputMapper::getSources() {
michael@0 1978 return mSource;
michael@0 1979 }
michael@0 1980
michael@0 1981 void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
michael@0 1982 InputMapper::populateDeviceInfo(info);
michael@0 1983
michael@0 1984 info->setKeyboardType(mKeyboardType);
michael@0 1985 info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId()));
michael@0 1986 }
michael@0 1987
michael@0 1988 void KeyboardInputMapper::dump(String8& dump) {
michael@0 1989 dump.append(INDENT2 "Keyboard Input Mapper:\n");
michael@0 1990 dumpParameters(dump);
michael@0 1991 dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType);
michael@0 1992 dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
michael@0 1993 dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mKeyDowns.size());
michael@0 1994 dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState);
michael@0 1995 dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime);
michael@0 1996 }
michael@0 1997
michael@0 1998
michael@0 1999 void KeyboardInputMapper::configure(nsecs_t when,
michael@0 2000 const InputReaderConfiguration* config, uint32_t changes) {
michael@0 2001 InputMapper::configure(when, config, changes);
michael@0 2002
michael@0 2003 if (!changes) { // first time only
michael@0 2004 // Configure basic parameters.
michael@0 2005 configureParameters();
michael@0 2006 }
michael@0 2007
michael@0 2008 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
michael@0 2009 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
michael@0 2010 DisplayViewport v;
michael@0 2011 if (config->getDisplayInfo(false /*external*/, &v)) {
michael@0 2012 mOrientation = v.orientation;
michael@0 2013 } else {
michael@0 2014 mOrientation = DISPLAY_ORIENTATION_0;
michael@0 2015 }
michael@0 2016 } else {
michael@0 2017 mOrientation = DISPLAY_ORIENTATION_0;
michael@0 2018 }
michael@0 2019 }
michael@0 2020 }
michael@0 2021
michael@0 2022 void KeyboardInputMapper::configureParameters() {
michael@0 2023 mParameters.orientationAware = false;
michael@0 2024 getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
michael@0 2025 mParameters.orientationAware);
michael@0 2026
michael@0 2027 mParameters.hasAssociatedDisplay = false;
michael@0 2028 if (mParameters.orientationAware) {
michael@0 2029 mParameters.hasAssociatedDisplay = true;
michael@0 2030 }
michael@0 2031 }
michael@0 2032
michael@0 2033 void KeyboardInputMapper::dumpParameters(String8& dump) {
michael@0 2034 dump.append(INDENT3 "Parameters:\n");
michael@0 2035 dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
michael@0 2036 toString(mParameters.hasAssociatedDisplay));
michael@0 2037 dump.appendFormat(INDENT4 "OrientationAware: %s\n",
michael@0 2038 toString(mParameters.orientationAware));
michael@0 2039 }
michael@0 2040
michael@0 2041 void KeyboardInputMapper::reset(nsecs_t when) {
michael@0 2042 mMetaState = AMETA_NONE;
michael@0 2043 mDownTime = 0;
michael@0 2044 mKeyDowns.clear();
michael@0 2045 mCurrentHidUsage = 0;
michael@0 2046
michael@0 2047 resetLedState();
michael@0 2048
michael@0 2049 InputMapper::reset(when);
michael@0 2050 }
michael@0 2051
michael@0 2052 void KeyboardInputMapper::process(const RawEvent* rawEvent) {
michael@0 2053 switch (rawEvent->type) {
michael@0 2054 case EV_KEY: {
michael@0 2055 int32_t scanCode = rawEvent->code;
michael@0 2056 int32_t usageCode = mCurrentHidUsage;
michael@0 2057 mCurrentHidUsage = 0;
michael@0 2058
michael@0 2059 if (isKeyboardOrGamepadKey(scanCode)) {
michael@0 2060 int32_t keyCode;
michael@0 2061 uint32_t flags;
michael@0 2062 if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {
michael@0 2063 keyCode = AKEYCODE_UNKNOWN;
michael@0 2064 flags = 0;
michael@0 2065 }
michael@0 2066 processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
michael@0 2067 }
michael@0 2068 break;
michael@0 2069 }
michael@0 2070 case EV_MSC: {
michael@0 2071 if (rawEvent->code == MSC_SCAN) {
michael@0 2072 mCurrentHidUsage = rawEvent->value;
michael@0 2073 }
michael@0 2074 break;
michael@0 2075 }
michael@0 2076 case EV_SYN: {
michael@0 2077 if (rawEvent->code == SYN_REPORT) {
michael@0 2078 mCurrentHidUsage = 0;
michael@0 2079 }
michael@0 2080 }
michael@0 2081 }
michael@0 2082 }
michael@0 2083
michael@0 2084 bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
michael@0 2085 return scanCode < BTN_MOUSE
michael@0 2086 || scanCode >= KEY_OK
michael@0 2087 || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE)
michael@0 2088 || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
michael@0 2089 }
michael@0 2090
michael@0 2091 void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
michael@0 2092 int32_t scanCode, uint32_t policyFlags) {
michael@0 2093
michael@0 2094 if (down) {
michael@0 2095 // Rotate key codes according to orientation if needed.
michael@0 2096 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
michael@0 2097 keyCode = rotateKeyCode(keyCode, mOrientation);
michael@0 2098 }
michael@0 2099
michael@0 2100 // Add key down.
michael@0 2101 ssize_t keyDownIndex = findKeyDown(scanCode);
michael@0 2102 if (keyDownIndex >= 0) {
michael@0 2103 // key repeat, be sure to use same keycode as before in case of rotation
michael@0 2104 keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
michael@0 2105 } else {
michael@0 2106 // key down
michael@0 2107 if ((policyFlags & POLICY_FLAG_VIRTUAL)
michael@0 2108 && mContext->shouldDropVirtualKey(when,
michael@0 2109 getDevice(), keyCode, scanCode)) {
michael@0 2110 return;
michael@0 2111 }
michael@0 2112
michael@0 2113 mKeyDowns.push();
michael@0 2114 KeyDown& keyDown = mKeyDowns.editTop();
michael@0 2115 keyDown.keyCode = keyCode;
michael@0 2116 keyDown.scanCode = scanCode;
michael@0 2117 }
michael@0 2118
michael@0 2119 mDownTime = when;
michael@0 2120 } else {
michael@0 2121 // Remove key down.
michael@0 2122 ssize_t keyDownIndex = findKeyDown(scanCode);
michael@0 2123 if (keyDownIndex >= 0) {
michael@0 2124 // key up, be sure to use same keycode as before in case of rotation
michael@0 2125 keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
michael@0 2126 mKeyDowns.removeAt(size_t(keyDownIndex));
michael@0 2127 } else {
michael@0 2128 // key was not actually down
michael@0 2129 ALOGI("Dropping key up from device %s because the key was not down. "
michael@0 2130 "keyCode=%d, scanCode=%d",
michael@0 2131 getDeviceName().string(), keyCode, scanCode);
michael@0 2132 return;
michael@0 2133 }
michael@0 2134 }
michael@0 2135
michael@0 2136 bool metaStateChanged = false;
michael@0 2137 int32_t oldMetaState = mMetaState;
michael@0 2138 int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
michael@0 2139 if (oldMetaState != newMetaState) {
michael@0 2140 mMetaState = newMetaState;
michael@0 2141 metaStateChanged = true;
michael@0 2142 updateLedState(false);
michael@0 2143 }
michael@0 2144
michael@0 2145 nsecs_t downTime = mDownTime;
michael@0 2146
michael@0 2147 // Key down on external an keyboard should wake the device.
michael@0 2148 // We don't do this for internal keyboards to prevent them from waking up in your pocket.
michael@0 2149 // For internal keyboards, the key layout file should specify the policy flags for
michael@0 2150 // each wake key individually.
michael@0 2151 // TODO: Use the input device configuration to control this behavior more finely.
michael@0 2152 if (down && getDevice()->isExternal()
michael@0 2153 && !(policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED))) {
michael@0 2154 policyFlags |= POLICY_FLAG_WAKE_DROPPED;
michael@0 2155 }
michael@0 2156
michael@0 2157 if (metaStateChanged) {
michael@0 2158 getContext()->updateGlobalMetaState();
michael@0 2159 }
michael@0 2160
michael@0 2161 if (down && !isMetaKey(keyCode)) {
michael@0 2162 getContext()->fadePointer();
michael@0 2163 }
michael@0 2164
michael@0 2165 NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 2166 down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
michael@0 2167 AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
michael@0 2168 getListener()->notifyKey(&args);
michael@0 2169 }
michael@0 2170
michael@0 2171 ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
michael@0 2172 size_t n = mKeyDowns.size();
michael@0 2173 for (size_t i = 0; i < n; i++) {
michael@0 2174 if (mKeyDowns[i].scanCode == scanCode) {
michael@0 2175 return i;
michael@0 2176 }
michael@0 2177 }
michael@0 2178 return -1;
michael@0 2179 }
michael@0 2180
michael@0 2181 int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
michael@0 2182 return getEventHub()->getKeyCodeState(getDeviceId(), keyCode);
michael@0 2183 }
michael@0 2184
michael@0 2185 int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
michael@0 2186 return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
michael@0 2187 }
michael@0 2188
michael@0 2189 bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
michael@0 2190 const int32_t* keyCodes, uint8_t* outFlags) {
michael@0 2191 return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags);
michael@0 2192 }
michael@0 2193
michael@0 2194 int32_t KeyboardInputMapper::getMetaState() {
michael@0 2195 return mMetaState;
michael@0 2196 }
michael@0 2197
michael@0 2198 void KeyboardInputMapper::resetLedState() {
michael@0 2199 initializeLedState(mCapsLockLedState, LED_CAPSL);
michael@0 2200 initializeLedState(mNumLockLedState, LED_NUML);
michael@0 2201 initializeLedState(mScrollLockLedState, LED_SCROLLL);
michael@0 2202
michael@0 2203 updateLedState(true);
michael@0 2204 }
michael@0 2205
michael@0 2206 void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) {
michael@0 2207 ledState.avail = getEventHub()->hasLed(getDeviceId(), led);
michael@0 2208 ledState.on = false;
michael@0 2209 }
michael@0 2210
michael@0 2211 void KeyboardInputMapper::updateLedState(bool reset) {
michael@0 2212 updateLedStateForModifier(mCapsLockLedState, LED_CAPSL,
michael@0 2213 AMETA_CAPS_LOCK_ON, reset);
michael@0 2214 updateLedStateForModifier(mNumLockLedState, LED_NUML,
michael@0 2215 AMETA_NUM_LOCK_ON, reset);
michael@0 2216 updateLedStateForModifier(mScrollLockLedState, LED_SCROLLL,
michael@0 2217 AMETA_SCROLL_LOCK_ON, reset);
michael@0 2218 }
michael@0 2219
michael@0 2220 void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState,
michael@0 2221 int32_t led, int32_t modifier, bool reset) {
michael@0 2222 if (ledState.avail) {
michael@0 2223 bool desiredState = (mMetaState & modifier) != 0;
michael@0 2224 if (reset || ledState.on != desiredState) {
michael@0 2225 getEventHub()->setLedState(getDeviceId(), led, desiredState);
michael@0 2226 ledState.on = desiredState;
michael@0 2227 }
michael@0 2228 }
michael@0 2229 }
michael@0 2230
michael@0 2231
michael@0 2232 // --- CursorInputMapper ---
michael@0 2233
michael@0 2234 CursorInputMapper::CursorInputMapper(InputDevice* device) :
michael@0 2235 InputMapper(device) {
michael@0 2236 }
michael@0 2237
michael@0 2238 CursorInputMapper::~CursorInputMapper() {
michael@0 2239 }
michael@0 2240
michael@0 2241 uint32_t CursorInputMapper::getSources() {
michael@0 2242 return mSource;
michael@0 2243 }
michael@0 2244
michael@0 2245 void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
michael@0 2246 InputMapper::populateDeviceInfo(info);
michael@0 2247
michael@0 2248 if (mParameters.mode == Parameters::MODE_POINTER) {
michael@0 2249 float minX, minY, maxX, maxY;
michael@0 2250 if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
michael@0 2251 info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
michael@0 2252 info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f);
michael@0 2253 }
michael@0 2254 } else {
michael@0 2255 info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
michael@0 2256 info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
michael@0 2257 }
michael@0 2258 info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
michael@0 2259
michael@0 2260 if (mCursorScrollAccumulator.haveRelativeVWheel()) {
michael@0 2261 info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
michael@0 2262 }
michael@0 2263 if (mCursorScrollAccumulator.haveRelativeHWheel()) {
michael@0 2264 info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
michael@0 2265 }
michael@0 2266 }
michael@0 2267
michael@0 2268 void CursorInputMapper::dump(String8& dump) {
michael@0 2269 dump.append(INDENT2 "Cursor Input Mapper:\n");
michael@0 2270 dumpParameters(dump);
michael@0 2271 dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale);
michael@0 2272 dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale);
michael@0 2273 dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
michael@0 2274 dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
michael@0 2275 dump.appendFormat(INDENT3 "HaveVWheel: %s\n",
michael@0 2276 toString(mCursorScrollAccumulator.haveRelativeVWheel()));
michael@0 2277 dump.appendFormat(INDENT3 "HaveHWheel: %s\n",
michael@0 2278 toString(mCursorScrollAccumulator.haveRelativeHWheel()));
michael@0 2279 dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
michael@0 2280 dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
michael@0 2281 dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
michael@0 2282 dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
michael@0 2283 dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
michael@0 2284 dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime);
michael@0 2285 }
michael@0 2286
michael@0 2287 void CursorInputMapper::configure(nsecs_t when,
michael@0 2288 const InputReaderConfiguration* config, uint32_t changes) {
michael@0 2289 InputMapper::configure(when, config, changes);
michael@0 2290
michael@0 2291 if (!changes) { // first time only
michael@0 2292 mCursorScrollAccumulator.configure(getDevice());
michael@0 2293
michael@0 2294 // Configure basic parameters.
michael@0 2295 configureParameters();
michael@0 2296
michael@0 2297 // Configure device mode.
michael@0 2298 switch (mParameters.mode) {
michael@0 2299 case Parameters::MODE_POINTER:
michael@0 2300 mSource = AINPUT_SOURCE_MOUSE;
michael@0 2301 mXPrecision = 1.0f;
michael@0 2302 mYPrecision = 1.0f;
michael@0 2303 mXScale = 1.0f;
michael@0 2304 mYScale = 1.0f;
michael@0 2305 mPointerController = getPolicy()->obtainPointerController(getDeviceId());
michael@0 2306 break;
michael@0 2307 case Parameters::MODE_NAVIGATION:
michael@0 2308 mSource = AINPUT_SOURCE_TRACKBALL;
michael@0 2309 mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
michael@0 2310 mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
michael@0 2311 mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
michael@0 2312 mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
michael@0 2313 break;
michael@0 2314 }
michael@0 2315
michael@0 2316 mVWheelScale = 1.0f;
michael@0 2317 mHWheelScale = 1.0f;
michael@0 2318 }
michael@0 2319
michael@0 2320 if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
michael@0 2321 mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
michael@0 2322 mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
michael@0 2323 mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
michael@0 2324 }
michael@0 2325
michael@0 2326 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
michael@0 2327 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
michael@0 2328 DisplayViewport v;
michael@0 2329 if (config->getDisplayInfo(false /*external*/, &v)) {
michael@0 2330 mOrientation = v.orientation;
michael@0 2331 } else {
michael@0 2332 mOrientation = DISPLAY_ORIENTATION_0;
michael@0 2333 }
michael@0 2334 } else {
michael@0 2335 mOrientation = DISPLAY_ORIENTATION_0;
michael@0 2336 }
michael@0 2337 bumpGeneration();
michael@0 2338 }
michael@0 2339 }
michael@0 2340
michael@0 2341 void CursorInputMapper::configureParameters() {
michael@0 2342 mParameters.mode = Parameters::MODE_POINTER;
michael@0 2343 String8 cursorModeString;
michael@0 2344 if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) {
michael@0 2345 if (cursorModeString == "navigation") {
michael@0 2346 mParameters.mode = Parameters::MODE_NAVIGATION;
michael@0 2347 } else if (cursorModeString != "pointer" && cursorModeString != "default") {
michael@0 2348 ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
michael@0 2349 }
michael@0 2350 }
michael@0 2351
michael@0 2352 mParameters.orientationAware = false;
michael@0 2353 getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
michael@0 2354 mParameters.orientationAware);
michael@0 2355
michael@0 2356 mParameters.hasAssociatedDisplay = false;
michael@0 2357 if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
michael@0 2358 mParameters.hasAssociatedDisplay = true;
michael@0 2359 }
michael@0 2360 }
michael@0 2361
michael@0 2362 void CursorInputMapper::dumpParameters(String8& dump) {
michael@0 2363 dump.append(INDENT3 "Parameters:\n");
michael@0 2364 dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
michael@0 2365 toString(mParameters.hasAssociatedDisplay));
michael@0 2366
michael@0 2367 switch (mParameters.mode) {
michael@0 2368 case Parameters::MODE_POINTER:
michael@0 2369 dump.append(INDENT4 "Mode: pointer\n");
michael@0 2370 break;
michael@0 2371 case Parameters::MODE_NAVIGATION:
michael@0 2372 dump.append(INDENT4 "Mode: navigation\n");
michael@0 2373 break;
michael@0 2374 default:
michael@0 2375 ALOG_ASSERT(false);
michael@0 2376 }
michael@0 2377
michael@0 2378 dump.appendFormat(INDENT4 "OrientationAware: %s\n",
michael@0 2379 toString(mParameters.orientationAware));
michael@0 2380 }
michael@0 2381
michael@0 2382 void CursorInputMapper::reset(nsecs_t when) {
michael@0 2383 mButtonState = 0;
michael@0 2384 mDownTime = 0;
michael@0 2385
michael@0 2386 mPointerVelocityControl.reset();
michael@0 2387 mWheelXVelocityControl.reset();
michael@0 2388 mWheelYVelocityControl.reset();
michael@0 2389
michael@0 2390 mCursorButtonAccumulator.reset(getDevice());
michael@0 2391 mCursorMotionAccumulator.reset(getDevice());
michael@0 2392 mCursorScrollAccumulator.reset(getDevice());
michael@0 2393
michael@0 2394 InputMapper::reset(when);
michael@0 2395 }
michael@0 2396
michael@0 2397 void CursorInputMapper::process(const RawEvent* rawEvent) {
michael@0 2398 mCursorButtonAccumulator.process(rawEvent);
michael@0 2399 mCursorMotionAccumulator.process(rawEvent);
michael@0 2400 mCursorScrollAccumulator.process(rawEvent);
michael@0 2401
michael@0 2402 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
michael@0 2403 sync(rawEvent->when);
michael@0 2404 }
michael@0 2405 }
michael@0 2406
michael@0 2407 void CursorInputMapper::sync(nsecs_t when) {
michael@0 2408 int32_t lastButtonState = mButtonState;
michael@0 2409 int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
michael@0 2410 mButtonState = currentButtonState;
michael@0 2411
michael@0 2412 bool wasDown = isPointerDown(lastButtonState);
michael@0 2413 bool down = isPointerDown(currentButtonState);
michael@0 2414 bool downChanged;
michael@0 2415 if (!wasDown && down) {
michael@0 2416 mDownTime = when;
michael@0 2417 downChanged = true;
michael@0 2418 } else if (wasDown && !down) {
michael@0 2419 downChanged = true;
michael@0 2420 } else {
michael@0 2421 downChanged = false;
michael@0 2422 }
michael@0 2423 nsecs_t downTime = mDownTime;
michael@0 2424 bool buttonsChanged = currentButtonState != lastButtonState;
michael@0 2425 bool buttonsPressed = currentButtonState & ~lastButtonState;
michael@0 2426
michael@0 2427 float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
michael@0 2428 float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
michael@0 2429 bool moved = deltaX != 0 || deltaY != 0;
michael@0 2430
michael@0 2431 // Rotate delta according to orientation if needed.
michael@0 2432 if (mParameters.orientationAware && mParameters.hasAssociatedDisplay
michael@0 2433 && (deltaX != 0.0f || deltaY != 0.0f)) {
michael@0 2434 rotateDelta(mOrientation, &deltaX, &deltaY);
michael@0 2435 }
michael@0 2436
michael@0 2437 // Move the pointer.
michael@0 2438 PointerProperties pointerProperties;
michael@0 2439 pointerProperties.clear();
michael@0 2440 pointerProperties.id = 0;
michael@0 2441 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;
michael@0 2442
michael@0 2443 PointerCoords pointerCoords;
michael@0 2444 pointerCoords.clear();
michael@0 2445
michael@0 2446 float vscroll = mCursorScrollAccumulator.getRelativeVWheel();
michael@0 2447 float hscroll = mCursorScrollAccumulator.getRelativeHWheel();
michael@0 2448 bool scrolled = vscroll != 0 || hscroll != 0;
michael@0 2449
michael@0 2450 mWheelYVelocityControl.move(when, NULL, &vscroll);
michael@0 2451 mWheelXVelocityControl.move(when, &hscroll, NULL);
michael@0 2452
michael@0 2453 mPointerVelocityControl.move(when, &deltaX, &deltaY);
michael@0 2454
michael@0 2455 int32_t displayId;
michael@0 2456 if (mPointerController != NULL) {
michael@0 2457 if (moved || scrolled || buttonsChanged) {
michael@0 2458 mPointerController->setPresentation(
michael@0 2459 PointerControllerInterface::PRESENTATION_POINTER);
michael@0 2460
michael@0 2461 if (moved) {
michael@0 2462 mPointerController->move(deltaX, deltaY);
michael@0 2463 }
michael@0 2464
michael@0 2465 if (buttonsChanged) {
michael@0 2466 mPointerController->setButtonState(currentButtonState);
michael@0 2467 }
michael@0 2468
michael@0 2469 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
michael@0 2470 }
michael@0 2471
michael@0 2472 float x, y;
michael@0 2473 mPointerController->getPosition(&x, &y);
michael@0 2474 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
michael@0 2475 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
michael@0 2476 displayId = ADISPLAY_ID_DEFAULT;
michael@0 2477 } else {
michael@0 2478 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
michael@0 2479 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
michael@0 2480 displayId = ADISPLAY_ID_NONE;
michael@0 2481 }
michael@0 2482
michael@0 2483 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
michael@0 2484
michael@0 2485 // Moving an external trackball or mouse should wake the device.
michael@0 2486 // We don't do this for internal cursor devices to prevent them from waking up
michael@0 2487 // the device in your pocket.
michael@0 2488 // TODO: Use the input device configuration to control this behavior more finely.
michael@0 2489 uint32_t policyFlags = 0;
michael@0 2490 if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) {
michael@0 2491 policyFlags |= POLICY_FLAG_WAKE_DROPPED;
michael@0 2492 }
michael@0 2493
michael@0 2494 // Synthesize key down from buttons if needed.
michael@0 2495 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
michael@0 2496 policyFlags, lastButtonState, currentButtonState);
michael@0 2497
michael@0 2498 // Send motion event.
michael@0 2499 if (downChanged || moved || scrolled || buttonsChanged) {
michael@0 2500 int32_t metaState = mContext->getGlobalMetaState();
michael@0 2501 int32_t motionEventAction;
michael@0 2502 if (downChanged) {
michael@0 2503 motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
michael@0 2504 } else if (down || mPointerController == NULL) {
michael@0 2505 motionEventAction = AMOTION_EVENT_ACTION_MOVE;
michael@0 2506 } else {
michael@0 2507 motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
michael@0 2508 }
michael@0 2509
michael@0 2510 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 2511 motionEventAction, 0, metaState, currentButtonState, 0,
michael@0 2512 displayId, 1, &pointerProperties, &pointerCoords,
michael@0 2513 mXPrecision, mYPrecision, downTime);
michael@0 2514 getListener()->notifyMotion(&args);
michael@0 2515
michael@0 2516 // Send hover move after UP to tell the application that the mouse is hovering now.
michael@0 2517 if (motionEventAction == AMOTION_EVENT_ACTION_UP
michael@0 2518 && mPointerController != NULL) {
michael@0 2519 NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
michael@0 2520 AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
michael@0 2521 metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 2522 displayId, 1, &pointerProperties, &pointerCoords,
michael@0 2523 mXPrecision, mYPrecision, downTime);
michael@0 2524 getListener()->notifyMotion(&hoverArgs);
michael@0 2525 }
michael@0 2526
michael@0 2527 // Send scroll events.
michael@0 2528 if (scrolled) {
michael@0 2529 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
michael@0 2530 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
michael@0 2531
michael@0 2532 NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
michael@0 2533 AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState,
michael@0 2534 AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 2535 displayId, 1, &pointerProperties, &pointerCoords,
michael@0 2536 mXPrecision, mYPrecision, downTime);
michael@0 2537 getListener()->notifyMotion(&scrollArgs);
michael@0 2538 }
michael@0 2539 }
michael@0 2540
michael@0 2541 // Synthesize key up from buttons if needed.
michael@0 2542 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
michael@0 2543 policyFlags, lastButtonState, currentButtonState);
michael@0 2544
michael@0 2545 mCursorMotionAccumulator.finishSync();
michael@0 2546 mCursorScrollAccumulator.finishSync();
michael@0 2547 }
michael@0 2548
michael@0 2549 int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
michael@0 2550 if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) {
michael@0 2551 return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
michael@0 2552 } else {
michael@0 2553 return AKEY_STATE_UNKNOWN;
michael@0 2554 }
michael@0 2555 }
michael@0 2556
michael@0 2557 void CursorInputMapper::fadePointer() {
michael@0 2558 if (mPointerController != NULL) {
michael@0 2559 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
michael@0 2560 }
michael@0 2561 }
michael@0 2562
michael@0 2563
michael@0 2564 // --- TouchInputMapper ---
michael@0 2565
michael@0 2566 TouchInputMapper::TouchInputMapper(InputDevice* device) :
michael@0 2567 InputMapper(device),
michael@0 2568 mSource(0), mDeviceMode(DEVICE_MODE_DISABLED),
michael@0 2569 mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0),
michael@0 2570 mSurfaceOrientation(DISPLAY_ORIENTATION_0) {
michael@0 2571 }
michael@0 2572
michael@0 2573 TouchInputMapper::~TouchInputMapper() {
michael@0 2574 }
michael@0 2575
michael@0 2576 uint32_t TouchInputMapper::getSources() {
michael@0 2577 return mSource;
michael@0 2578 }
michael@0 2579
michael@0 2580 void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
michael@0 2581 InputMapper::populateDeviceInfo(info);
michael@0 2582
michael@0 2583 if (mDeviceMode != DEVICE_MODE_DISABLED) {
michael@0 2584 info->addMotionRange(mOrientedRanges.x);
michael@0 2585 info->addMotionRange(mOrientedRanges.y);
michael@0 2586 info->addMotionRange(mOrientedRanges.pressure);
michael@0 2587
michael@0 2588 if (mOrientedRanges.haveSize) {
michael@0 2589 info->addMotionRange(mOrientedRanges.size);
michael@0 2590 }
michael@0 2591
michael@0 2592 if (mOrientedRanges.haveTouchSize) {
michael@0 2593 info->addMotionRange(mOrientedRanges.touchMajor);
michael@0 2594 info->addMotionRange(mOrientedRanges.touchMinor);
michael@0 2595 }
michael@0 2596
michael@0 2597 if (mOrientedRanges.haveToolSize) {
michael@0 2598 info->addMotionRange(mOrientedRanges.toolMajor);
michael@0 2599 info->addMotionRange(mOrientedRanges.toolMinor);
michael@0 2600 }
michael@0 2601
michael@0 2602 if (mOrientedRanges.haveOrientation) {
michael@0 2603 info->addMotionRange(mOrientedRanges.orientation);
michael@0 2604 }
michael@0 2605
michael@0 2606 if (mOrientedRanges.haveDistance) {
michael@0 2607 info->addMotionRange(mOrientedRanges.distance);
michael@0 2608 }
michael@0 2609
michael@0 2610 if (mOrientedRanges.haveTilt) {
michael@0 2611 info->addMotionRange(mOrientedRanges.tilt);
michael@0 2612 }
michael@0 2613
michael@0 2614 if (mCursorScrollAccumulator.haveRelativeVWheel()) {
michael@0 2615 info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
michael@0 2616 0.0f);
michael@0 2617 }
michael@0 2618 if (mCursorScrollAccumulator.haveRelativeHWheel()) {
michael@0 2619 info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
michael@0 2620 0.0f);
michael@0 2621 }
michael@0 2622 if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
michael@0 2623 const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
michael@0 2624 const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
michael@0 2625 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat,
michael@0 2626 x.fuzz, x.resolution);
michael@0 2627 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat,
michael@0 2628 y.fuzz, y.resolution);
michael@0 2629 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat,
michael@0 2630 x.fuzz, x.resolution);
michael@0 2631 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat,
michael@0 2632 y.fuzz, y.resolution);
michael@0 2633 }
michael@0 2634 }
michael@0 2635 }
michael@0 2636
michael@0 2637 void TouchInputMapper::dump(String8& dump) {
michael@0 2638 dump.append(INDENT2 "Touch Input Mapper:\n");
michael@0 2639 dumpParameters(dump);
michael@0 2640 dumpVirtualKeys(dump);
michael@0 2641 dumpRawPointerAxes(dump);
michael@0 2642 dumpCalibration(dump);
michael@0 2643 dumpSurface(dump);
michael@0 2644
michael@0 2645 dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
michael@0 2646 dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
michael@0 2647 dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
michael@0 2648 dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale);
michael@0 2649 dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale);
michael@0 2650 dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
michael@0 2651 dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
michael@0 2652 dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
michael@0 2653 dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
michael@0 2654 dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
michael@0 2655 dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale);
michael@0 2656 dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale);
michael@0 2657 dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt));
michael@0 2658 dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter);
michael@0 2659 dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale);
michael@0 2660 dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
michael@0 2661 dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
michael@0 2662
michael@0 2663 dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState);
michael@0 2664
michael@0 2665 dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n",
michael@0 2666 mLastRawPointerData.pointerCount);
michael@0 2667 for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) {
michael@0 2668 const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i];
michael@0 2669 dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
michael@0 2670 "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
michael@0 2671 "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
michael@0 2672 "toolType=%d, isHovering=%s\n", i,
michael@0 2673 pointer.id, pointer.x, pointer.y, pointer.pressure,
michael@0 2674 pointer.touchMajor, pointer.touchMinor,
michael@0 2675 pointer.toolMajor, pointer.toolMinor,
michael@0 2676 pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance,
michael@0 2677 pointer.toolType, toString(pointer.isHovering));
michael@0 2678 }
michael@0 2679
michael@0 2680 dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
michael@0 2681 mLastCookedPointerData.pointerCount);
michael@0 2682 for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) {
michael@0 2683 const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i];
michael@0 2684 const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i];
michael@0 2685 dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
michael@0 2686 "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, "
michael@0 2687 "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
michael@0 2688 "toolType=%d, isHovering=%s\n", i,
michael@0 2689 pointerProperties.id,
michael@0 2690 pointerCoords.getX(),
michael@0 2691 pointerCoords.getY(),
michael@0 2692 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
michael@0 2693 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
michael@0 2694 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
michael@0 2695 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
michael@0 2696 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
michael@0 2697 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
michael@0 2698 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT),
michael@0 2699 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE),
michael@0 2700 pointerProperties.toolType,
michael@0 2701 toString(mLastCookedPointerData.isHovering(i)));
michael@0 2702 }
michael@0 2703
michael@0 2704 if (mDeviceMode == DEVICE_MODE_POINTER) {
michael@0 2705 dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
michael@0 2706 dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
michael@0 2707 mPointerXMovementScale);
michael@0 2708 dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n",
michael@0 2709 mPointerYMovementScale);
michael@0 2710 dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n",
michael@0 2711 mPointerXZoomScale);
michael@0 2712 dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n",
michael@0 2713 mPointerYZoomScale);
michael@0 2714 dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n",
michael@0 2715 mPointerGestureMaxSwipeWidth);
michael@0 2716 }
michael@0 2717 }
michael@0 2718
michael@0 2719 void TouchInputMapper::configure(nsecs_t when,
michael@0 2720 const InputReaderConfiguration* config, uint32_t changes) {
michael@0 2721 InputMapper::configure(when, config, changes);
michael@0 2722
michael@0 2723 mConfig = *config;
michael@0 2724
michael@0 2725 if (!changes) { // first time only
michael@0 2726 // Configure basic parameters.
michael@0 2727 configureParameters();
michael@0 2728
michael@0 2729 // Configure common accumulators.
michael@0 2730 mCursorScrollAccumulator.configure(getDevice());
michael@0 2731 mTouchButtonAccumulator.configure(getDevice());
michael@0 2732
michael@0 2733 // Configure absolute axis information.
michael@0 2734 configureRawPointerAxes();
michael@0 2735
michael@0 2736 // Prepare input device calibration.
michael@0 2737 parseCalibration();
michael@0 2738 resolveCalibration();
michael@0 2739 }
michael@0 2740
michael@0 2741 if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
michael@0 2742 // Update pointer speed.
michael@0 2743 mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
michael@0 2744 mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
michael@0 2745 mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
michael@0 2746 }
michael@0 2747
michael@0 2748 bool resetNeeded = false;
michael@0 2749 if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO
michael@0 2750 | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
michael@0 2751 | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) {
michael@0 2752 // Configure device sources, surface dimensions, orientation and
michael@0 2753 // scaling factors.
michael@0 2754 configureSurface(when, &resetNeeded);
michael@0 2755 }
michael@0 2756
michael@0 2757 if (changes && resetNeeded) {
michael@0 2758 // Send reset, unless this is the first time the device has been configured,
michael@0 2759 // in which case the reader will call reset itself after all mappers are ready.
michael@0 2760 getDevice()->notifyReset(when);
michael@0 2761 }
michael@0 2762 }
michael@0 2763
michael@0 2764 void TouchInputMapper::configureParameters() {
michael@0 2765 // Use the pointer presentation mode for devices that do not support distinct
michael@0 2766 // multitouch. The spot-based presentation relies on being able to accurately
michael@0 2767 // locate two or more fingers on the touch pad.
michael@0 2768 mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT)
michael@0 2769 ? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS;
michael@0 2770
michael@0 2771 String8 gestureModeString;
michael@0 2772 if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"),
michael@0 2773 gestureModeString)) {
michael@0 2774 if (gestureModeString == "pointer") {
michael@0 2775 mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER;
michael@0 2776 } else if (gestureModeString == "spots") {
michael@0 2777 mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS;
michael@0 2778 } else if (gestureModeString != "default") {
michael@0 2779 ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
michael@0 2780 }
michael@0 2781 }
michael@0 2782
michael@0 2783 if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) {
michael@0 2784 // The device is a touch screen.
michael@0 2785 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
michael@0 2786 } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) {
michael@0 2787 // The device is a pointing device like a track pad.
michael@0 2788 mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
michael@0 2789 } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X)
michael@0 2790 || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) {
michael@0 2791 // The device is a cursor device with a touch pad attached.
michael@0 2792 // By default don't use the touch pad to move the pointer.
michael@0 2793 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
michael@0 2794 } else {
michael@0 2795 // The device is a touch pad of unknown purpose.
michael@0 2796 mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
michael@0 2797 }
michael@0 2798
michael@0 2799 String8 deviceTypeString;
michael@0 2800 if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
michael@0 2801 deviceTypeString)) {
michael@0 2802 if (deviceTypeString == "touchScreen") {
michael@0 2803 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
michael@0 2804 } else if (deviceTypeString == "touchPad") {
michael@0 2805 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
michael@0 2806 } else if (deviceTypeString == "touchNavigation") {
michael@0 2807 mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION;
michael@0 2808 } else if (deviceTypeString == "pointer") {
michael@0 2809 mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
michael@0 2810 } else if (deviceTypeString != "default") {
michael@0 2811 ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
michael@0 2812 }
michael@0 2813 }
michael@0 2814
michael@0 2815 mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
michael@0 2816 getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
michael@0 2817 mParameters.orientationAware);
michael@0 2818
michael@0 2819 mParameters.hasAssociatedDisplay = false;
michael@0 2820 mParameters.associatedDisplayIsExternal = false;
michael@0 2821 if (mParameters.orientationAware
michael@0 2822 || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
michael@0 2823 || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
michael@0 2824 mParameters.hasAssociatedDisplay = true;
michael@0 2825 mParameters.associatedDisplayIsExternal =
michael@0 2826 mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
michael@0 2827 && getDevice()->isExternal();
michael@0 2828 }
michael@0 2829 }
michael@0 2830
michael@0 2831 void TouchInputMapper::dumpParameters(String8& dump) {
michael@0 2832 dump.append(INDENT3 "Parameters:\n");
michael@0 2833
michael@0 2834 switch (mParameters.gestureMode) {
michael@0 2835 case Parameters::GESTURE_MODE_POINTER:
michael@0 2836 dump.append(INDENT4 "GestureMode: pointer\n");
michael@0 2837 break;
michael@0 2838 case Parameters::GESTURE_MODE_SPOTS:
michael@0 2839 dump.append(INDENT4 "GestureMode: spots\n");
michael@0 2840 break;
michael@0 2841 default:
michael@0 2842 assert(false);
michael@0 2843 }
michael@0 2844
michael@0 2845 switch (mParameters.deviceType) {
michael@0 2846 case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
michael@0 2847 dump.append(INDENT4 "DeviceType: touchScreen\n");
michael@0 2848 break;
michael@0 2849 case Parameters::DEVICE_TYPE_TOUCH_PAD:
michael@0 2850 dump.append(INDENT4 "DeviceType: touchPad\n");
michael@0 2851 break;
michael@0 2852 case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION:
michael@0 2853 dump.append(INDENT4 "DeviceType: touchNavigation\n");
michael@0 2854 break;
michael@0 2855 case Parameters::DEVICE_TYPE_POINTER:
michael@0 2856 dump.append(INDENT4 "DeviceType: pointer\n");
michael@0 2857 break;
michael@0 2858 default:
michael@0 2859 ALOG_ASSERT(false);
michael@0 2860 }
michael@0 2861
michael@0 2862 dump.appendFormat(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s\n",
michael@0 2863 toString(mParameters.hasAssociatedDisplay),
michael@0 2864 toString(mParameters.associatedDisplayIsExternal));
michael@0 2865 dump.appendFormat(INDENT4 "OrientationAware: %s\n",
michael@0 2866 toString(mParameters.orientationAware));
michael@0 2867 }
michael@0 2868
michael@0 2869 void TouchInputMapper::configureRawPointerAxes() {
michael@0 2870 mRawPointerAxes.clear();
michael@0 2871 }
michael@0 2872
michael@0 2873 void TouchInputMapper::dumpRawPointerAxes(String8& dump) {
michael@0 2874 dump.append(INDENT3 "Raw Touch Axes:\n");
michael@0 2875 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X");
michael@0 2876 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y");
michael@0 2877 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure");
michael@0 2878 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor");
michael@0 2879 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor");
michael@0 2880 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor");
michael@0 2881 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor");
michael@0 2882 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation");
michael@0 2883 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance");
michael@0 2884 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX");
michael@0 2885 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY");
michael@0 2886 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId");
michael@0 2887 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot");
michael@0 2888 }
michael@0 2889
michael@0 2890 void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
michael@0 2891 int32_t oldDeviceMode = mDeviceMode;
michael@0 2892
michael@0 2893 // Determine device mode.
michael@0 2894 if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
michael@0 2895 && mConfig.pointerGesturesEnabled) {
michael@0 2896 mSource = AINPUT_SOURCE_MOUSE;
michael@0 2897 mDeviceMode = DEVICE_MODE_POINTER;
michael@0 2898 if (hasStylus()) {
michael@0 2899 mSource |= AINPUT_SOURCE_STYLUS;
michael@0 2900 }
michael@0 2901 } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
michael@0 2902 && mParameters.hasAssociatedDisplay) {
michael@0 2903 mSource = AINPUT_SOURCE_TOUCHSCREEN;
michael@0 2904 mDeviceMode = DEVICE_MODE_DIRECT;
michael@0 2905 if (hasStylus()) {
michael@0 2906 mSource |= AINPUT_SOURCE_STYLUS;
michael@0 2907 }
michael@0 2908 } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
michael@0 2909 mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
michael@0 2910 mDeviceMode = DEVICE_MODE_NAVIGATION;
michael@0 2911 } else {
michael@0 2912 mSource = AINPUT_SOURCE_TOUCHPAD;
michael@0 2913 mDeviceMode = DEVICE_MODE_UNSCALED;
michael@0 2914 }
michael@0 2915
michael@0 2916 // Ensure we have valid X and Y axes.
michael@0 2917 if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
michael@0 2918 ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis! "
michael@0 2919 "The device will be inoperable.", getDeviceName().string());
michael@0 2920 mDeviceMode = DEVICE_MODE_DISABLED;
michael@0 2921 return;
michael@0 2922 }
michael@0 2923
michael@0 2924 // Raw width and height in the natural orientation.
michael@0 2925 int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
michael@0 2926 int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
michael@0 2927
michael@0 2928 // Get associated display dimensions.
michael@0 2929 bool viewportChanged = false;
michael@0 2930 DisplayViewport newViewport;
michael@0 2931 if (mParameters.hasAssociatedDisplay) {
michael@0 2932 if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal, &newViewport)) {
michael@0 2933 ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
michael@0 2934 "display. The device will be inoperable until the display size "
michael@0 2935 "becomes available.",
michael@0 2936 getDeviceName().string());
michael@0 2937 mDeviceMode = DEVICE_MODE_DISABLED;
michael@0 2938 return;
michael@0 2939 }
michael@0 2940 } else {
michael@0 2941 newViewport.setNonDisplayViewport(rawWidth, rawHeight);
michael@0 2942 }
michael@0 2943 if (mViewport != newViewport) {
michael@0 2944 mViewport = newViewport;
michael@0 2945 viewportChanged = true;
michael@0 2946
michael@0 2947 if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
michael@0 2948 // Convert rotated viewport to natural surface coordinates.
michael@0 2949 int32_t naturalLogicalWidth, naturalLogicalHeight;
michael@0 2950 int32_t naturalPhysicalWidth, naturalPhysicalHeight;
michael@0 2951 int32_t naturalPhysicalLeft, naturalPhysicalTop;
michael@0 2952 int32_t naturalDeviceWidth, naturalDeviceHeight;
michael@0 2953 switch (mViewport.orientation) {
michael@0 2954 case DISPLAY_ORIENTATION_90:
michael@0 2955 naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
michael@0 2956 naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
michael@0 2957 naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
michael@0 2958 naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
michael@0 2959 naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
michael@0 2960 naturalPhysicalTop = mViewport.physicalLeft;
michael@0 2961 naturalDeviceWidth = mViewport.deviceHeight;
michael@0 2962 naturalDeviceHeight = mViewport.deviceWidth;
michael@0 2963 break;
michael@0 2964 case DISPLAY_ORIENTATION_180:
michael@0 2965 naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
michael@0 2966 naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
michael@0 2967 naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
michael@0 2968 naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
michael@0 2969 naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight;
michael@0 2970 naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom;
michael@0 2971 naturalDeviceWidth = mViewport.deviceWidth;
michael@0 2972 naturalDeviceHeight = mViewport.deviceHeight;
michael@0 2973 break;
michael@0 2974 case DISPLAY_ORIENTATION_270:
michael@0 2975 naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
michael@0 2976 naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
michael@0 2977 naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
michael@0 2978 naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
michael@0 2979 naturalPhysicalLeft = mViewport.physicalTop;
michael@0 2980 naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight;
michael@0 2981 naturalDeviceWidth = mViewport.deviceHeight;
michael@0 2982 naturalDeviceHeight = mViewport.deviceWidth;
michael@0 2983 break;
michael@0 2984 case DISPLAY_ORIENTATION_0:
michael@0 2985 default:
michael@0 2986 naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
michael@0 2987 naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
michael@0 2988 naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
michael@0 2989 naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
michael@0 2990 naturalPhysicalLeft = mViewport.physicalLeft;
michael@0 2991 naturalPhysicalTop = mViewport.physicalTop;
michael@0 2992 naturalDeviceWidth = mViewport.deviceWidth;
michael@0 2993 naturalDeviceHeight = mViewport.deviceHeight;
michael@0 2994 break;
michael@0 2995 }
michael@0 2996
michael@0 2997 mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
michael@0 2998 mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
michael@0 2999 mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
michael@0 3000 mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
michael@0 3001
michael@0 3002 mSurfaceOrientation = mParameters.orientationAware ?
michael@0 3003 mViewport.orientation : DISPLAY_ORIENTATION_0;
michael@0 3004 } else {
michael@0 3005 mSurfaceWidth = rawWidth;
michael@0 3006 mSurfaceHeight = rawHeight;
michael@0 3007 mSurfaceLeft = 0;
michael@0 3008 mSurfaceTop = 0;
michael@0 3009 mSurfaceOrientation = DISPLAY_ORIENTATION_0;
michael@0 3010 }
michael@0 3011 }
michael@0 3012
michael@0 3013 // If moving between pointer modes, need to reset some state.
michael@0 3014 bool deviceModeChanged;
michael@0 3015 if (mDeviceMode != oldDeviceMode) {
michael@0 3016 deviceModeChanged = true;
michael@0 3017 mOrientedRanges.clear();
michael@0 3018 }
michael@0 3019
michael@0 3020 // Create pointer controller if needed.
michael@0 3021 if (mDeviceMode == DEVICE_MODE_POINTER ||
michael@0 3022 (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
michael@0 3023 if (mPointerController == NULL) {
michael@0 3024 mPointerController = getPolicy()->obtainPointerController(getDeviceId());
michael@0 3025 }
michael@0 3026 } else {
michael@0 3027 mPointerController.clear();
michael@0 3028 }
michael@0 3029
michael@0 3030 if (viewportChanged || deviceModeChanged) {
michael@0 3031 ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
michael@0 3032 "display id %d",
michael@0 3033 getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight,
michael@0 3034 mSurfaceOrientation, mDeviceMode, mViewport.displayId);
michael@0 3035
michael@0 3036 // Configure X and Y factors.
michael@0 3037 mXScale = float(mSurfaceWidth) / rawWidth;
michael@0 3038 mYScale = float(mSurfaceHeight) / rawHeight;
michael@0 3039 mXTranslate = -mSurfaceLeft;
michael@0 3040 mYTranslate = -mSurfaceTop;
michael@0 3041 mXPrecision = 1.0f / mXScale;
michael@0 3042 mYPrecision = 1.0f / mYScale;
michael@0 3043
michael@0 3044 mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
michael@0 3045 mOrientedRanges.x.source = mSource;
michael@0 3046 mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
michael@0 3047 mOrientedRanges.y.source = mSource;
michael@0 3048
michael@0 3049 configureVirtualKeys();
michael@0 3050
michael@0 3051 // Scale factor for terms that are not oriented in a particular axis.
michael@0 3052 // If the pixels are square then xScale == yScale otherwise we fake it
michael@0 3053 // by choosing an average.
michael@0 3054 mGeometricScale = avg(mXScale, mYScale);
michael@0 3055
michael@0 3056 // Size of diagonal axis.
michael@0 3057 float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight);
michael@0 3058
michael@0 3059 // Size factors.
michael@0 3060 if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
michael@0 3061 if (mRawPointerAxes.touchMajor.valid
michael@0 3062 && mRawPointerAxes.touchMajor.maxValue != 0) {
michael@0 3063 mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
michael@0 3064 } else if (mRawPointerAxes.toolMajor.valid
michael@0 3065 && mRawPointerAxes.toolMajor.maxValue != 0) {
michael@0 3066 mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue;
michael@0 3067 } else {
michael@0 3068 mSizeScale = 0.0f;
michael@0 3069 }
michael@0 3070
michael@0 3071 mOrientedRanges.haveTouchSize = true;
michael@0 3072 mOrientedRanges.haveToolSize = true;
michael@0 3073 mOrientedRanges.haveSize = true;
michael@0 3074
michael@0 3075 mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
michael@0 3076 mOrientedRanges.touchMajor.source = mSource;
michael@0 3077 mOrientedRanges.touchMajor.min = 0;
michael@0 3078 mOrientedRanges.touchMajor.max = diagonalSize;
michael@0 3079 mOrientedRanges.touchMajor.flat = 0;
michael@0 3080 mOrientedRanges.touchMajor.fuzz = 0;
michael@0 3081 mOrientedRanges.touchMajor.resolution = 0;
michael@0 3082
michael@0 3083 mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
michael@0 3084 mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
michael@0 3085
michael@0 3086 mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
michael@0 3087 mOrientedRanges.toolMajor.source = mSource;
michael@0 3088 mOrientedRanges.toolMajor.min = 0;
michael@0 3089 mOrientedRanges.toolMajor.max = diagonalSize;
michael@0 3090 mOrientedRanges.toolMajor.flat = 0;
michael@0 3091 mOrientedRanges.toolMajor.fuzz = 0;
michael@0 3092 mOrientedRanges.toolMajor.resolution = 0;
michael@0 3093
michael@0 3094 mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
michael@0 3095 mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
michael@0 3096
michael@0 3097 mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
michael@0 3098 mOrientedRanges.size.source = mSource;
michael@0 3099 mOrientedRanges.size.min = 0;
michael@0 3100 mOrientedRanges.size.max = 1.0;
michael@0 3101 mOrientedRanges.size.flat = 0;
michael@0 3102 mOrientedRanges.size.fuzz = 0;
michael@0 3103 mOrientedRanges.size.resolution = 0;
michael@0 3104 } else {
michael@0 3105 mSizeScale = 0.0f;
michael@0 3106 }
michael@0 3107
michael@0 3108 // Pressure factors.
michael@0 3109 mPressureScale = 0;
michael@0 3110 if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL
michael@0 3111 || mCalibration.pressureCalibration
michael@0 3112 == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
michael@0 3113 if (mCalibration.havePressureScale) {
michael@0 3114 mPressureScale = mCalibration.pressureScale;
michael@0 3115 } else if (mRawPointerAxes.pressure.valid
michael@0 3116 && mRawPointerAxes.pressure.maxValue != 0) {
michael@0 3117 mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
michael@0 3118 }
michael@0 3119 }
michael@0 3120
michael@0 3121 mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
michael@0 3122 mOrientedRanges.pressure.source = mSource;
michael@0 3123 mOrientedRanges.pressure.min = 0;
michael@0 3124 mOrientedRanges.pressure.max = 1.0;
michael@0 3125 mOrientedRanges.pressure.flat = 0;
michael@0 3126 mOrientedRanges.pressure.fuzz = 0;
michael@0 3127 mOrientedRanges.pressure.resolution = 0;
michael@0 3128
michael@0 3129 // Tilt
michael@0 3130 mTiltXCenter = 0;
michael@0 3131 mTiltXScale = 0;
michael@0 3132 mTiltYCenter = 0;
michael@0 3133 mTiltYScale = 0;
michael@0 3134 mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid;
michael@0 3135 if (mHaveTilt) {
michael@0 3136 mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue,
michael@0 3137 mRawPointerAxes.tiltX.maxValue);
michael@0 3138 mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue,
michael@0 3139 mRawPointerAxes.tiltY.maxValue);
michael@0 3140 mTiltXScale = M_PI / 180;
michael@0 3141 mTiltYScale = M_PI / 180;
michael@0 3142
michael@0 3143 mOrientedRanges.haveTilt = true;
michael@0 3144
michael@0 3145 mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
michael@0 3146 mOrientedRanges.tilt.source = mSource;
michael@0 3147 mOrientedRanges.tilt.min = 0;
michael@0 3148 mOrientedRanges.tilt.max = M_PI_2;
michael@0 3149 mOrientedRanges.tilt.flat = 0;
michael@0 3150 mOrientedRanges.tilt.fuzz = 0;
michael@0 3151 mOrientedRanges.tilt.resolution = 0;
michael@0 3152 }
michael@0 3153
michael@0 3154 // Orientation
michael@0 3155 mOrientationScale = 0;
michael@0 3156 if (mHaveTilt) {
michael@0 3157 mOrientedRanges.haveOrientation = true;
michael@0 3158
michael@0 3159 mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
michael@0 3160 mOrientedRanges.orientation.source = mSource;
michael@0 3161 mOrientedRanges.orientation.min = -M_PI;
michael@0 3162 mOrientedRanges.orientation.max = M_PI;
michael@0 3163 mOrientedRanges.orientation.flat = 0;
michael@0 3164 mOrientedRanges.orientation.fuzz = 0;
michael@0 3165 mOrientedRanges.orientation.resolution = 0;
michael@0 3166 } else if (mCalibration.orientationCalibration !=
michael@0 3167 Calibration::ORIENTATION_CALIBRATION_NONE) {
michael@0 3168 if (mCalibration.orientationCalibration
michael@0 3169 == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) {
michael@0 3170 if (mRawPointerAxes.orientation.valid) {
michael@0 3171 if (mRawPointerAxes.orientation.maxValue > 0) {
michael@0 3172 mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
michael@0 3173 } else if (mRawPointerAxes.orientation.minValue < 0) {
michael@0 3174 mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue;
michael@0 3175 } else {
michael@0 3176 mOrientationScale = 0;
michael@0 3177 }
michael@0 3178 }
michael@0 3179 }
michael@0 3180
michael@0 3181 mOrientedRanges.haveOrientation = true;
michael@0 3182
michael@0 3183 mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
michael@0 3184 mOrientedRanges.orientation.source = mSource;
michael@0 3185 mOrientedRanges.orientation.min = -M_PI_2;
michael@0 3186 mOrientedRanges.orientation.max = M_PI_2;
michael@0 3187 mOrientedRanges.orientation.flat = 0;
michael@0 3188 mOrientedRanges.orientation.fuzz = 0;
michael@0 3189 mOrientedRanges.orientation.resolution = 0;
michael@0 3190 }
michael@0 3191
michael@0 3192 // Distance
michael@0 3193 mDistanceScale = 0;
michael@0 3194 if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) {
michael@0 3195 if (mCalibration.distanceCalibration
michael@0 3196 == Calibration::DISTANCE_CALIBRATION_SCALED) {
michael@0 3197 if (mCalibration.haveDistanceScale) {
michael@0 3198 mDistanceScale = mCalibration.distanceScale;
michael@0 3199 } else {
michael@0 3200 mDistanceScale = 1.0f;
michael@0 3201 }
michael@0 3202 }
michael@0 3203
michael@0 3204 mOrientedRanges.haveDistance = true;
michael@0 3205
michael@0 3206 mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE;
michael@0 3207 mOrientedRanges.distance.source = mSource;
michael@0 3208 mOrientedRanges.distance.min =
michael@0 3209 mRawPointerAxes.distance.minValue * mDistanceScale;
michael@0 3210 mOrientedRanges.distance.max =
michael@0 3211 mRawPointerAxes.distance.maxValue * mDistanceScale;
michael@0 3212 mOrientedRanges.distance.flat = 0;
michael@0 3213 mOrientedRanges.distance.fuzz =
michael@0 3214 mRawPointerAxes.distance.fuzz * mDistanceScale;
michael@0 3215 mOrientedRanges.distance.resolution = 0;
michael@0 3216 }
michael@0 3217
michael@0 3218 // Compute oriented precision, scales and ranges.
michael@0 3219 // Note that the maximum value reported is an inclusive maximum value so it is one
michael@0 3220 // unit less than the total width or height of surface.
michael@0 3221 switch (mSurfaceOrientation) {
michael@0 3222 case DISPLAY_ORIENTATION_90:
michael@0 3223 case DISPLAY_ORIENTATION_270:
michael@0 3224 mOrientedXPrecision = mYPrecision;
michael@0 3225 mOrientedYPrecision = mXPrecision;
michael@0 3226
michael@0 3227 mOrientedRanges.x.min = mYTranslate;
michael@0 3228 mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1;
michael@0 3229 mOrientedRanges.x.flat = 0;
michael@0 3230 mOrientedRanges.x.fuzz = 0;
michael@0 3231 mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
michael@0 3232
michael@0 3233 mOrientedRanges.y.min = mXTranslate;
michael@0 3234 mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1;
michael@0 3235 mOrientedRanges.y.flat = 0;
michael@0 3236 mOrientedRanges.y.fuzz = 0;
michael@0 3237 mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
michael@0 3238 break;
michael@0 3239
michael@0 3240 default:
michael@0 3241 mOrientedXPrecision = mXPrecision;
michael@0 3242 mOrientedYPrecision = mYPrecision;
michael@0 3243
michael@0 3244 mOrientedRanges.x.min = mXTranslate;
michael@0 3245 mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1;
michael@0 3246 mOrientedRanges.x.flat = 0;
michael@0 3247 mOrientedRanges.x.fuzz = 0;
michael@0 3248 mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
michael@0 3249
michael@0 3250 mOrientedRanges.y.min = mYTranslate;
michael@0 3251 mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1;
michael@0 3252 mOrientedRanges.y.flat = 0;
michael@0 3253 mOrientedRanges.y.fuzz = 0;
michael@0 3254 mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
michael@0 3255 break;
michael@0 3256 }
michael@0 3257
michael@0 3258 if (mDeviceMode == DEVICE_MODE_POINTER) {
michael@0 3259 // Compute pointer gesture detection parameters.
michael@0 3260 float rawDiagonal = hypotf(rawWidth, rawHeight);
michael@0 3261 float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight);
michael@0 3262
michael@0 3263 // Scale movements such that one whole swipe of the touch pad covers a
michael@0 3264 // given area relative to the diagonal size of the display when no acceleration
michael@0 3265 // is applied.
michael@0 3266 // Assume that the touch pad has a square aspect ratio such that movements in
michael@0 3267 // X and Y of the same number of raw units cover the same physical distance.
michael@0 3268 mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio
michael@0 3269 * displayDiagonal / rawDiagonal;
michael@0 3270 mPointerYMovementScale = mPointerXMovementScale;
michael@0 3271
michael@0 3272 // Scale zooms to cover a smaller range of the display than movements do.
michael@0 3273 // This value determines the area around the pointer that is affected by freeform
michael@0 3274 // pointer gestures.
michael@0 3275 mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio
michael@0 3276 * displayDiagonal / rawDiagonal;
michael@0 3277 mPointerYZoomScale = mPointerXZoomScale;
michael@0 3278
michael@0 3279 // Max width between pointers to detect a swipe gesture is more than some fraction
michael@0 3280 // of the diagonal axis of the touch pad. Touches that are wider than this are
michael@0 3281 // translated into freeform gestures.
michael@0 3282 mPointerGestureMaxSwipeWidth =
michael@0 3283 mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal;
michael@0 3284
michael@0 3285 // Abort current pointer usages because the state has changed.
michael@0 3286 abortPointerUsage(when, 0 /*policyFlags*/);
michael@0 3287 }
michael@0 3288
michael@0 3289 // Inform the dispatcher about the changes.
michael@0 3290 *outResetNeeded = true;
michael@0 3291 bumpGeneration();
michael@0 3292 }
michael@0 3293 }
michael@0 3294
michael@0 3295 void TouchInputMapper::dumpSurface(String8& dump) {
michael@0 3296 dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, "
michael@0 3297 "logicalFrame=[%d, %d, %d, %d], "
michael@0 3298 "physicalFrame=[%d, %d, %d, %d], "
michael@0 3299 "deviceSize=[%d, %d]\n",
michael@0 3300 mViewport.displayId, mViewport.orientation,
michael@0 3301 mViewport.logicalLeft, mViewport.logicalTop,
michael@0 3302 mViewport.logicalRight, mViewport.logicalBottom,
michael@0 3303 mViewport.physicalLeft, mViewport.physicalTop,
michael@0 3304 mViewport.physicalRight, mViewport.physicalBottom,
michael@0 3305 mViewport.deviceWidth, mViewport.deviceHeight);
michael@0 3306
michael@0 3307 dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
michael@0 3308 dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
michael@0 3309 dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
michael@0 3310 dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
michael@0 3311 dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
michael@0 3312 }
michael@0 3313
michael@0 3314 void TouchInputMapper::configureVirtualKeys() {
michael@0 3315 Vector<VirtualKeyDefinition> virtualKeyDefinitions;
michael@0 3316 getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
michael@0 3317
michael@0 3318 mVirtualKeys.clear();
michael@0 3319
michael@0 3320 if (virtualKeyDefinitions.size() == 0) {
michael@0 3321 return;
michael@0 3322 }
michael@0 3323
michael@0 3324 mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
michael@0 3325
michael@0 3326 int32_t touchScreenLeft = mRawPointerAxes.x.minValue;
michael@0 3327 int32_t touchScreenTop = mRawPointerAxes.y.minValue;
michael@0 3328 int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
michael@0 3329 int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
michael@0 3330
michael@0 3331 for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
michael@0 3332 const VirtualKeyDefinition& virtualKeyDefinition =
michael@0 3333 virtualKeyDefinitions[i];
michael@0 3334
michael@0 3335 mVirtualKeys.add();
michael@0 3336 VirtualKey& virtualKey = mVirtualKeys.editTop();
michael@0 3337
michael@0 3338 virtualKey.scanCode = virtualKeyDefinition.scanCode;
michael@0 3339 int32_t keyCode;
michael@0 3340 uint32_t flags;
michael@0 3341 if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, &keyCode, &flags)) {
michael@0 3342 ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
michael@0 3343 virtualKey.scanCode);
michael@0 3344 mVirtualKeys.pop(); // drop the key
michael@0 3345 continue;
michael@0 3346 }
michael@0 3347
michael@0 3348 virtualKey.keyCode = keyCode;
michael@0 3349 virtualKey.flags = flags;
michael@0 3350
michael@0 3351 // convert the key definition's display coordinates into touch coordinates for a hit box
michael@0 3352 int32_t halfWidth = virtualKeyDefinition.width / 2;
michael@0 3353 int32_t halfHeight = virtualKeyDefinition.height / 2;
michael@0 3354
michael@0 3355 virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
michael@0 3356 * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
michael@0 3357 virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
michael@0 3358 * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
michael@0 3359 virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
michael@0 3360 * touchScreenHeight / mSurfaceHeight + touchScreenTop;
michael@0 3361 virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
michael@0 3362 * touchScreenHeight / mSurfaceHeight + touchScreenTop;
michael@0 3363 }
michael@0 3364 }
michael@0 3365
michael@0 3366 void TouchInputMapper::dumpVirtualKeys(String8& dump) {
michael@0 3367 if (!mVirtualKeys.isEmpty()) {
michael@0 3368 dump.append(INDENT3 "Virtual Keys:\n");
michael@0 3369
michael@0 3370 for (size_t i = 0; i < mVirtualKeys.size(); i++) {
michael@0 3371 const VirtualKey& virtualKey = mVirtualKeys.itemAt(i);
michael@0 3372 dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, "
michael@0 3373 "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
michael@0 3374 i, virtualKey.scanCode, virtualKey.keyCode,
michael@0 3375 virtualKey.hitLeft, virtualKey.hitRight,
michael@0 3376 virtualKey.hitTop, virtualKey.hitBottom);
michael@0 3377 }
michael@0 3378 }
michael@0 3379 }
michael@0 3380
michael@0 3381 void TouchInputMapper::parseCalibration() {
michael@0 3382 const PropertyMap& in = getDevice()->getConfiguration();
michael@0 3383 Calibration& out = mCalibration;
michael@0 3384
michael@0 3385 // Size
michael@0 3386 out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT;
michael@0 3387 String8 sizeCalibrationString;
michael@0 3388 if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) {
michael@0 3389 if (sizeCalibrationString == "none") {
michael@0 3390 out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
michael@0 3391 } else if (sizeCalibrationString == "geometric") {
michael@0 3392 out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
michael@0 3393 } else if (sizeCalibrationString == "diameter") {
michael@0 3394 out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER;
michael@0 3395 } else if (sizeCalibrationString == "box") {
michael@0 3396 out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX;
michael@0 3397 } else if (sizeCalibrationString == "area") {
michael@0 3398 out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA;
michael@0 3399 } else if (sizeCalibrationString != "default") {
michael@0 3400 ALOGW("Invalid value for touch.size.calibration: '%s'",
michael@0 3401 sizeCalibrationString.string());
michael@0 3402 }
michael@0 3403 }
michael@0 3404
michael@0 3405 out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"),
michael@0 3406 out.sizeScale);
michael@0 3407 out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"),
michael@0 3408 out.sizeBias);
michael@0 3409 out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"),
michael@0 3410 out.sizeIsSummed);
michael@0 3411
michael@0 3412 // Pressure
michael@0 3413 out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT;
michael@0 3414 String8 pressureCalibrationString;
michael@0 3415 if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) {
michael@0 3416 if (pressureCalibrationString == "none") {
michael@0 3417 out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
michael@0 3418 } else if (pressureCalibrationString == "physical") {
michael@0 3419 out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
michael@0 3420 } else if (pressureCalibrationString == "amplitude") {
michael@0 3421 out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE;
michael@0 3422 } else if (pressureCalibrationString != "default") {
michael@0 3423 ALOGW("Invalid value for touch.pressure.calibration: '%s'",
michael@0 3424 pressureCalibrationString.string());
michael@0 3425 }
michael@0 3426 }
michael@0 3427
michael@0 3428 out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"),
michael@0 3429 out.pressureScale);
michael@0 3430
michael@0 3431 // Orientation
michael@0 3432 out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT;
michael@0 3433 String8 orientationCalibrationString;
michael@0 3434 if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) {
michael@0 3435 if (orientationCalibrationString == "none") {
michael@0 3436 out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
michael@0 3437 } else if (orientationCalibrationString == "interpolated") {
michael@0 3438 out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
michael@0 3439 } else if (orientationCalibrationString == "vector") {
michael@0 3440 out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR;
michael@0 3441 } else if (orientationCalibrationString != "default") {
michael@0 3442 ALOGW("Invalid value for touch.orientation.calibration: '%s'",
michael@0 3443 orientationCalibrationString.string());
michael@0 3444 }
michael@0 3445 }
michael@0 3446
michael@0 3447 // Distance
michael@0 3448 out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT;
michael@0 3449 String8 distanceCalibrationString;
michael@0 3450 if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) {
michael@0 3451 if (distanceCalibrationString == "none") {
michael@0 3452 out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
michael@0 3453 } else if (distanceCalibrationString == "scaled") {
michael@0 3454 out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
michael@0 3455 } else if (distanceCalibrationString != "default") {
michael@0 3456 ALOGW("Invalid value for touch.distance.calibration: '%s'",
michael@0 3457 distanceCalibrationString.string());
michael@0 3458 }
michael@0 3459 }
michael@0 3460
michael@0 3461 out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"),
michael@0 3462 out.distanceScale);
michael@0 3463
michael@0 3464 out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT;
michael@0 3465 String8 coverageCalibrationString;
michael@0 3466 if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) {
michael@0 3467 if (coverageCalibrationString == "none") {
michael@0 3468 out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
michael@0 3469 } else if (coverageCalibrationString == "box") {
michael@0 3470 out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX;
michael@0 3471 } else if (coverageCalibrationString != "default") {
michael@0 3472 ALOGW("Invalid value for touch.coverage.calibration: '%s'",
michael@0 3473 coverageCalibrationString.string());
michael@0 3474 }
michael@0 3475 }
michael@0 3476 }
michael@0 3477
michael@0 3478 void TouchInputMapper::resolveCalibration() {
michael@0 3479 // Size
michael@0 3480 if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) {
michael@0 3481 if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) {
michael@0 3482 mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
michael@0 3483 }
michael@0 3484 } else {
michael@0 3485 mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
michael@0 3486 }
michael@0 3487
michael@0 3488 // Pressure
michael@0 3489 if (mRawPointerAxes.pressure.valid) {
michael@0 3490 if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) {
michael@0 3491 mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
michael@0 3492 }
michael@0 3493 } else {
michael@0 3494 mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
michael@0 3495 }
michael@0 3496
michael@0 3497 // Orientation
michael@0 3498 if (mRawPointerAxes.orientation.valid) {
michael@0 3499 if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) {
michael@0 3500 mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
michael@0 3501 }
michael@0 3502 } else {
michael@0 3503 mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
michael@0 3504 }
michael@0 3505
michael@0 3506 // Distance
michael@0 3507 if (mRawPointerAxes.distance.valid) {
michael@0 3508 if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) {
michael@0 3509 mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
michael@0 3510 }
michael@0 3511 } else {
michael@0 3512 mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
michael@0 3513 }
michael@0 3514
michael@0 3515 // Coverage
michael@0 3516 if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) {
michael@0 3517 mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
michael@0 3518 }
michael@0 3519 }
michael@0 3520
michael@0 3521 void TouchInputMapper::dumpCalibration(String8& dump) {
michael@0 3522 dump.append(INDENT3 "Calibration:\n");
michael@0 3523
michael@0 3524 // Size
michael@0 3525 switch (mCalibration.sizeCalibration) {
michael@0 3526 case Calibration::SIZE_CALIBRATION_NONE:
michael@0 3527 dump.append(INDENT4 "touch.size.calibration: none\n");
michael@0 3528 break;
michael@0 3529 case Calibration::SIZE_CALIBRATION_GEOMETRIC:
michael@0 3530 dump.append(INDENT4 "touch.size.calibration: geometric\n");
michael@0 3531 break;
michael@0 3532 case Calibration::SIZE_CALIBRATION_DIAMETER:
michael@0 3533 dump.append(INDENT4 "touch.size.calibration: diameter\n");
michael@0 3534 break;
michael@0 3535 case Calibration::SIZE_CALIBRATION_BOX:
michael@0 3536 dump.append(INDENT4 "touch.size.calibration: box\n");
michael@0 3537 break;
michael@0 3538 case Calibration::SIZE_CALIBRATION_AREA:
michael@0 3539 dump.append(INDENT4 "touch.size.calibration: area\n");
michael@0 3540 break;
michael@0 3541 default:
michael@0 3542 ALOG_ASSERT(false);
michael@0 3543 }
michael@0 3544
michael@0 3545 if (mCalibration.haveSizeScale) {
michael@0 3546 dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n",
michael@0 3547 mCalibration.sizeScale);
michael@0 3548 }
michael@0 3549
michael@0 3550 if (mCalibration.haveSizeBias) {
michael@0 3551 dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n",
michael@0 3552 mCalibration.sizeBias);
michael@0 3553 }
michael@0 3554
michael@0 3555 if (mCalibration.haveSizeIsSummed) {
michael@0 3556 dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n",
michael@0 3557 toString(mCalibration.sizeIsSummed));
michael@0 3558 }
michael@0 3559
michael@0 3560 // Pressure
michael@0 3561 switch (mCalibration.pressureCalibration) {
michael@0 3562 case Calibration::PRESSURE_CALIBRATION_NONE:
michael@0 3563 dump.append(INDENT4 "touch.pressure.calibration: none\n");
michael@0 3564 break;
michael@0 3565 case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
michael@0 3566 dump.append(INDENT4 "touch.pressure.calibration: physical\n");
michael@0 3567 break;
michael@0 3568 case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
michael@0 3569 dump.append(INDENT4 "touch.pressure.calibration: amplitude\n");
michael@0 3570 break;
michael@0 3571 default:
michael@0 3572 ALOG_ASSERT(false);
michael@0 3573 }
michael@0 3574
michael@0 3575 if (mCalibration.havePressureScale) {
michael@0 3576 dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n",
michael@0 3577 mCalibration.pressureScale);
michael@0 3578 }
michael@0 3579
michael@0 3580 // Orientation
michael@0 3581 switch (mCalibration.orientationCalibration) {
michael@0 3582 case Calibration::ORIENTATION_CALIBRATION_NONE:
michael@0 3583 dump.append(INDENT4 "touch.orientation.calibration: none\n");
michael@0 3584 break;
michael@0 3585 case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
michael@0 3586 dump.append(INDENT4 "touch.orientation.calibration: interpolated\n");
michael@0 3587 break;
michael@0 3588 case Calibration::ORIENTATION_CALIBRATION_VECTOR:
michael@0 3589 dump.append(INDENT4 "touch.orientation.calibration: vector\n");
michael@0 3590 break;
michael@0 3591 default:
michael@0 3592 ALOG_ASSERT(false);
michael@0 3593 }
michael@0 3594
michael@0 3595 // Distance
michael@0 3596 switch (mCalibration.distanceCalibration) {
michael@0 3597 case Calibration::DISTANCE_CALIBRATION_NONE:
michael@0 3598 dump.append(INDENT4 "touch.distance.calibration: none\n");
michael@0 3599 break;
michael@0 3600 case Calibration::DISTANCE_CALIBRATION_SCALED:
michael@0 3601 dump.append(INDENT4 "touch.distance.calibration: scaled\n");
michael@0 3602 break;
michael@0 3603 default:
michael@0 3604 ALOG_ASSERT(false);
michael@0 3605 }
michael@0 3606
michael@0 3607 if (mCalibration.haveDistanceScale) {
michael@0 3608 dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n",
michael@0 3609 mCalibration.distanceScale);
michael@0 3610 }
michael@0 3611
michael@0 3612 switch (mCalibration.coverageCalibration) {
michael@0 3613 case Calibration::COVERAGE_CALIBRATION_NONE:
michael@0 3614 dump.append(INDENT4 "touch.coverage.calibration: none\n");
michael@0 3615 break;
michael@0 3616 case Calibration::COVERAGE_CALIBRATION_BOX:
michael@0 3617 dump.append(INDENT4 "touch.coverage.calibration: box\n");
michael@0 3618 break;
michael@0 3619 default:
michael@0 3620 ALOG_ASSERT(false);
michael@0 3621 }
michael@0 3622 }
michael@0 3623
michael@0 3624 void TouchInputMapper::reset(nsecs_t when) {
michael@0 3625 mCursorButtonAccumulator.reset(getDevice());
michael@0 3626 mCursorScrollAccumulator.reset(getDevice());
michael@0 3627 mTouchButtonAccumulator.reset(getDevice());
michael@0 3628
michael@0 3629 mPointerVelocityControl.reset();
michael@0 3630 mWheelXVelocityControl.reset();
michael@0 3631 mWheelYVelocityControl.reset();
michael@0 3632
michael@0 3633 mCurrentRawPointerData.clear();
michael@0 3634 mLastRawPointerData.clear();
michael@0 3635 mCurrentCookedPointerData.clear();
michael@0 3636 mLastCookedPointerData.clear();
michael@0 3637 mCurrentButtonState = 0;
michael@0 3638 mLastButtonState = 0;
michael@0 3639 mCurrentRawVScroll = 0;
michael@0 3640 mCurrentRawHScroll = 0;
michael@0 3641 mCurrentFingerIdBits.clear();
michael@0 3642 mLastFingerIdBits.clear();
michael@0 3643 mCurrentStylusIdBits.clear();
michael@0 3644 mLastStylusIdBits.clear();
michael@0 3645 mCurrentMouseIdBits.clear();
michael@0 3646 mLastMouseIdBits.clear();
michael@0 3647 mPointerUsage = POINTER_USAGE_NONE;
michael@0 3648 mSentHoverEnter = false;
michael@0 3649 mDownTime = 0;
michael@0 3650
michael@0 3651 mCurrentVirtualKey.down = false;
michael@0 3652
michael@0 3653 mPointerGesture.reset();
michael@0 3654 mPointerSimple.reset();
michael@0 3655
michael@0 3656 if (mPointerController != NULL) {
michael@0 3657 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
michael@0 3658 mPointerController->clearSpots();
michael@0 3659 }
michael@0 3660
michael@0 3661 InputMapper::reset(when);
michael@0 3662 }
michael@0 3663
michael@0 3664 void TouchInputMapper::process(const RawEvent* rawEvent) {
michael@0 3665 mCursorButtonAccumulator.process(rawEvent);
michael@0 3666 mCursorScrollAccumulator.process(rawEvent);
michael@0 3667 mTouchButtonAccumulator.process(rawEvent);
michael@0 3668
michael@0 3669 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
michael@0 3670 sync(rawEvent->when);
michael@0 3671 }
michael@0 3672 }
michael@0 3673
michael@0 3674 void TouchInputMapper::sync(nsecs_t when) {
michael@0 3675 // Sync button state.
michael@0 3676 mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
michael@0 3677 | mCursorButtonAccumulator.getButtonState();
michael@0 3678
michael@0 3679 // Sync scroll state.
michael@0 3680 mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
michael@0 3681 mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
michael@0 3682 mCursorScrollAccumulator.finishSync();
michael@0 3683
michael@0 3684 // Sync touch state.
michael@0 3685 bool havePointerIds = true;
michael@0 3686 mCurrentRawPointerData.clear();
michael@0 3687 syncTouch(when, &havePointerIds);
michael@0 3688
michael@0 3689 #if DEBUG_RAW_EVENTS
michael@0 3690 if (!havePointerIds) {
michael@0 3691 ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids",
michael@0 3692 mLastRawPointerData.pointerCount,
michael@0 3693 mCurrentRawPointerData.pointerCount);
michael@0 3694 } else {
michael@0 3695 ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
michael@0 3696 "hovering ids 0x%08x -> 0x%08x",
michael@0 3697 mLastRawPointerData.pointerCount,
michael@0 3698 mCurrentRawPointerData.pointerCount,
michael@0 3699 mLastRawPointerData.touchingIdBits.value,
michael@0 3700 mCurrentRawPointerData.touchingIdBits.value,
michael@0 3701 mLastRawPointerData.hoveringIdBits.value,
michael@0 3702 mCurrentRawPointerData.hoveringIdBits.value);
michael@0 3703 }
michael@0 3704 #endif
michael@0 3705
michael@0 3706 // Reset state that we will compute below.
michael@0 3707 mCurrentFingerIdBits.clear();
michael@0 3708 mCurrentStylusIdBits.clear();
michael@0 3709 mCurrentMouseIdBits.clear();
michael@0 3710 mCurrentCookedPointerData.clear();
michael@0 3711
michael@0 3712 if (mDeviceMode == DEVICE_MODE_DISABLED) {
michael@0 3713 // Drop all input if the device is disabled.
michael@0 3714 mCurrentRawPointerData.clear();
michael@0 3715 mCurrentButtonState = 0;
michael@0 3716 } else {
michael@0 3717 // Preprocess pointer data.
michael@0 3718 if (!havePointerIds) {
michael@0 3719 assignPointerIds();
michael@0 3720 }
michael@0 3721
michael@0 3722 // Handle policy on initial down or hover events.
michael@0 3723 uint32_t policyFlags = 0;
michael@0 3724 bool initialDown = mLastRawPointerData.pointerCount == 0
michael@0 3725 && mCurrentRawPointerData.pointerCount != 0;
michael@0 3726 bool buttonsPressed = mCurrentButtonState & ~mLastButtonState;
michael@0 3727 if (initialDown || buttonsPressed) {
michael@0 3728 // If this is a touch screen, hide the pointer on an initial down.
michael@0 3729 if (mDeviceMode == DEVICE_MODE_DIRECT) {
michael@0 3730 getContext()->fadePointer();
michael@0 3731 }
michael@0 3732
michael@0 3733 // Initial downs on external touch devices should wake the device.
michael@0 3734 // We don't do this for internal touch screens to prevent them from waking
michael@0 3735 // up in your pocket.
michael@0 3736 // TODO: Use the input device configuration to control this behavior more finely.
michael@0 3737 if (getDevice()->isExternal()) {
michael@0 3738 policyFlags |= POLICY_FLAG_WAKE_DROPPED;
michael@0 3739 }
michael@0 3740 }
michael@0 3741
michael@0 3742 // Synthesize key down from raw buttons if needed.
michael@0 3743 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
michael@0 3744 policyFlags, mLastButtonState, mCurrentButtonState);
michael@0 3745
michael@0 3746 // Consume raw off-screen touches before cooking pointer data.
michael@0 3747 // If touches are consumed, subsequent code will not receive any pointer data.
michael@0 3748 if (consumeRawTouches(when, policyFlags)) {
michael@0 3749 mCurrentRawPointerData.clear();
michael@0 3750 }
michael@0 3751
michael@0 3752 // Cook pointer data. This call populates the mCurrentCookedPointerData structure
michael@0 3753 // with cooked pointer data that has the same ids and indices as the raw data.
michael@0 3754 // The following code can use either the raw or cooked data, as needed.
michael@0 3755 cookPointerData();
michael@0 3756
michael@0 3757 // Dispatch the touches either directly or by translation through a pointer on screen.
michael@0 3758 if (mDeviceMode == DEVICE_MODE_POINTER) {
michael@0 3759 for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
michael@0 3760 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 3761 const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
michael@0 3762 if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
michael@0 3763 || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
michael@0 3764 mCurrentStylusIdBits.markBit(id);
michael@0 3765 } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
michael@0 3766 || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
michael@0 3767 mCurrentFingerIdBits.markBit(id);
michael@0 3768 } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
michael@0 3769 mCurrentMouseIdBits.markBit(id);
michael@0 3770 }
michael@0 3771 }
michael@0 3772 for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) {
michael@0 3773 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 3774 const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
michael@0 3775 if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
michael@0 3776 || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
michael@0 3777 mCurrentStylusIdBits.markBit(id);
michael@0 3778 }
michael@0 3779 }
michael@0 3780
michael@0 3781 // Stylus takes precedence over all tools, then mouse, then finger.
michael@0 3782 PointerUsage pointerUsage = mPointerUsage;
michael@0 3783 if (!mCurrentStylusIdBits.isEmpty()) {
michael@0 3784 mCurrentMouseIdBits.clear();
michael@0 3785 mCurrentFingerIdBits.clear();
michael@0 3786 pointerUsage = POINTER_USAGE_STYLUS;
michael@0 3787 } else if (!mCurrentMouseIdBits.isEmpty()) {
michael@0 3788 mCurrentFingerIdBits.clear();
michael@0 3789 pointerUsage = POINTER_USAGE_MOUSE;
michael@0 3790 } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) {
michael@0 3791 pointerUsage = POINTER_USAGE_GESTURES;
michael@0 3792 }
michael@0 3793
michael@0 3794 dispatchPointerUsage(when, policyFlags, pointerUsage);
michael@0 3795 } else {
michael@0 3796 if (mDeviceMode == DEVICE_MODE_DIRECT
michael@0 3797 && mConfig.showTouches && mPointerController != NULL) {
michael@0 3798 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
michael@0 3799 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
michael@0 3800
michael@0 3801 mPointerController->setButtonState(mCurrentButtonState);
michael@0 3802 mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
michael@0 3803 mCurrentCookedPointerData.idToIndex,
michael@0 3804 mCurrentCookedPointerData.touchingIdBits);
michael@0 3805 }
michael@0 3806
michael@0 3807 dispatchHoverExit(when, policyFlags);
michael@0 3808 dispatchTouches(when, policyFlags);
michael@0 3809 dispatchHoverEnterAndMove(when, policyFlags);
michael@0 3810 }
michael@0 3811
michael@0 3812 // Synthesize key up from raw buttons if needed.
michael@0 3813 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
michael@0 3814 policyFlags, mLastButtonState, mCurrentButtonState);
michael@0 3815 }
michael@0 3816
michael@0 3817 // Copy current touch to last touch in preparation for the next cycle.
michael@0 3818 mLastRawPointerData.copyFrom(mCurrentRawPointerData);
michael@0 3819 mLastCookedPointerData.copyFrom(mCurrentCookedPointerData);
michael@0 3820 mLastButtonState = mCurrentButtonState;
michael@0 3821 mLastFingerIdBits = mCurrentFingerIdBits;
michael@0 3822 mLastStylusIdBits = mCurrentStylusIdBits;
michael@0 3823 mLastMouseIdBits = mCurrentMouseIdBits;
michael@0 3824
michael@0 3825 // Clear some transient state.
michael@0 3826 mCurrentRawVScroll = 0;
michael@0 3827 mCurrentRawHScroll = 0;
michael@0 3828 }
michael@0 3829
michael@0 3830 void TouchInputMapper::timeoutExpired(nsecs_t when) {
michael@0 3831 if (mDeviceMode == DEVICE_MODE_POINTER) {
michael@0 3832 if (mPointerUsage == POINTER_USAGE_GESTURES) {
michael@0 3833 dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
michael@0 3834 }
michael@0 3835 }
michael@0 3836 }
michael@0 3837
michael@0 3838 bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
michael@0 3839 // Check for release of a virtual key.
michael@0 3840 if (mCurrentVirtualKey.down) {
michael@0 3841 if (mCurrentRawPointerData.touchingIdBits.isEmpty()) {
michael@0 3842 // Pointer went up while virtual key was down.
michael@0 3843 mCurrentVirtualKey.down = false;
michael@0 3844 if (!mCurrentVirtualKey.ignored) {
michael@0 3845 #if DEBUG_VIRTUAL_KEYS
michael@0 3846 ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
michael@0 3847 mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
michael@0 3848 #endif
michael@0 3849 dispatchVirtualKey(when, policyFlags,
michael@0 3850 AKEY_EVENT_ACTION_UP,
michael@0 3851 AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
michael@0 3852 }
michael@0 3853 return true;
michael@0 3854 }
michael@0 3855
michael@0 3856 if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
michael@0 3857 uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
michael@0 3858 const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
michael@0 3859 const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
michael@0 3860 if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
michael@0 3861 // Pointer is still within the space of the virtual key.
michael@0 3862 return true;
michael@0 3863 }
michael@0 3864 }
michael@0 3865
michael@0 3866 // Pointer left virtual key area or another pointer also went down.
michael@0 3867 // Send key cancellation but do not consume the touch yet.
michael@0 3868 // This is useful when the user swipes through from the virtual key area
michael@0 3869 // into the main display surface.
michael@0 3870 mCurrentVirtualKey.down = false;
michael@0 3871 if (!mCurrentVirtualKey.ignored) {
michael@0 3872 #if DEBUG_VIRTUAL_KEYS
michael@0 3873 ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
michael@0 3874 mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
michael@0 3875 #endif
michael@0 3876 dispatchVirtualKey(when, policyFlags,
michael@0 3877 AKEY_EVENT_ACTION_UP,
michael@0 3878 AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
michael@0 3879 | AKEY_EVENT_FLAG_CANCELED);
michael@0 3880 }
michael@0 3881 }
michael@0 3882
michael@0 3883 if (mLastRawPointerData.touchingIdBits.isEmpty()
michael@0 3884 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
michael@0 3885 // Pointer just went down. Check for virtual key press or off-screen touches.
michael@0 3886 uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
michael@0 3887 const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
michael@0 3888 if (!isPointInsideSurface(pointer.x, pointer.y)) {
michael@0 3889 // If exactly one pointer went down, check for virtual key hit.
michael@0 3890 // Otherwise we will drop the entire stroke.
michael@0 3891 if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
michael@0 3892 const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
michael@0 3893 if (virtualKey) {
michael@0 3894 mCurrentVirtualKey.down = true;
michael@0 3895 mCurrentVirtualKey.downTime = when;
michael@0 3896 mCurrentVirtualKey.keyCode = virtualKey->keyCode;
michael@0 3897 mCurrentVirtualKey.scanCode = virtualKey->scanCode;
michael@0 3898 mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey(
michael@0 3899 when, getDevice(), virtualKey->keyCode, virtualKey->scanCode);
michael@0 3900
michael@0 3901 if (!mCurrentVirtualKey.ignored) {
michael@0 3902 #if DEBUG_VIRTUAL_KEYS
michael@0 3903 ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
michael@0 3904 mCurrentVirtualKey.keyCode,
michael@0 3905 mCurrentVirtualKey.scanCode);
michael@0 3906 #endif
michael@0 3907 dispatchVirtualKey(when, policyFlags,
michael@0 3908 AKEY_EVENT_ACTION_DOWN,
michael@0 3909 AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
michael@0 3910 }
michael@0 3911 }
michael@0 3912 }
michael@0 3913 return true;
michael@0 3914 }
michael@0 3915 }
michael@0 3916
michael@0 3917 // Disable all virtual key touches that happen within a short time interval of the
michael@0 3918 // most recent touch within the screen area. The idea is to filter out stray
michael@0 3919 // virtual key presses when interacting with the touch screen.
michael@0 3920 //
michael@0 3921 // Problems we're trying to solve:
michael@0 3922 //
michael@0 3923 // 1. While scrolling a list or dragging the window shade, the user swipes down into a
michael@0 3924 // virtual key area that is implemented by a separate touch panel and accidentally
michael@0 3925 // triggers a virtual key.
michael@0 3926 //
michael@0 3927 // 2. While typing in the on screen keyboard, the user taps slightly outside the screen
michael@0 3928 // area and accidentally triggers a virtual key. This often happens when virtual keys
michael@0 3929 // are layed out below the screen near to where the on screen keyboard's space bar
michael@0 3930 // is displayed.
michael@0 3931 if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
michael@0 3932 mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
michael@0 3933 }
michael@0 3934 return false;
michael@0 3935 }
michael@0 3936
michael@0 3937 void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
michael@0 3938 int32_t keyEventAction, int32_t keyEventFlags) {
michael@0 3939 int32_t keyCode = mCurrentVirtualKey.keyCode;
michael@0 3940 int32_t scanCode = mCurrentVirtualKey.scanCode;
michael@0 3941 nsecs_t downTime = mCurrentVirtualKey.downTime;
michael@0 3942 int32_t metaState = mContext->getGlobalMetaState();
michael@0 3943 policyFlags |= POLICY_FLAG_VIRTUAL;
michael@0 3944
michael@0 3945 NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
michael@0 3946 keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
michael@0 3947 getListener()->notifyKey(&args);
michael@0 3948 }
michael@0 3949
michael@0 3950 void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
michael@0 3951 BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits;
michael@0 3952 BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits;
michael@0 3953 int32_t metaState = getContext()->getGlobalMetaState();
michael@0 3954 int32_t buttonState = mCurrentButtonState;
michael@0 3955
michael@0 3956 if (currentIdBits == lastIdBits) {
michael@0 3957 if (!currentIdBits.isEmpty()) {
michael@0 3958 // No pointer id changes so this is a move event.
michael@0 3959 // The listener takes care of batching moves so we don't have to deal with that here.
michael@0 3960 dispatchMotion(when, policyFlags, mSource,
michael@0 3961 AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
michael@0 3962 AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 3963 mCurrentCookedPointerData.pointerProperties,
michael@0 3964 mCurrentCookedPointerData.pointerCoords,
michael@0 3965 mCurrentCookedPointerData.idToIndex,
michael@0 3966 currentIdBits, -1,
michael@0 3967 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
michael@0 3968 }
michael@0 3969 } else {
michael@0 3970 // There may be pointers going up and pointers going down and pointers moving
michael@0 3971 // all at the same time.
michael@0 3972 BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
michael@0 3973 BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
michael@0 3974 BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
michael@0 3975 BitSet32 dispatchedIdBits(lastIdBits.value);
michael@0 3976
michael@0 3977 // Update last coordinates of pointers that have moved so that we observe the new
michael@0 3978 // pointer positions at the same time as other pointers that have just gone up.
michael@0 3979 bool moveNeeded = updateMovedPointers(
michael@0 3980 mCurrentCookedPointerData.pointerProperties,
michael@0 3981 mCurrentCookedPointerData.pointerCoords,
michael@0 3982 mCurrentCookedPointerData.idToIndex,
michael@0 3983 mLastCookedPointerData.pointerProperties,
michael@0 3984 mLastCookedPointerData.pointerCoords,
michael@0 3985 mLastCookedPointerData.idToIndex,
michael@0 3986 moveIdBits);
michael@0 3987 if (buttonState != mLastButtonState) {
michael@0 3988 moveNeeded = true;
michael@0 3989 }
michael@0 3990
michael@0 3991 // Dispatch pointer up events.
michael@0 3992 while (!upIdBits.isEmpty()) {
michael@0 3993 uint32_t upId = upIdBits.clearFirstMarkedBit();
michael@0 3994
michael@0 3995 dispatchMotion(when, policyFlags, mSource,
michael@0 3996 AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0,
michael@0 3997 mLastCookedPointerData.pointerProperties,
michael@0 3998 mLastCookedPointerData.pointerCoords,
michael@0 3999 mLastCookedPointerData.idToIndex,
michael@0 4000 dispatchedIdBits, upId,
michael@0 4001 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
michael@0 4002 dispatchedIdBits.clearBit(upId);
michael@0 4003 }
michael@0 4004
michael@0 4005 // Dispatch move events if any of the remaining pointers moved from their old locations.
michael@0 4006 // Although applications receive new locations as part of individual pointer up
michael@0 4007 // events, they do not generally handle them except when presented in a move event.
michael@0 4008 if (moveNeeded) {
michael@0 4009 ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
michael@0 4010 dispatchMotion(when, policyFlags, mSource,
michael@0 4011 AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
michael@0 4012 mCurrentCookedPointerData.pointerProperties,
michael@0 4013 mCurrentCookedPointerData.pointerCoords,
michael@0 4014 mCurrentCookedPointerData.idToIndex,
michael@0 4015 dispatchedIdBits, -1,
michael@0 4016 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
michael@0 4017 }
michael@0 4018
michael@0 4019 // Dispatch pointer down events using the new pointer locations.
michael@0 4020 while (!downIdBits.isEmpty()) {
michael@0 4021 uint32_t downId = downIdBits.clearFirstMarkedBit();
michael@0 4022 dispatchedIdBits.markBit(downId);
michael@0 4023
michael@0 4024 if (dispatchedIdBits.count() == 1) {
michael@0 4025 // First pointer is going down. Set down time.
michael@0 4026 mDownTime = when;
michael@0 4027 }
michael@0 4028
michael@0 4029 dispatchMotion(when, policyFlags, mSource,
michael@0 4030 AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
michael@0 4031 mCurrentCookedPointerData.pointerProperties,
michael@0 4032 mCurrentCookedPointerData.pointerCoords,
michael@0 4033 mCurrentCookedPointerData.idToIndex,
michael@0 4034 dispatchedIdBits, downId,
michael@0 4035 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
michael@0 4036 }
michael@0 4037 }
michael@0 4038 }
michael@0 4039
michael@0 4040 void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) {
michael@0 4041 if (mSentHoverEnter &&
michael@0 4042 (mCurrentCookedPointerData.hoveringIdBits.isEmpty()
michael@0 4043 || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) {
michael@0 4044 int32_t metaState = getContext()->getGlobalMetaState();
michael@0 4045 dispatchMotion(when, policyFlags, mSource,
michael@0 4046 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
michael@0 4047 mLastCookedPointerData.pointerProperties,
michael@0 4048 mLastCookedPointerData.pointerCoords,
michael@0 4049 mLastCookedPointerData.idToIndex,
michael@0 4050 mLastCookedPointerData.hoveringIdBits, -1,
michael@0 4051 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
michael@0 4052 mSentHoverEnter = false;
michael@0 4053 }
michael@0 4054 }
michael@0 4055
michael@0 4056 void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) {
michael@0 4057 if (mCurrentCookedPointerData.touchingIdBits.isEmpty()
michael@0 4058 && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) {
michael@0 4059 int32_t metaState = getContext()->getGlobalMetaState();
michael@0 4060 if (!mSentHoverEnter) {
michael@0 4061 dispatchMotion(when, policyFlags, mSource,
michael@0 4062 AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
michael@0 4063 mCurrentCookedPointerData.pointerProperties,
michael@0 4064 mCurrentCookedPointerData.pointerCoords,
michael@0 4065 mCurrentCookedPointerData.idToIndex,
michael@0 4066 mCurrentCookedPointerData.hoveringIdBits, -1,
michael@0 4067 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
michael@0 4068 mSentHoverEnter = true;
michael@0 4069 }
michael@0 4070
michael@0 4071 dispatchMotion(when, policyFlags, mSource,
michael@0 4072 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
michael@0 4073 mCurrentCookedPointerData.pointerProperties,
michael@0 4074 mCurrentCookedPointerData.pointerCoords,
michael@0 4075 mCurrentCookedPointerData.idToIndex,
michael@0 4076 mCurrentCookedPointerData.hoveringIdBits, -1,
michael@0 4077 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
michael@0 4078 }
michael@0 4079 }
michael@0 4080
michael@0 4081 void TouchInputMapper::cookPointerData() {
michael@0 4082 uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
michael@0 4083
michael@0 4084 mCurrentCookedPointerData.clear();
michael@0 4085 mCurrentCookedPointerData.pointerCount = currentPointerCount;
michael@0 4086 mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits;
michael@0 4087 mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits;
michael@0 4088
michael@0 4089 // Walk through the the active pointers and map device coordinates onto
michael@0 4090 // surface coordinates and adjust for display orientation.
michael@0 4091 for (uint32_t i = 0; i < currentPointerCount; i++) {
michael@0 4092 const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i];
michael@0 4093
michael@0 4094 // Size
michael@0 4095 float touchMajor, touchMinor, toolMajor, toolMinor, size;
michael@0 4096 switch (mCalibration.sizeCalibration) {
michael@0 4097 case Calibration::SIZE_CALIBRATION_GEOMETRIC:
michael@0 4098 case Calibration::SIZE_CALIBRATION_DIAMETER:
michael@0 4099 case Calibration::SIZE_CALIBRATION_BOX:
michael@0 4100 case Calibration::SIZE_CALIBRATION_AREA:
michael@0 4101 if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) {
michael@0 4102 touchMajor = in.touchMajor;
michael@0 4103 touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
michael@0 4104 toolMajor = in.toolMajor;
michael@0 4105 toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor;
michael@0 4106 size = mRawPointerAxes.touchMinor.valid
michael@0 4107 ? avg(in.touchMajor, in.touchMinor) : in.touchMajor;
michael@0 4108 } else if (mRawPointerAxes.touchMajor.valid) {
michael@0 4109 toolMajor = touchMajor = in.touchMajor;
michael@0 4110 toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid
michael@0 4111 ? in.touchMinor : in.touchMajor;
michael@0 4112 size = mRawPointerAxes.touchMinor.valid
michael@0 4113 ? avg(in.touchMajor, in.touchMinor) : in.touchMajor;
michael@0 4114 } else if (mRawPointerAxes.toolMajor.valid) {
michael@0 4115 touchMajor = toolMajor = in.toolMajor;
michael@0 4116 touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid
michael@0 4117 ? in.toolMinor : in.toolMajor;
michael@0 4118 size = mRawPointerAxes.toolMinor.valid
michael@0 4119 ? avg(in.toolMajor, in.toolMinor) : in.toolMajor;
michael@0 4120 } else {
michael@0 4121 ALOG_ASSERT(false, "No touch or tool axes. "
michael@0 4122 "Size calibration should have been resolved to NONE.");
michael@0 4123 touchMajor = 0;
michael@0 4124 touchMinor = 0;
michael@0 4125 toolMajor = 0;
michael@0 4126 toolMinor = 0;
michael@0 4127 size = 0;
michael@0 4128 }
michael@0 4129
michael@0 4130 if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) {
michael@0 4131 uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count();
michael@0 4132 if (touchingCount > 1) {
michael@0 4133 touchMajor /= touchingCount;
michael@0 4134 touchMinor /= touchingCount;
michael@0 4135 toolMajor /= touchingCount;
michael@0 4136 toolMinor /= touchingCount;
michael@0 4137 size /= touchingCount;
michael@0 4138 }
michael@0 4139 }
michael@0 4140
michael@0 4141 if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) {
michael@0 4142 touchMajor *= mGeometricScale;
michael@0 4143 touchMinor *= mGeometricScale;
michael@0 4144 toolMajor *= mGeometricScale;
michael@0 4145 toolMinor *= mGeometricScale;
michael@0 4146 } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) {
michael@0 4147 touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0;
michael@0 4148 touchMinor = touchMajor;
michael@0 4149 toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0;
michael@0 4150 toolMinor = toolMajor;
michael@0 4151 } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) {
michael@0 4152 touchMinor = touchMajor;
michael@0 4153 toolMinor = toolMajor;
michael@0 4154 }
michael@0 4155
michael@0 4156 mCalibration.applySizeScaleAndBias(&touchMajor);
michael@0 4157 mCalibration.applySizeScaleAndBias(&touchMinor);
michael@0 4158 mCalibration.applySizeScaleAndBias(&toolMajor);
michael@0 4159 mCalibration.applySizeScaleAndBias(&toolMinor);
michael@0 4160 size *= mSizeScale;
michael@0 4161 break;
michael@0 4162 default:
michael@0 4163 touchMajor = 0;
michael@0 4164 touchMinor = 0;
michael@0 4165 toolMajor = 0;
michael@0 4166 toolMinor = 0;
michael@0 4167 size = 0;
michael@0 4168 break;
michael@0 4169 }
michael@0 4170
michael@0 4171 // Pressure
michael@0 4172 float pressure;
michael@0 4173 switch (mCalibration.pressureCalibration) {
michael@0 4174 case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
michael@0 4175 case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
michael@0 4176 pressure = in.pressure * mPressureScale;
michael@0 4177 break;
michael@0 4178 default:
michael@0 4179 pressure = in.isHovering ? 0 : 1;
michael@0 4180 break;
michael@0 4181 }
michael@0 4182
michael@0 4183 // Tilt and Orientation
michael@0 4184 float tilt;
michael@0 4185 float orientation;
michael@0 4186 if (mHaveTilt) {
michael@0 4187 float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale;
michael@0 4188 float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale;
michael@0 4189 orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle));
michael@0 4190 tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle));
michael@0 4191 } else {
michael@0 4192 tilt = 0;
michael@0 4193
michael@0 4194 switch (mCalibration.orientationCalibration) {
michael@0 4195 case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
michael@0 4196 orientation = in.orientation * mOrientationScale;
michael@0 4197 break;
michael@0 4198 case Calibration::ORIENTATION_CALIBRATION_VECTOR: {
michael@0 4199 int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
michael@0 4200 int32_t c2 = signExtendNybble(in.orientation & 0x0f);
michael@0 4201 if (c1 != 0 || c2 != 0) {
michael@0 4202 orientation = atan2f(c1, c2) * 0.5f;
michael@0 4203 float confidence = hypotf(c1, c2);
michael@0 4204 float scale = 1.0f + confidence / 16.0f;
michael@0 4205 touchMajor *= scale;
michael@0 4206 touchMinor /= scale;
michael@0 4207 toolMajor *= scale;
michael@0 4208 toolMinor /= scale;
michael@0 4209 } else {
michael@0 4210 orientation = 0;
michael@0 4211 }
michael@0 4212 break;
michael@0 4213 }
michael@0 4214 default:
michael@0 4215 orientation = 0;
michael@0 4216 }
michael@0 4217 }
michael@0 4218
michael@0 4219 // Distance
michael@0 4220 float distance;
michael@0 4221 switch (mCalibration.distanceCalibration) {
michael@0 4222 case Calibration::DISTANCE_CALIBRATION_SCALED:
michael@0 4223 distance = in.distance * mDistanceScale;
michael@0 4224 break;
michael@0 4225 default:
michael@0 4226 distance = 0;
michael@0 4227 }
michael@0 4228
michael@0 4229 // Coverage
michael@0 4230 int32_t rawLeft, rawTop, rawRight, rawBottom;
michael@0 4231 switch (mCalibration.coverageCalibration) {
michael@0 4232 case Calibration::COVERAGE_CALIBRATION_BOX:
michael@0 4233 rawLeft = (in.toolMinor & 0xffff0000) >> 16;
michael@0 4234 rawRight = in.toolMinor & 0x0000ffff;
michael@0 4235 rawBottom = in.toolMajor & 0x0000ffff;
michael@0 4236 rawTop = (in.toolMajor & 0xffff0000) >> 16;
michael@0 4237 break;
michael@0 4238 default:
michael@0 4239 rawLeft = rawTop = rawRight = rawBottom = 0;
michael@0 4240 break;
michael@0 4241 }
michael@0 4242
michael@0 4243 // X, Y, and the bounding box for coverage information
michael@0 4244 // Adjust coords for surface orientation.
michael@0 4245 float x, y, left, top, right, bottom;
michael@0 4246 switch (mSurfaceOrientation) {
michael@0 4247 case DISPLAY_ORIENTATION_90:
michael@0 4248 x = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
michael@0 4249 y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
michael@0 4250 left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
michael@0 4251 right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
michael@0 4252 bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
michael@0 4253 top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
michael@0 4254 orientation -= M_PI_2;
michael@0 4255 if (orientation < - M_PI_2) {
michael@0 4256 orientation += M_PI;
michael@0 4257 }
michael@0 4258 break;
michael@0 4259 case DISPLAY_ORIENTATION_180:
michael@0 4260 x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
michael@0 4261 y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
michael@0 4262 left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
michael@0 4263 right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
michael@0 4264 bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
michael@0 4265 top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
michael@0 4266 break;
michael@0 4267 case DISPLAY_ORIENTATION_270:
michael@0 4268 x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
michael@0 4269 y = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
michael@0 4270 left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
michael@0 4271 right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
michael@0 4272 bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
michael@0 4273 top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
michael@0 4274 orientation += M_PI_2;
michael@0 4275 if (orientation > M_PI_2) {
michael@0 4276 orientation -= M_PI;
michael@0 4277 }
michael@0 4278 break;
michael@0 4279 default:
michael@0 4280 x = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
michael@0 4281 y = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
michael@0 4282 left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
michael@0 4283 right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
michael@0 4284 bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
michael@0 4285 top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
michael@0 4286 break;
michael@0 4287 }
michael@0 4288
michael@0 4289 // Write output coords.
michael@0 4290 PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i];
michael@0 4291 out.clear();
michael@0 4292 out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
michael@0 4293 out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
michael@0 4294 out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
michael@0 4295 out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
michael@0 4296 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
michael@0 4297 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
michael@0 4298 out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
michael@0 4299 out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
michael@0 4300 out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
michael@0 4301 if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
michael@0 4302 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);
michael@0 4303 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);
michael@0 4304 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);
michael@0 4305 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom);
michael@0 4306 } else {
michael@0 4307 out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
michael@0 4308 out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
michael@0 4309 }
michael@0 4310
michael@0 4311 // Write output properties.
michael@0 4312 PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i];
michael@0 4313 uint32_t id = in.id;
michael@0 4314 properties.clear();
michael@0 4315 properties.id = id;
michael@0 4316 properties.toolType = in.toolType;
michael@0 4317
michael@0 4318 // Write id index.
michael@0 4319 mCurrentCookedPointerData.idToIndex[id] = i;
michael@0 4320 }
michael@0 4321 }
michael@0 4322
michael@0 4323 void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags,
michael@0 4324 PointerUsage pointerUsage) {
michael@0 4325 if (pointerUsage != mPointerUsage) {
michael@0 4326 abortPointerUsage(when, policyFlags);
michael@0 4327 mPointerUsage = pointerUsage;
michael@0 4328 }
michael@0 4329
michael@0 4330 switch (mPointerUsage) {
michael@0 4331 case POINTER_USAGE_GESTURES:
michael@0 4332 dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
michael@0 4333 break;
michael@0 4334 case POINTER_USAGE_STYLUS:
michael@0 4335 dispatchPointerStylus(when, policyFlags);
michael@0 4336 break;
michael@0 4337 case POINTER_USAGE_MOUSE:
michael@0 4338 dispatchPointerMouse(when, policyFlags);
michael@0 4339 break;
michael@0 4340 default:
michael@0 4341 break;
michael@0 4342 }
michael@0 4343 }
michael@0 4344
michael@0 4345 void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) {
michael@0 4346 switch (mPointerUsage) {
michael@0 4347 case POINTER_USAGE_GESTURES:
michael@0 4348 abortPointerGestures(when, policyFlags);
michael@0 4349 break;
michael@0 4350 case POINTER_USAGE_STYLUS:
michael@0 4351 abortPointerStylus(when, policyFlags);
michael@0 4352 break;
michael@0 4353 case POINTER_USAGE_MOUSE:
michael@0 4354 abortPointerMouse(when, policyFlags);
michael@0 4355 break;
michael@0 4356 default:
michael@0 4357 break;
michael@0 4358 }
michael@0 4359
michael@0 4360 mPointerUsage = POINTER_USAGE_NONE;
michael@0 4361 }
michael@0 4362
michael@0 4363 void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags,
michael@0 4364 bool isTimeout) {
michael@0 4365 // Update current gesture coordinates.
michael@0 4366 bool cancelPreviousGesture, finishPreviousGesture;
michael@0 4367 bool sendEvents = preparePointerGestures(when,
michael@0 4368 &cancelPreviousGesture, &finishPreviousGesture, isTimeout);
michael@0 4369 if (!sendEvents) {
michael@0 4370 return;
michael@0 4371 }
michael@0 4372 if (finishPreviousGesture) {
michael@0 4373 cancelPreviousGesture = false;
michael@0 4374 }
michael@0 4375
michael@0 4376 // Update the pointer presentation and spots.
michael@0 4377 if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
michael@0 4378 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
michael@0 4379 if (finishPreviousGesture || cancelPreviousGesture) {
michael@0 4380 mPointerController->clearSpots();
michael@0 4381 }
michael@0 4382 mPointerController->setSpots(mPointerGesture.currentGestureCoords,
michael@0 4383 mPointerGesture.currentGestureIdToIndex,
michael@0 4384 mPointerGesture.currentGestureIdBits);
michael@0 4385 } else {
michael@0 4386 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
michael@0 4387 }
michael@0 4388
michael@0 4389 // Show or hide the pointer if needed.
michael@0 4390 switch (mPointerGesture.currentGestureMode) {
michael@0 4391 case PointerGesture::NEUTRAL:
michael@0 4392 case PointerGesture::QUIET:
michael@0 4393 if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
michael@0 4394 && (mPointerGesture.lastGestureMode == PointerGesture::SWIPE
michael@0 4395 || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)) {
michael@0 4396 // Remind the user of where the pointer is after finishing a gesture with spots.
michael@0 4397 mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL);
michael@0 4398 }
michael@0 4399 break;
michael@0 4400 case PointerGesture::TAP:
michael@0 4401 case PointerGesture::TAP_DRAG:
michael@0 4402 case PointerGesture::BUTTON_CLICK_OR_DRAG:
michael@0 4403 case PointerGesture::HOVER:
michael@0 4404 case PointerGesture::PRESS:
michael@0 4405 // Unfade the pointer when the current gesture manipulates the
michael@0 4406 // area directly under the pointer.
michael@0 4407 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
michael@0 4408 break;
michael@0 4409 case PointerGesture::SWIPE:
michael@0 4410 case PointerGesture::FREEFORM:
michael@0 4411 // Fade the pointer when the current gesture manipulates a different
michael@0 4412 // area and there are spots to guide the user experience.
michael@0 4413 if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
michael@0 4414 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
michael@0 4415 } else {
michael@0 4416 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
michael@0 4417 }
michael@0 4418 break;
michael@0 4419 }
michael@0 4420
michael@0 4421 // Send events!
michael@0 4422 int32_t metaState = getContext()->getGlobalMetaState();
michael@0 4423 int32_t buttonState = mCurrentButtonState;
michael@0 4424
michael@0 4425 // Update last coordinates of pointers that have moved so that we observe the new
michael@0 4426 // pointer positions at the same time as other pointers that have just gone up.
michael@0 4427 bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP
michael@0 4428 || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG
michael@0 4429 || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
michael@0 4430 || mPointerGesture.currentGestureMode == PointerGesture::PRESS
michael@0 4431 || mPointerGesture.currentGestureMode == PointerGesture::SWIPE
michael@0 4432 || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM;
michael@0 4433 bool moveNeeded = false;
michael@0 4434 if (down && !cancelPreviousGesture && !finishPreviousGesture
michael@0 4435 && !mPointerGesture.lastGestureIdBits.isEmpty()
michael@0 4436 && !mPointerGesture.currentGestureIdBits.isEmpty()) {
michael@0 4437 BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value
michael@0 4438 & mPointerGesture.lastGestureIdBits.value);
michael@0 4439 moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties,
michael@0 4440 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
michael@0 4441 mPointerGesture.lastGestureProperties,
michael@0 4442 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
michael@0 4443 movedGestureIdBits);
michael@0 4444 if (buttonState != mLastButtonState) {
michael@0 4445 moveNeeded = true;
michael@0 4446 }
michael@0 4447 }
michael@0 4448
michael@0 4449 // Send motion events for all pointers that went up or were canceled.
michael@0 4450 BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits);
michael@0 4451 if (!dispatchedGestureIdBits.isEmpty()) {
michael@0 4452 if (cancelPreviousGesture) {
michael@0 4453 dispatchMotion(when, policyFlags, mSource,
michael@0 4454 AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
michael@0 4455 AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 4456 mPointerGesture.lastGestureProperties,
michael@0 4457 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
michael@0 4458 dispatchedGestureIdBits, -1,
michael@0 4459 0, 0, mPointerGesture.downTime);
michael@0 4460
michael@0 4461 dispatchedGestureIdBits.clear();
michael@0 4462 } else {
michael@0 4463 BitSet32 upGestureIdBits;
michael@0 4464 if (finishPreviousGesture) {
michael@0 4465 upGestureIdBits = dispatchedGestureIdBits;
michael@0 4466 } else {
michael@0 4467 upGestureIdBits.value = dispatchedGestureIdBits.value
michael@0 4468 & ~mPointerGesture.currentGestureIdBits.value;
michael@0 4469 }
michael@0 4470 while (!upGestureIdBits.isEmpty()) {
michael@0 4471 uint32_t id = upGestureIdBits.clearFirstMarkedBit();
michael@0 4472
michael@0 4473 dispatchMotion(when, policyFlags, mSource,
michael@0 4474 AMOTION_EVENT_ACTION_POINTER_UP, 0,
michael@0 4475 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 4476 mPointerGesture.lastGestureProperties,
michael@0 4477 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
michael@0 4478 dispatchedGestureIdBits, id,
michael@0 4479 0, 0, mPointerGesture.downTime);
michael@0 4480
michael@0 4481 dispatchedGestureIdBits.clearBit(id);
michael@0 4482 }
michael@0 4483 }
michael@0 4484 }
michael@0 4485
michael@0 4486 // Send motion events for all pointers that moved.
michael@0 4487 if (moveNeeded) {
michael@0 4488 dispatchMotion(when, policyFlags, mSource,
michael@0 4489 AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 4490 mPointerGesture.currentGestureProperties,
michael@0 4491 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
michael@0 4492 dispatchedGestureIdBits, -1,
michael@0 4493 0, 0, mPointerGesture.downTime);
michael@0 4494 }
michael@0 4495
michael@0 4496 // Send motion events for all pointers that went down.
michael@0 4497 if (down) {
michael@0 4498 BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value
michael@0 4499 & ~dispatchedGestureIdBits.value);
michael@0 4500 while (!downGestureIdBits.isEmpty()) {
michael@0 4501 uint32_t id = downGestureIdBits.clearFirstMarkedBit();
michael@0 4502 dispatchedGestureIdBits.markBit(id);
michael@0 4503
michael@0 4504 if (dispatchedGestureIdBits.count() == 1) {
michael@0 4505 mPointerGesture.downTime = when;
michael@0 4506 }
michael@0 4507
michael@0 4508 dispatchMotion(when, policyFlags, mSource,
michael@0 4509 AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
michael@0 4510 mPointerGesture.currentGestureProperties,
michael@0 4511 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
michael@0 4512 dispatchedGestureIdBits, id,
michael@0 4513 0, 0, mPointerGesture.downTime);
michael@0 4514 }
michael@0 4515 }
michael@0 4516
michael@0 4517 // Send motion events for hover.
michael@0 4518 if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
michael@0 4519 dispatchMotion(when, policyFlags, mSource,
michael@0 4520 AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
michael@0 4521 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 4522 mPointerGesture.currentGestureProperties,
michael@0 4523 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
michael@0 4524 mPointerGesture.currentGestureIdBits, -1,
michael@0 4525 0, 0, mPointerGesture.downTime);
michael@0 4526 } else if (dispatchedGestureIdBits.isEmpty()
michael@0 4527 && !mPointerGesture.lastGestureIdBits.isEmpty()) {
michael@0 4528 // Synthesize a hover move event after all pointers go up to indicate that
michael@0 4529 // the pointer is hovering again even if the user is not currently touching
michael@0 4530 // the touch pad. This ensures that a view will receive a fresh hover enter
michael@0 4531 // event after a tap.
michael@0 4532 float x, y;
michael@0 4533 mPointerController->getPosition(&x, &y);
michael@0 4534
michael@0 4535 PointerProperties pointerProperties;
michael@0 4536 pointerProperties.clear();
michael@0 4537 pointerProperties.id = 0;
michael@0 4538 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 4539
michael@0 4540 PointerCoords pointerCoords;
michael@0 4541 pointerCoords.clear();
michael@0 4542 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
michael@0 4543 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
michael@0 4544
michael@0 4545 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 4546 AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
michael@0 4547 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 4548 mViewport.displayId, 1, &pointerProperties, &pointerCoords,
michael@0 4549 0, 0, mPointerGesture.downTime);
michael@0 4550 getListener()->notifyMotion(&args);
michael@0 4551 }
michael@0 4552
michael@0 4553 // Update state.
michael@0 4554 mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode;
michael@0 4555 if (!down) {
michael@0 4556 mPointerGesture.lastGestureIdBits.clear();
michael@0 4557 } else {
michael@0 4558 mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits;
michael@0 4559 for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) {
michael@0 4560 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 4561 uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
michael@0 4562 mPointerGesture.lastGestureProperties[index].copyFrom(
michael@0 4563 mPointerGesture.currentGestureProperties[index]);
michael@0 4564 mPointerGesture.lastGestureCoords[index].copyFrom(
michael@0 4565 mPointerGesture.currentGestureCoords[index]);
michael@0 4566 mPointerGesture.lastGestureIdToIndex[id] = index;
michael@0 4567 }
michael@0 4568 }
michael@0 4569 }
michael@0 4570
michael@0 4571 void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) {
michael@0 4572 // Cancel previously dispatches pointers.
michael@0 4573 if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
michael@0 4574 int32_t metaState = getContext()->getGlobalMetaState();
michael@0 4575 int32_t buttonState = mCurrentButtonState;
michael@0 4576 dispatchMotion(when, policyFlags, mSource,
michael@0 4577 AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
michael@0 4578 AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 4579 mPointerGesture.lastGestureProperties,
michael@0 4580 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
michael@0 4581 mPointerGesture.lastGestureIdBits, -1,
michael@0 4582 0, 0, mPointerGesture.downTime);
michael@0 4583 }
michael@0 4584
michael@0 4585 // Reset the current pointer gesture.
michael@0 4586 mPointerGesture.reset();
michael@0 4587 mPointerVelocityControl.reset();
michael@0 4588
michael@0 4589 // Remove any current spots.
michael@0 4590 if (mPointerController != NULL) {
michael@0 4591 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
michael@0 4592 mPointerController->clearSpots();
michael@0 4593 }
michael@0 4594 }
michael@0 4595
michael@0 4596 bool TouchInputMapper::preparePointerGestures(nsecs_t when,
michael@0 4597 bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) {
michael@0 4598 *outCancelPreviousGesture = false;
michael@0 4599 *outFinishPreviousGesture = false;
michael@0 4600
michael@0 4601 // Handle TAP timeout.
michael@0 4602 if (isTimeout) {
michael@0 4603 #if DEBUG_GESTURES
michael@0 4604 ALOGD("Gestures: Processing timeout");
michael@0 4605 #endif
michael@0 4606
michael@0 4607 if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
michael@0 4608 if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
michael@0 4609 // The tap/drag timeout has not yet expired.
michael@0 4610 getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime
michael@0 4611 + mConfig.pointerGestureTapDragInterval);
michael@0 4612 } else {
michael@0 4613 // The tap is finished.
michael@0 4614 #if DEBUG_GESTURES
michael@0 4615 ALOGD("Gestures: TAP finished");
michael@0 4616 #endif
michael@0 4617 *outFinishPreviousGesture = true;
michael@0 4618
michael@0 4619 mPointerGesture.activeGestureId = -1;
michael@0 4620 mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
michael@0 4621 mPointerGesture.currentGestureIdBits.clear();
michael@0 4622
michael@0 4623 mPointerVelocityControl.reset();
michael@0 4624 return true;
michael@0 4625 }
michael@0 4626 }
michael@0 4627
michael@0 4628 // We did not handle this timeout.
michael@0 4629 return false;
michael@0 4630 }
michael@0 4631
michael@0 4632 const uint32_t currentFingerCount = mCurrentFingerIdBits.count();
michael@0 4633 const uint32_t lastFingerCount = mLastFingerIdBits.count();
michael@0 4634
michael@0 4635 // Update the velocity tracker.
michael@0 4636 {
michael@0 4637 VelocityTracker::Position positions[MAX_POINTERS];
michael@0 4638 uint32_t count = 0;
michael@0 4639 for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) {
michael@0 4640 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 4641 const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
michael@0 4642 positions[count].x = pointer.x * mPointerXMovementScale;
michael@0 4643 positions[count].y = pointer.y * mPointerYMovementScale;
michael@0 4644 }
michael@0 4645 mPointerGesture.velocityTracker.addMovement(when,
michael@0 4646 mCurrentFingerIdBits, positions);
michael@0 4647 }
michael@0 4648
michael@0 4649 // Pick a new active touch id if needed.
michael@0 4650 // Choose an arbitrary pointer that just went down, if there is one.
michael@0 4651 // Otherwise choose an arbitrary remaining pointer.
michael@0 4652 // This guarantees we always have an active touch id when there is at least one pointer.
michael@0 4653 // We keep the same active touch id for as long as possible.
michael@0 4654 bool activeTouchChanged = false;
michael@0 4655 int32_t lastActiveTouchId = mPointerGesture.activeTouchId;
michael@0 4656 int32_t activeTouchId = lastActiveTouchId;
michael@0 4657 if (activeTouchId < 0) {
michael@0 4658 if (!mCurrentFingerIdBits.isEmpty()) {
michael@0 4659 activeTouchChanged = true;
michael@0 4660 activeTouchId = mPointerGesture.activeTouchId =
michael@0 4661 mCurrentFingerIdBits.firstMarkedBit();
michael@0 4662 mPointerGesture.firstTouchTime = when;
michael@0 4663 }
michael@0 4664 } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) {
michael@0 4665 activeTouchChanged = true;
michael@0 4666 if (!mCurrentFingerIdBits.isEmpty()) {
michael@0 4667 activeTouchId = mPointerGesture.activeTouchId =
michael@0 4668 mCurrentFingerIdBits.firstMarkedBit();
michael@0 4669 } else {
michael@0 4670 activeTouchId = mPointerGesture.activeTouchId = -1;
michael@0 4671 }
michael@0 4672 }
michael@0 4673
michael@0 4674 // Determine whether we are in quiet time.
michael@0 4675 bool isQuietTime = false;
michael@0 4676 if (activeTouchId < 0) {
michael@0 4677 mPointerGesture.resetQuietTime();
michael@0 4678 } else {
michael@0 4679 isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval;
michael@0 4680 if (!isQuietTime) {
michael@0 4681 if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS
michael@0 4682 || mPointerGesture.lastGestureMode == PointerGesture::SWIPE
michael@0 4683 || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)
michael@0 4684 && currentFingerCount < 2) {
michael@0 4685 // Enter quiet time when exiting swipe or freeform state.
michael@0 4686 // This is to prevent accidentally entering the hover state and flinging the
michael@0 4687 // pointer when finishing a swipe and there is still one pointer left onscreen.
michael@0 4688 isQuietTime = true;
michael@0 4689 } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
michael@0 4690 && currentFingerCount >= 2
michael@0 4691 && !isPointerDown(mCurrentButtonState)) {
michael@0 4692 // Enter quiet time when releasing the button and there are still two or more
michael@0 4693 // fingers down. This may indicate that one finger was used to press the button
michael@0 4694 // but it has not gone up yet.
michael@0 4695 isQuietTime = true;
michael@0 4696 }
michael@0 4697 if (isQuietTime) {
michael@0 4698 mPointerGesture.quietTime = when;
michael@0 4699 }
michael@0 4700 }
michael@0 4701 }
michael@0 4702
michael@0 4703 // Switch states based on button and pointer state.
michael@0 4704 if (isQuietTime) {
michael@0 4705 // Case 1: Quiet time. (QUIET)
michael@0 4706 #if DEBUG_GESTURES
michael@0 4707 ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime
michael@0 4708 + mConfig.pointerGestureQuietInterval - when) * 0.000001f);
michael@0 4709 #endif
michael@0 4710 if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) {
michael@0 4711 *outFinishPreviousGesture = true;
michael@0 4712 }
michael@0 4713
michael@0 4714 mPointerGesture.activeGestureId = -1;
michael@0 4715 mPointerGesture.currentGestureMode = PointerGesture::QUIET;
michael@0 4716 mPointerGesture.currentGestureIdBits.clear();
michael@0 4717
michael@0 4718 mPointerVelocityControl.reset();
michael@0 4719 } else if (isPointerDown(mCurrentButtonState)) {
michael@0 4720 // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
michael@0 4721 // The pointer follows the active touch point.
michael@0 4722 // Emit DOWN, MOVE, UP events at the pointer location.
michael@0 4723 //
michael@0 4724 // Only the active touch matters; other fingers are ignored. This policy helps
michael@0 4725 // to handle the case where the user places a second finger on the touch pad
michael@0 4726 // to apply the necessary force to depress an integrated button below the surface.
michael@0 4727 // We don't want the second finger to be delivered to applications.
michael@0 4728 //
michael@0 4729 // For this to work well, we need to make sure to track the pointer that is really
michael@0 4730 // active. If the user first puts one finger down to click then adds another
michael@0 4731 // finger to drag then the active pointer should switch to the finger that is
michael@0 4732 // being dragged.
michael@0 4733 #if DEBUG_GESTURES
michael@0 4734 ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, "
michael@0 4735 "currentFingerCount=%d", activeTouchId, currentFingerCount);
michael@0 4736 #endif
michael@0 4737 // Reset state when just starting.
michael@0 4738 if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) {
michael@0 4739 *outFinishPreviousGesture = true;
michael@0 4740 mPointerGesture.activeGestureId = 0;
michael@0 4741 }
michael@0 4742
michael@0 4743 // Switch pointers if needed.
michael@0 4744 // Find the fastest pointer and follow it.
michael@0 4745 if (activeTouchId >= 0 && currentFingerCount > 1) {
michael@0 4746 int32_t bestId = -1;
michael@0 4747 float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
michael@0 4748 for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) {
michael@0 4749 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 4750 float vx, vy;
michael@0 4751 if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
michael@0 4752 float speed = hypotf(vx, vy);
michael@0 4753 if (speed > bestSpeed) {
michael@0 4754 bestId = id;
michael@0 4755 bestSpeed = speed;
michael@0 4756 }
michael@0 4757 }
michael@0 4758 }
michael@0 4759 if (bestId >= 0 && bestId != activeTouchId) {
michael@0 4760 mPointerGesture.activeTouchId = activeTouchId = bestId;
michael@0 4761 activeTouchChanged = true;
michael@0 4762 #if DEBUG_GESTURES
michael@0 4763 ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
michael@0 4764 "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
michael@0 4765 #endif
michael@0 4766 }
michael@0 4767 }
michael@0 4768
michael@0 4769 if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) {
michael@0 4770 const RawPointerData::Pointer& currentPointer =
michael@0 4771 mCurrentRawPointerData.pointerForId(activeTouchId);
michael@0 4772 const RawPointerData::Pointer& lastPointer =
michael@0 4773 mLastRawPointerData.pointerForId(activeTouchId);
michael@0 4774 float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
michael@0 4775 float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
michael@0 4776
michael@0 4777 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
michael@0 4778 mPointerVelocityControl.move(when, &deltaX, &deltaY);
michael@0 4779
michael@0 4780 // Move the pointer using a relative motion.
michael@0 4781 // When using spots, the click will occur at the position of the anchor
michael@0 4782 // spot and all other spots will move there.
michael@0 4783 mPointerController->move(deltaX, deltaY);
michael@0 4784 } else {
michael@0 4785 mPointerVelocityControl.reset();
michael@0 4786 }
michael@0 4787
michael@0 4788 float x, y;
michael@0 4789 mPointerController->getPosition(&x, &y);
michael@0 4790
michael@0 4791 mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG;
michael@0 4792 mPointerGesture.currentGestureIdBits.clear();
michael@0 4793 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
michael@0 4794 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
michael@0 4795 mPointerGesture.currentGestureProperties[0].clear();
michael@0 4796 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
michael@0 4797 mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 4798 mPointerGesture.currentGestureCoords[0].clear();
michael@0 4799 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
michael@0 4800 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
michael@0 4801 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
michael@0 4802 } else if (currentFingerCount == 0) {
michael@0 4803 // Case 3. No fingers down and button is not pressed. (NEUTRAL)
michael@0 4804 if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) {
michael@0 4805 *outFinishPreviousGesture = true;
michael@0 4806 }
michael@0 4807
michael@0 4808 // Watch for taps coming out of HOVER or TAP_DRAG mode.
michael@0 4809 // Checking for taps after TAP_DRAG allows us to detect double-taps.
michael@0 4810 bool tapped = false;
michael@0 4811 if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER
michael@0 4812 || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG)
michael@0 4813 && lastFingerCount == 1) {
michael@0 4814 if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
michael@0 4815 float x, y;
michael@0 4816 mPointerController->getPosition(&x, &y);
michael@0 4817 if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop
michael@0 4818 && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
michael@0 4819 #if DEBUG_GESTURES
michael@0 4820 ALOGD("Gestures: TAP");
michael@0 4821 #endif
michael@0 4822
michael@0 4823 mPointerGesture.tapUpTime = when;
michael@0 4824 getContext()->requestTimeoutAtTime(when
michael@0 4825 + mConfig.pointerGestureTapDragInterval);
michael@0 4826
michael@0 4827 mPointerGesture.activeGestureId = 0;
michael@0 4828 mPointerGesture.currentGestureMode = PointerGesture::TAP;
michael@0 4829 mPointerGesture.currentGestureIdBits.clear();
michael@0 4830 mPointerGesture.currentGestureIdBits.markBit(
michael@0 4831 mPointerGesture.activeGestureId);
michael@0 4832 mPointerGesture.currentGestureIdToIndex[
michael@0 4833 mPointerGesture.activeGestureId] = 0;
michael@0 4834 mPointerGesture.currentGestureProperties[0].clear();
michael@0 4835 mPointerGesture.currentGestureProperties[0].id =
michael@0 4836 mPointerGesture.activeGestureId;
michael@0 4837 mPointerGesture.currentGestureProperties[0].toolType =
michael@0 4838 AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 4839 mPointerGesture.currentGestureCoords[0].clear();
michael@0 4840 mPointerGesture.currentGestureCoords[0].setAxisValue(
michael@0 4841 AMOTION_EVENT_AXIS_X, mPointerGesture.tapX);
michael@0 4842 mPointerGesture.currentGestureCoords[0].setAxisValue(
michael@0 4843 AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY);
michael@0 4844 mPointerGesture.currentGestureCoords[0].setAxisValue(
michael@0 4845 AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
michael@0 4846
michael@0 4847 tapped = true;
michael@0 4848 } else {
michael@0 4849 #if DEBUG_GESTURES
michael@0 4850 ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f",
michael@0 4851 x - mPointerGesture.tapX,
michael@0 4852 y - mPointerGesture.tapY);
michael@0 4853 #endif
michael@0 4854 }
michael@0 4855 } else {
michael@0 4856 #if DEBUG_GESTURES
michael@0 4857 ALOGD("Gestures: Not a TAP, %0.3fms since down",
michael@0 4858 (when - mPointerGesture.tapDownTime) * 0.000001f);
michael@0 4859 #endif
michael@0 4860 }
michael@0 4861 }
michael@0 4862
michael@0 4863 mPointerVelocityControl.reset();
michael@0 4864
michael@0 4865 if (!tapped) {
michael@0 4866 #if DEBUG_GESTURES
michael@0 4867 ALOGD("Gestures: NEUTRAL");
michael@0 4868 #endif
michael@0 4869 mPointerGesture.activeGestureId = -1;
michael@0 4870 mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
michael@0 4871 mPointerGesture.currentGestureIdBits.clear();
michael@0 4872 }
michael@0 4873 } else if (currentFingerCount == 1) {
michael@0 4874 // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG)
michael@0 4875 // The pointer follows the active touch point.
michael@0 4876 // When in HOVER, emit HOVER_MOVE events at the pointer location.
michael@0 4877 // When in TAP_DRAG, emit MOVE events at the pointer location.
michael@0 4878 ALOG_ASSERT(activeTouchId >= 0);
michael@0 4879
michael@0 4880 mPointerGesture.currentGestureMode = PointerGesture::HOVER;
michael@0 4881 if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
michael@0 4882 if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
michael@0 4883 float x, y;
michael@0 4884 mPointerController->getPosition(&x, &y);
michael@0 4885 if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop
michael@0 4886 && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
michael@0 4887 mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
michael@0 4888 } else {
michael@0 4889 #if DEBUG_GESTURES
michael@0 4890 ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
michael@0 4891 x - mPointerGesture.tapX,
michael@0 4892 y - mPointerGesture.tapY);
michael@0 4893 #endif
michael@0 4894 }
michael@0 4895 } else {
michael@0 4896 #if DEBUG_GESTURES
michael@0 4897 ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up",
michael@0 4898 (when - mPointerGesture.tapUpTime) * 0.000001f);
michael@0 4899 #endif
michael@0 4900 }
michael@0 4901 } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) {
michael@0 4902 mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
michael@0 4903 }
michael@0 4904
michael@0 4905 if (mLastFingerIdBits.hasBit(activeTouchId)) {
michael@0 4906 const RawPointerData::Pointer& currentPointer =
michael@0 4907 mCurrentRawPointerData.pointerForId(activeTouchId);
michael@0 4908 const RawPointerData::Pointer& lastPointer =
michael@0 4909 mLastRawPointerData.pointerForId(activeTouchId);
michael@0 4910 float deltaX = (currentPointer.x - lastPointer.x)
michael@0 4911 * mPointerXMovementScale;
michael@0 4912 float deltaY = (currentPointer.y - lastPointer.y)
michael@0 4913 * mPointerYMovementScale;
michael@0 4914
michael@0 4915 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
michael@0 4916 mPointerVelocityControl.move(when, &deltaX, &deltaY);
michael@0 4917
michael@0 4918 // Move the pointer using a relative motion.
michael@0 4919 // When using spots, the hover or drag will occur at the position of the anchor spot.
michael@0 4920 mPointerController->move(deltaX, deltaY);
michael@0 4921 } else {
michael@0 4922 mPointerVelocityControl.reset();
michael@0 4923 }
michael@0 4924
michael@0 4925 bool down;
michael@0 4926 if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) {
michael@0 4927 #if DEBUG_GESTURES
michael@0 4928 ALOGD("Gestures: TAP_DRAG");
michael@0 4929 #endif
michael@0 4930 down = true;
michael@0 4931 } else {
michael@0 4932 #if DEBUG_GESTURES
michael@0 4933 ALOGD("Gestures: HOVER");
michael@0 4934 #endif
michael@0 4935 if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) {
michael@0 4936 *outFinishPreviousGesture = true;
michael@0 4937 }
michael@0 4938 mPointerGesture.activeGestureId = 0;
michael@0 4939 down = false;
michael@0 4940 }
michael@0 4941
michael@0 4942 float x, y;
michael@0 4943 mPointerController->getPosition(&x, &y);
michael@0 4944
michael@0 4945 mPointerGesture.currentGestureIdBits.clear();
michael@0 4946 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
michael@0 4947 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
michael@0 4948 mPointerGesture.currentGestureProperties[0].clear();
michael@0 4949 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
michael@0 4950 mPointerGesture.currentGestureProperties[0].toolType =
michael@0 4951 AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 4952 mPointerGesture.currentGestureCoords[0].clear();
michael@0 4953 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
michael@0 4954 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
michael@0 4955 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
michael@0 4956 down ? 1.0f : 0.0f);
michael@0 4957
michael@0 4958 if (lastFingerCount == 0 && currentFingerCount != 0) {
michael@0 4959 mPointerGesture.resetTap();
michael@0 4960 mPointerGesture.tapDownTime = when;
michael@0 4961 mPointerGesture.tapX = x;
michael@0 4962 mPointerGesture.tapY = y;
michael@0 4963 }
michael@0 4964 } else {
michael@0 4965 // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM)
michael@0 4966 // We need to provide feedback for each finger that goes down so we cannot wait
michael@0 4967 // for the fingers to move before deciding what to do.
michael@0 4968 //
michael@0 4969 // The ambiguous case is deciding what to do when there are two fingers down but they
michael@0 4970 // have not moved enough to determine whether they are part of a drag or part of a
michael@0 4971 // freeform gesture, or just a press or long-press at the pointer location.
michael@0 4972 //
michael@0 4973 // When there are two fingers we start with the PRESS hypothesis and we generate a
michael@0 4974 // down at the pointer location.
michael@0 4975 //
michael@0 4976 // When the two fingers move enough or when additional fingers are added, we make
michael@0 4977 // a decision to transition into SWIPE or FREEFORM mode accordingly.
michael@0 4978 ALOG_ASSERT(activeTouchId >= 0);
michael@0 4979
michael@0 4980 bool settled = when >= mPointerGesture.firstTouchTime
michael@0 4981 + mConfig.pointerGestureMultitouchSettleInterval;
michael@0 4982 if (mPointerGesture.lastGestureMode != PointerGesture::PRESS
michael@0 4983 && mPointerGesture.lastGestureMode != PointerGesture::SWIPE
michael@0 4984 && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
michael@0 4985 *outFinishPreviousGesture = true;
michael@0 4986 } else if (!settled && currentFingerCount > lastFingerCount) {
michael@0 4987 // Additional pointers have gone down but not yet settled.
michael@0 4988 // Reset the gesture.
michael@0 4989 #if DEBUG_GESTURES
michael@0 4990 ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, "
michael@0 4991 "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
michael@0 4992 + mConfig.pointerGestureMultitouchSettleInterval - when)
michael@0 4993 * 0.000001f);
michael@0 4994 #endif
michael@0 4995 *outCancelPreviousGesture = true;
michael@0 4996 } else {
michael@0 4997 // Continue previous gesture.
michael@0 4998 mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode;
michael@0 4999 }
michael@0 5000
michael@0 5001 if (*outFinishPreviousGesture || *outCancelPreviousGesture) {
michael@0 5002 mPointerGesture.currentGestureMode = PointerGesture::PRESS;
michael@0 5003 mPointerGesture.activeGestureId = 0;
michael@0 5004 mPointerGesture.referenceIdBits.clear();
michael@0 5005 mPointerVelocityControl.reset();
michael@0 5006
michael@0 5007 // Use the centroid and pointer location as the reference points for the gesture.
michael@0 5008 #if DEBUG_GESTURES
michael@0 5009 ALOGD("Gestures: Using centroid as reference for MULTITOUCH, "
michael@0 5010 "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
michael@0 5011 + mConfig.pointerGestureMultitouchSettleInterval - when)
michael@0 5012 * 0.000001f);
michael@0 5013 #endif
michael@0 5014 mCurrentRawPointerData.getCentroidOfTouchingPointers(
michael@0 5015 &mPointerGesture.referenceTouchX,
michael@0 5016 &mPointerGesture.referenceTouchY);
michael@0 5017 mPointerController->getPosition(&mPointerGesture.referenceGestureX,
michael@0 5018 &mPointerGesture.referenceGestureY);
michael@0 5019 }
michael@0 5020
michael@0 5021 // Clear the reference deltas for fingers not yet included in the reference calculation.
michael@0 5022 for (BitSet32 idBits(mCurrentFingerIdBits.value
michael@0 5023 & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) {
michael@0 5024 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 5025 mPointerGesture.referenceDeltas[id].dx = 0;
michael@0 5026 mPointerGesture.referenceDeltas[id].dy = 0;
michael@0 5027 }
michael@0 5028 mPointerGesture.referenceIdBits = mCurrentFingerIdBits;
michael@0 5029
michael@0 5030 // Add delta for all fingers and calculate a common movement delta.
michael@0 5031 float commonDeltaX = 0, commonDeltaY = 0;
michael@0 5032 BitSet32 commonIdBits(mLastFingerIdBits.value
michael@0 5033 & mCurrentFingerIdBits.value);
michael@0 5034 for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
michael@0 5035 bool first = (idBits == commonIdBits);
michael@0 5036 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 5037 const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id);
michael@0 5038 const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id);
michael@0 5039 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
michael@0 5040 delta.dx += cpd.x - lpd.x;
michael@0 5041 delta.dy += cpd.y - lpd.y;
michael@0 5042
michael@0 5043 if (first) {
michael@0 5044 commonDeltaX = delta.dx;
michael@0 5045 commonDeltaY = delta.dy;
michael@0 5046 } else {
michael@0 5047 commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
michael@0 5048 commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
michael@0 5049 }
michael@0 5050 }
michael@0 5051
michael@0 5052 // Consider transitions from PRESS to SWIPE or MULTITOUCH.
michael@0 5053 if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
michael@0 5054 float dist[MAX_POINTER_ID + 1];
michael@0 5055 int32_t distOverThreshold = 0;
michael@0 5056 for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
michael@0 5057 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 5058 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
michael@0 5059 dist[id] = hypotf(delta.dx * mPointerXZoomScale,
michael@0 5060 delta.dy * mPointerYZoomScale);
michael@0 5061 if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) {
michael@0 5062 distOverThreshold += 1;
michael@0 5063 }
michael@0 5064 }
michael@0 5065
michael@0 5066 // Only transition when at least two pointers have moved further than
michael@0 5067 // the minimum distance threshold.
michael@0 5068 if (distOverThreshold >= 2) {
michael@0 5069 if (currentFingerCount > 2) {
michael@0 5070 // There are more than two pointers, switch to FREEFORM.
michael@0 5071 #if DEBUG_GESTURES
michael@0 5072 ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2",
michael@0 5073 currentFingerCount);
michael@0 5074 #endif
michael@0 5075 *outCancelPreviousGesture = true;
michael@0 5076 mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
michael@0 5077 } else {
michael@0 5078 // There are exactly two pointers.
michael@0 5079 BitSet32 idBits(mCurrentFingerIdBits);
michael@0 5080 uint32_t id1 = idBits.clearFirstMarkedBit();
michael@0 5081 uint32_t id2 = idBits.firstMarkedBit();
michael@0 5082 const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1);
michael@0 5083 const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2);
michael@0 5084 float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y);
michael@0 5085 if (mutualDistance > mPointerGestureMaxSwipeWidth) {
michael@0 5086 // There are two pointers but they are too far apart for a SWIPE,
michael@0 5087 // switch to FREEFORM.
michael@0 5088 #if DEBUG_GESTURES
michael@0 5089 ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f",
michael@0 5090 mutualDistance, mPointerGestureMaxSwipeWidth);
michael@0 5091 #endif
michael@0 5092 *outCancelPreviousGesture = true;
michael@0 5093 mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
michael@0 5094 } else {
michael@0 5095 // There are two pointers. Wait for both pointers to start moving
michael@0 5096 // before deciding whether this is a SWIPE or FREEFORM gesture.
michael@0 5097 float dist1 = dist[id1];
michael@0 5098 float dist2 = dist[id2];
michael@0 5099 if (dist1 >= mConfig.pointerGestureMultitouchMinDistance
michael@0 5100 && dist2 >= mConfig.pointerGestureMultitouchMinDistance) {
michael@0 5101 // Calculate the dot product of the displacement vectors.
michael@0 5102 // When the vectors are oriented in approximately the same direction,
michael@0 5103 // the angle betweeen them is near zero and the cosine of the angle
michael@0 5104 // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
michael@0 5105 PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1];
michael@0 5106 PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2];
michael@0 5107 float dx1 = delta1.dx * mPointerXZoomScale;
michael@0 5108 float dy1 = delta1.dy * mPointerYZoomScale;
michael@0 5109 float dx2 = delta2.dx * mPointerXZoomScale;
michael@0 5110 float dy2 = delta2.dy * mPointerYZoomScale;
michael@0 5111 float dot = dx1 * dx2 + dy1 * dy2;
michael@0 5112 float cosine = dot / (dist1 * dist2); // denominator always > 0
michael@0 5113 if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) {
michael@0 5114 // Pointers are moving in the same direction. Switch to SWIPE.
michael@0 5115 #if DEBUG_GESTURES
michael@0 5116 ALOGD("Gestures: PRESS transitioned to SWIPE, "
michael@0 5117 "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
michael@0 5118 "cosine %0.3f >= %0.3f",
michael@0 5119 dist1, mConfig.pointerGestureMultitouchMinDistance,
michael@0 5120 dist2, mConfig.pointerGestureMultitouchMinDistance,
michael@0 5121 cosine, mConfig.pointerGestureSwipeTransitionAngleCosine);
michael@0 5122 #endif
michael@0 5123 mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
michael@0 5124 } else {
michael@0 5125 // Pointers are moving in different directions. Switch to FREEFORM.
michael@0 5126 #if DEBUG_GESTURES
michael@0 5127 ALOGD("Gestures: PRESS transitioned to FREEFORM, "
michael@0 5128 "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
michael@0 5129 "cosine %0.3f < %0.3f",
michael@0 5130 dist1, mConfig.pointerGestureMultitouchMinDistance,
michael@0 5131 dist2, mConfig.pointerGestureMultitouchMinDistance,
michael@0 5132 cosine, mConfig.pointerGestureSwipeTransitionAngleCosine);
michael@0 5133 #endif
michael@0 5134 *outCancelPreviousGesture = true;
michael@0 5135 mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
michael@0 5136 }
michael@0 5137 }
michael@0 5138 }
michael@0 5139 }
michael@0 5140 }
michael@0 5141 } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
michael@0 5142 // Switch from SWIPE to FREEFORM if additional pointers go down.
michael@0 5143 // Cancel previous gesture.
michael@0 5144 if (currentFingerCount > 2) {
michael@0 5145 #if DEBUG_GESTURES
michael@0 5146 ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2",
michael@0 5147 currentFingerCount);
michael@0 5148 #endif
michael@0 5149 *outCancelPreviousGesture = true;
michael@0 5150 mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
michael@0 5151 }
michael@0 5152 }
michael@0 5153
michael@0 5154 // Move the reference points based on the overall group motion of the fingers
michael@0 5155 // except in PRESS mode while waiting for a transition to occur.
michael@0 5156 if (mPointerGesture.currentGestureMode != PointerGesture::PRESS
michael@0 5157 && (commonDeltaX || commonDeltaY)) {
michael@0 5158 for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
michael@0 5159 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 5160 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
michael@0 5161 delta.dx = 0;
michael@0 5162 delta.dy = 0;
michael@0 5163 }
michael@0 5164
michael@0 5165 mPointerGesture.referenceTouchX += commonDeltaX;
michael@0 5166 mPointerGesture.referenceTouchY += commonDeltaY;
michael@0 5167
michael@0 5168 commonDeltaX *= mPointerXMovementScale;
michael@0 5169 commonDeltaY *= mPointerYMovementScale;
michael@0 5170
michael@0 5171 rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY);
michael@0 5172 mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
michael@0 5173
michael@0 5174 mPointerGesture.referenceGestureX += commonDeltaX;
michael@0 5175 mPointerGesture.referenceGestureY += commonDeltaY;
michael@0 5176 }
michael@0 5177
michael@0 5178 // Report gestures.
michael@0 5179 if (mPointerGesture.currentGestureMode == PointerGesture::PRESS
michael@0 5180 || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
michael@0 5181 // PRESS or SWIPE mode.
michael@0 5182 #if DEBUG_GESTURES
michael@0 5183 ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d,"
michael@0 5184 "activeGestureId=%d, currentTouchPointerCount=%d",
michael@0 5185 activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
michael@0 5186 #endif
michael@0 5187 ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
michael@0 5188
michael@0 5189 mPointerGesture.currentGestureIdBits.clear();
michael@0 5190 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
michael@0 5191 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
michael@0 5192 mPointerGesture.currentGestureProperties[0].clear();
michael@0 5193 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
michael@0 5194 mPointerGesture.currentGestureProperties[0].toolType =
michael@0 5195 AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 5196 mPointerGesture.currentGestureCoords[0].clear();
michael@0 5197 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
michael@0 5198 mPointerGesture.referenceGestureX);
michael@0 5199 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
michael@0 5200 mPointerGesture.referenceGestureY);
michael@0 5201 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
michael@0 5202 } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
michael@0 5203 // FREEFORM mode.
michael@0 5204 #if DEBUG_GESTURES
michael@0 5205 ALOGD("Gestures: FREEFORM activeTouchId=%d,"
michael@0 5206 "activeGestureId=%d, currentTouchPointerCount=%d",
michael@0 5207 activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
michael@0 5208 #endif
michael@0 5209 ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
michael@0 5210
michael@0 5211 mPointerGesture.currentGestureIdBits.clear();
michael@0 5212
michael@0 5213 BitSet32 mappedTouchIdBits;
michael@0 5214 BitSet32 usedGestureIdBits;
michael@0 5215 if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
michael@0 5216 // Initially, assign the active gesture id to the active touch point
michael@0 5217 // if there is one. No other touch id bits are mapped yet.
michael@0 5218 if (!*outCancelPreviousGesture) {
michael@0 5219 mappedTouchIdBits.markBit(activeTouchId);
michael@0 5220 usedGestureIdBits.markBit(mPointerGesture.activeGestureId);
michael@0 5221 mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] =
michael@0 5222 mPointerGesture.activeGestureId;
michael@0 5223 } else {
michael@0 5224 mPointerGesture.activeGestureId = -1;
michael@0 5225 }
michael@0 5226 } else {
michael@0 5227 // Otherwise, assume we mapped all touches from the previous frame.
michael@0 5228 // Reuse all mappings that are still applicable.
michael@0 5229 mappedTouchIdBits.value = mLastFingerIdBits.value
michael@0 5230 & mCurrentFingerIdBits.value;
michael@0 5231 usedGestureIdBits = mPointerGesture.lastGestureIdBits;
michael@0 5232
michael@0 5233 // Check whether we need to choose a new active gesture id because the
michael@0 5234 // current went went up.
michael@0 5235 for (BitSet32 upTouchIdBits(mLastFingerIdBits.value
michael@0 5236 & ~mCurrentFingerIdBits.value);
michael@0 5237 !upTouchIdBits.isEmpty(); ) {
michael@0 5238 uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit();
michael@0 5239 uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
michael@0 5240 if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) {
michael@0 5241 mPointerGesture.activeGestureId = -1;
michael@0 5242 break;
michael@0 5243 }
michael@0 5244 }
michael@0 5245 }
michael@0 5246
michael@0 5247 #if DEBUG_GESTURES
michael@0 5248 ALOGD("Gestures: FREEFORM follow up "
michael@0 5249 "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, "
michael@0 5250 "activeGestureId=%d",
michael@0 5251 mappedTouchIdBits.value, usedGestureIdBits.value,
michael@0 5252 mPointerGesture.activeGestureId);
michael@0 5253 #endif
michael@0 5254
michael@0 5255 BitSet32 idBits(mCurrentFingerIdBits);
michael@0 5256 for (uint32_t i = 0; i < currentFingerCount; i++) {
michael@0 5257 uint32_t touchId = idBits.clearFirstMarkedBit();
michael@0 5258 uint32_t gestureId;
michael@0 5259 if (!mappedTouchIdBits.hasBit(touchId)) {
michael@0 5260 gestureId = usedGestureIdBits.markFirstUnmarkedBit();
michael@0 5261 mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId;
michael@0 5262 #if DEBUG_GESTURES
michael@0 5263 ALOGD("Gestures: FREEFORM "
michael@0 5264 "new mapping for touch id %d -> gesture id %d",
michael@0 5265 touchId, gestureId);
michael@0 5266 #endif
michael@0 5267 } else {
michael@0 5268 gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId];
michael@0 5269 #if DEBUG_GESTURES
michael@0 5270 ALOGD("Gestures: FREEFORM "
michael@0 5271 "existing mapping for touch id %d -> gesture id %d",
michael@0 5272 touchId, gestureId);
michael@0 5273 #endif
michael@0 5274 }
michael@0 5275 mPointerGesture.currentGestureIdBits.markBit(gestureId);
michael@0 5276 mPointerGesture.currentGestureIdToIndex[gestureId] = i;
michael@0 5277
michael@0 5278 const RawPointerData::Pointer& pointer =
michael@0 5279 mCurrentRawPointerData.pointerForId(touchId);
michael@0 5280 float deltaX = (pointer.x - mPointerGesture.referenceTouchX)
michael@0 5281 * mPointerXZoomScale;
michael@0 5282 float deltaY = (pointer.y - mPointerGesture.referenceTouchY)
michael@0 5283 * mPointerYZoomScale;
michael@0 5284 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
michael@0 5285
michael@0 5286 mPointerGesture.currentGestureProperties[i].clear();
michael@0 5287 mPointerGesture.currentGestureProperties[i].id = gestureId;
michael@0 5288 mPointerGesture.currentGestureProperties[i].toolType =
michael@0 5289 AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 5290 mPointerGesture.currentGestureCoords[i].clear();
michael@0 5291 mPointerGesture.currentGestureCoords[i].setAxisValue(
michael@0 5292 AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX);
michael@0 5293 mPointerGesture.currentGestureCoords[i].setAxisValue(
michael@0 5294 AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY);
michael@0 5295 mPointerGesture.currentGestureCoords[i].setAxisValue(
michael@0 5296 AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
michael@0 5297 }
michael@0 5298
michael@0 5299 if (mPointerGesture.activeGestureId < 0) {
michael@0 5300 mPointerGesture.activeGestureId =
michael@0 5301 mPointerGesture.currentGestureIdBits.firstMarkedBit();
michael@0 5302 #if DEBUG_GESTURES
michael@0 5303 ALOGD("Gestures: FREEFORM new "
michael@0 5304 "activeGestureId=%d", mPointerGesture.activeGestureId);
michael@0 5305 #endif
michael@0 5306 }
michael@0 5307 }
michael@0 5308 }
michael@0 5309
michael@0 5310 mPointerController->setButtonState(mCurrentButtonState);
michael@0 5311
michael@0 5312 #if DEBUG_GESTURES
michael@0 5313 ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
michael@0 5314 "currentGestureMode=%d, currentGestureIdBits=0x%08x, "
michael@0 5315 "lastGestureMode=%d, lastGestureIdBits=0x%08x",
michael@0 5316 toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture),
michael@0 5317 mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value,
michael@0 5318 mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value);
michael@0 5319 for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) {
michael@0 5320 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 5321 uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
michael@0 5322 const PointerProperties& properties = mPointerGesture.currentGestureProperties[index];
michael@0 5323 const PointerCoords& coords = mPointerGesture.currentGestureCoords[index];
michael@0 5324 ALOGD(" currentGesture[%d]: index=%d, toolType=%d, "
michael@0 5325 "x=%0.3f, y=%0.3f, pressure=%0.3f",
michael@0 5326 id, index, properties.toolType,
michael@0 5327 coords.getAxisValue(AMOTION_EVENT_AXIS_X),
michael@0 5328 coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
michael@0 5329 coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
michael@0 5330 }
michael@0 5331 for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) {
michael@0 5332 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 5333 uint32_t index = mPointerGesture.lastGestureIdToIndex[id];
michael@0 5334 const PointerProperties& properties = mPointerGesture.lastGestureProperties[index];
michael@0 5335 const PointerCoords& coords = mPointerGesture.lastGestureCoords[index];
michael@0 5336 ALOGD(" lastGesture[%d]: index=%d, toolType=%d, "
michael@0 5337 "x=%0.3f, y=%0.3f, pressure=%0.3f",
michael@0 5338 id, index, properties.toolType,
michael@0 5339 coords.getAxisValue(AMOTION_EVENT_AXIS_X),
michael@0 5340 coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
michael@0 5341 coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
michael@0 5342 }
michael@0 5343 #endif
michael@0 5344 return true;
michael@0 5345 }
michael@0 5346
michael@0 5347 void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) {
michael@0 5348 mPointerSimple.currentCoords.clear();
michael@0 5349 mPointerSimple.currentProperties.clear();
michael@0 5350
michael@0 5351 bool down, hovering;
michael@0 5352 if (!mCurrentStylusIdBits.isEmpty()) {
michael@0 5353 uint32_t id = mCurrentStylusIdBits.firstMarkedBit();
michael@0 5354 uint32_t index = mCurrentCookedPointerData.idToIndex[id];
michael@0 5355 float x = mCurrentCookedPointerData.pointerCoords[index].getX();
michael@0 5356 float y = mCurrentCookedPointerData.pointerCoords[index].getY();
michael@0 5357 mPointerController->setPosition(x, y);
michael@0 5358
michael@0 5359 hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id);
michael@0 5360 down = !hovering;
michael@0 5361
michael@0 5362 mPointerController->getPosition(&x, &y);
michael@0 5363 mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]);
michael@0 5364 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
michael@0 5365 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
michael@0 5366 mPointerSimple.currentProperties.id = 0;
michael@0 5367 mPointerSimple.currentProperties.toolType =
michael@0 5368 mCurrentCookedPointerData.pointerProperties[index].toolType;
michael@0 5369 } else {
michael@0 5370 down = false;
michael@0 5371 hovering = false;
michael@0 5372 }
michael@0 5373
michael@0 5374 dispatchPointerSimple(when, policyFlags, down, hovering);
michael@0 5375 }
michael@0 5376
michael@0 5377 void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) {
michael@0 5378 abortPointerSimple(when, policyFlags);
michael@0 5379 }
michael@0 5380
michael@0 5381 void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) {
michael@0 5382 mPointerSimple.currentCoords.clear();
michael@0 5383 mPointerSimple.currentProperties.clear();
michael@0 5384
michael@0 5385 bool down, hovering;
michael@0 5386 if (!mCurrentMouseIdBits.isEmpty()) {
michael@0 5387 uint32_t id = mCurrentMouseIdBits.firstMarkedBit();
michael@0 5388 uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id];
michael@0 5389 if (mLastMouseIdBits.hasBit(id)) {
michael@0 5390 uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id];
michael@0 5391 float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x
michael@0 5392 - mLastRawPointerData.pointers[lastIndex].x)
michael@0 5393 * mPointerXMovementScale;
michael@0 5394 float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y
michael@0 5395 - mLastRawPointerData.pointers[lastIndex].y)
michael@0 5396 * mPointerYMovementScale;
michael@0 5397
michael@0 5398 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
michael@0 5399 mPointerVelocityControl.move(when, &deltaX, &deltaY);
michael@0 5400
michael@0 5401 mPointerController->move(deltaX, deltaY);
michael@0 5402 } else {
michael@0 5403 mPointerVelocityControl.reset();
michael@0 5404 }
michael@0 5405
michael@0 5406 down = isPointerDown(mCurrentButtonState);
michael@0 5407 hovering = !down;
michael@0 5408
michael@0 5409 float x, y;
michael@0 5410 mPointerController->getPosition(&x, &y);
michael@0 5411 mPointerSimple.currentCoords.copyFrom(
michael@0 5412 mCurrentCookedPointerData.pointerCoords[currentIndex]);
michael@0 5413 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
michael@0 5414 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
michael@0 5415 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
michael@0 5416 hovering ? 0.0f : 1.0f);
michael@0 5417 mPointerSimple.currentProperties.id = 0;
michael@0 5418 mPointerSimple.currentProperties.toolType =
michael@0 5419 mCurrentCookedPointerData.pointerProperties[currentIndex].toolType;
michael@0 5420 } else {
michael@0 5421 mPointerVelocityControl.reset();
michael@0 5422
michael@0 5423 down = false;
michael@0 5424 hovering = false;
michael@0 5425 }
michael@0 5426
michael@0 5427 dispatchPointerSimple(when, policyFlags, down, hovering);
michael@0 5428 }
michael@0 5429
michael@0 5430 void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) {
michael@0 5431 abortPointerSimple(when, policyFlags);
michael@0 5432
michael@0 5433 mPointerVelocityControl.reset();
michael@0 5434 }
michael@0 5435
michael@0 5436 void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
michael@0 5437 bool down, bool hovering) {
michael@0 5438 int32_t metaState = getContext()->getGlobalMetaState();
michael@0 5439
michael@0 5440 if (mPointerController != NULL) {
michael@0 5441 if (down || hovering) {
michael@0 5442 mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
michael@0 5443 mPointerController->clearSpots();
michael@0 5444 mPointerController->setButtonState(mCurrentButtonState);
michael@0 5445 mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
michael@0 5446 } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
michael@0 5447 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
michael@0 5448 }
michael@0 5449 }
michael@0 5450
michael@0 5451 if (mPointerSimple.down && !down) {
michael@0 5452 mPointerSimple.down = false;
michael@0 5453
michael@0 5454 // Send up.
michael@0 5455 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 5456 AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0,
michael@0 5457 mViewport.displayId,
michael@0 5458 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
michael@0 5459 mOrientedXPrecision, mOrientedYPrecision,
michael@0 5460 mPointerSimple.downTime);
michael@0 5461 getListener()->notifyMotion(&args);
michael@0 5462 }
michael@0 5463
michael@0 5464 if (mPointerSimple.hovering && !hovering) {
michael@0 5465 mPointerSimple.hovering = false;
michael@0 5466
michael@0 5467 // Send hover exit.
michael@0 5468 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 5469 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
michael@0 5470 mViewport.displayId,
michael@0 5471 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
michael@0 5472 mOrientedXPrecision, mOrientedYPrecision,
michael@0 5473 mPointerSimple.downTime);
michael@0 5474 getListener()->notifyMotion(&args);
michael@0 5475 }
michael@0 5476
michael@0 5477 if (down) {
michael@0 5478 if (!mPointerSimple.down) {
michael@0 5479 mPointerSimple.down = true;
michael@0 5480 mPointerSimple.downTime = when;
michael@0 5481
michael@0 5482 // Send down.
michael@0 5483 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 5484 AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0,
michael@0 5485 mViewport.displayId,
michael@0 5486 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
michael@0 5487 mOrientedXPrecision, mOrientedYPrecision,
michael@0 5488 mPointerSimple.downTime);
michael@0 5489 getListener()->notifyMotion(&args);
michael@0 5490 }
michael@0 5491
michael@0 5492 // Send move.
michael@0 5493 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 5494 AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0,
michael@0 5495 mViewport.displayId,
michael@0 5496 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
michael@0 5497 mOrientedXPrecision, mOrientedYPrecision,
michael@0 5498 mPointerSimple.downTime);
michael@0 5499 getListener()->notifyMotion(&args);
michael@0 5500 }
michael@0 5501
michael@0 5502 if (hovering) {
michael@0 5503 if (!mPointerSimple.hovering) {
michael@0 5504 mPointerSimple.hovering = true;
michael@0 5505
michael@0 5506 // Send hover enter.
michael@0 5507 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 5508 AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
michael@0 5509 mViewport.displayId,
michael@0 5510 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
michael@0 5511 mOrientedXPrecision, mOrientedYPrecision,
michael@0 5512 mPointerSimple.downTime);
michael@0 5513 getListener()->notifyMotion(&args);
michael@0 5514 }
michael@0 5515
michael@0 5516 // Send hover move.
michael@0 5517 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 5518 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
michael@0 5519 mViewport.displayId,
michael@0 5520 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
michael@0 5521 mOrientedXPrecision, mOrientedYPrecision,
michael@0 5522 mPointerSimple.downTime);
michael@0 5523 getListener()->notifyMotion(&args);
michael@0 5524 }
michael@0 5525
michael@0 5526 if (mCurrentRawVScroll || mCurrentRawHScroll) {
michael@0 5527 float vscroll = mCurrentRawVScroll;
michael@0 5528 float hscroll = mCurrentRawHScroll;
michael@0 5529 mWheelYVelocityControl.move(when, NULL, &vscroll);
michael@0 5530 mWheelXVelocityControl.move(when, &hscroll, NULL);
michael@0 5531
michael@0 5532 // Send scroll.
michael@0 5533 PointerCoords pointerCoords;
michael@0 5534 pointerCoords.copyFrom(mPointerSimple.currentCoords);
michael@0 5535 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
michael@0 5536 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
michael@0 5537
michael@0 5538 NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
michael@0 5539 AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0,
michael@0 5540 mViewport.displayId,
michael@0 5541 1, &mPointerSimple.currentProperties, &pointerCoords,
michael@0 5542 mOrientedXPrecision, mOrientedYPrecision,
michael@0 5543 mPointerSimple.downTime);
michael@0 5544 getListener()->notifyMotion(&args);
michael@0 5545 }
michael@0 5546
michael@0 5547 // Save state.
michael@0 5548 if (down || hovering) {
michael@0 5549 mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords);
michael@0 5550 mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties);
michael@0 5551 } else {
michael@0 5552 mPointerSimple.reset();
michael@0 5553 }
michael@0 5554 }
michael@0 5555
michael@0 5556 void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) {
michael@0 5557 mPointerSimple.currentCoords.clear();
michael@0 5558 mPointerSimple.currentProperties.clear();
michael@0 5559
michael@0 5560 dispatchPointerSimple(when, policyFlags, false, false);
michael@0 5561 }
michael@0 5562
michael@0 5563 void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
michael@0 5564 int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
michael@0 5565 const PointerProperties* properties, const PointerCoords* coords,
michael@0 5566 const uint32_t* idToIndex, BitSet32 idBits,
michael@0 5567 int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
michael@0 5568 PointerCoords pointerCoords[MAX_POINTERS];
michael@0 5569 PointerProperties pointerProperties[MAX_POINTERS];
michael@0 5570 uint32_t pointerCount = 0;
michael@0 5571 while (!idBits.isEmpty()) {
michael@0 5572 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 5573 uint32_t index = idToIndex[id];
michael@0 5574 pointerProperties[pointerCount].copyFrom(properties[index]);
michael@0 5575 pointerCoords[pointerCount].copyFrom(coords[index]);
michael@0 5576
michael@0 5577 if (changedId >= 0 && id == uint32_t(changedId)) {
michael@0 5578 action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
michael@0 5579 }
michael@0 5580
michael@0 5581 pointerCount += 1;
michael@0 5582 }
michael@0 5583
michael@0 5584 ALOG_ASSERT(pointerCount != 0);
michael@0 5585
michael@0 5586 if (changedId >= 0 && pointerCount == 1) {
michael@0 5587 // Replace initial down and final up action.
michael@0 5588 // We can compare the action without masking off the changed pointer index
michael@0 5589 // because we know the index is 0.
michael@0 5590 if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
michael@0 5591 action = AMOTION_EVENT_ACTION_DOWN;
michael@0 5592 } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
michael@0 5593 action = AMOTION_EVENT_ACTION_UP;
michael@0 5594 } else {
michael@0 5595 // Can't happen.
michael@0 5596 ALOG_ASSERT(false);
michael@0 5597 }
michael@0 5598 }
michael@0 5599
michael@0 5600 NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
michael@0 5601 action, flags, metaState, buttonState, edgeFlags,
michael@0 5602 mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
michael@0 5603 xPrecision, yPrecision, downTime);
michael@0 5604 getListener()->notifyMotion(&args);
michael@0 5605 }
michael@0 5606
michael@0 5607 bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties,
michael@0 5608 const PointerCoords* inCoords, const uint32_t* inIdToIndex,
michael@0 5609 PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex,
michael@0 5610 BitSet32 idBits) const {
michael@0 5611 bool changed = false;
michael@0 5612 while (!idBits.isEmpty()) {
michael@0 5613 uint32_t id = idBits.clearFirstMarkedBit();
michael@0 5614 uint32_t inIndex = inIdToIndex[id];
michael@0 5615 uint32_t outIndex = outIdToIndex[id];
michael@0 5616
michael@0 5617 const PointerProperties& curInProperties = inProperties[inIndex];
michael@0 5618 const PointerCoords& curInCoords = inCoords[inIndex];
michael@0 5619 PointerProperties& curOutProperties = outProperties[outIndex];
michael@0 5620 PointerCoords& curOutCoords = outCoords[outIndex];
michael@0 5621
michael@0 5622 if (curInProperties != curOutProperties) {
michael@0 5623 curOutProperties.copyFrom(curInProperties);
michael@0 5624 changed = true;
michael@0 5625 }
michael@0 5626
michael@0 5627 if (curInCoords != curOutCoords) {
michael@0 5628 curOutCoords.copyFrom(curInCoords);
michael@0 5629 changed = true;
michael@0 5630 }
michael@0 5631 }
michael@0 5632 return changed;
michael@0 5633 }
michael@0 5634
michael@0 5635 void TouchInputMapper::fadePointer() {
michael@0 5636 if (mPointerController != NULL) {
michael@0 5637 mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
michael@0 5638 }
michael@0 5639 }
michael@0 5640
michael@0 5641 bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
michael@0 5642 return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue
michael@0 5643 && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue;
michael@0 5644 }
michael@0 5645
michael@0 5646 const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(
michael@0 5647 int32_t x, int32_t y) {
michael@0 5648 size_t numVirtualKeys = mVirtualKeys.size();
michael@0 5649 for (size_t i = 0; i < numVirtualKeys; i++) {
michael@0 5650 const VirtualKey& virtualKey = mVirtualKeys[i];
michael@0 5651
michael@0 5652 #if DEBUG_VIRTUAL_KEYS
michael@0 5653 ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
michael@0 5654 "left=%d, top=%d, right=%d, bottom=%d",
michael@0 5655 x, y,
michael@0 5656 virtualKey.keyCode, virtualKey.scanCode,
michael@0 5657 virtualKey.hitLeft, virtualKey.hitTop,
michael@0 5658 virtualKey.hitRight, virtualKey.hitBottom);
michael@0 5659 #endif
michael@0 5660
michael@0 5661 if (virtualKey.isHit(x, y)) {
michael@0 5662 return & virtualKey;
michael@0 5663 }
michael@0 5664 }
michael@0 5665
michael@0 5666 return NULL;
michael@0 5667 }
michael@0 5668
michael@0 5669 void TouchInputMapper::assignPointerIds() {
michael@0 5670 uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
michael@0 5671 uint32_t lastPointerCount = mLastRawPointerData.pointerCount;
michael@0 5672
michael@0 5673 mCurrentRawPointerData.clearIdBits();
michael@0 5674
michael@0 5675 if (currentPointerCount == 0) {
michael@0 5676 // No pointers to assign.
michael@0 5677 return;
michael@0 5678 }
michael@0 5679
michael@0 5680 if (lastPointerCount == 0) {
michael@0 5681 // All pointers are new.
michael@0 5682 for (uint32_t i = 0; i < currentPointerCount; i++) {
michael@0 5683 uint32_t id = i;
michael@0 5684 mCurrentRawPointerData.pointers[i].id = id;
michael@0 5685 mCurrentRawPointerData.idToIndex[id] = i;
michael@0 5686 mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i));
michael@0 5687 }
michael@0 5688 return;
michael@0 5689 }
michael@0 5690
michael@0 5691 if (currentPointerCount == 1 && lastPointerCount == 1
michael@0 5692 && mCurrentRawPointerData.pointers[0].toolType
michael@0 5693 == mLastRawPointerData.pointers[0].toolType) {
michael@0 5694 // Only one pointer and no change in count so it must have the same id as before.
michael@0 5695 uint32_t id = mLastRawPointerData.pointers[0].id;
michael@0 5696 mCurrentRawPointerData.pointers[0].id = id;
michael@0 5697 mCurrentRawPointerData.idToIndex[id] = 0;
michael@0 5698 mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0));
michael@0 5699 return;
michael@0 5700 }
michael@0 5701
michael@0 5702 // General case.
michael@0 5703 // We build a heap of squared euclidean distances between current and last pointers
michael@0 5704 // associated with the current and last pointer indices. Then, we find the best
michael@0 5705 // match (by distance) for each current pointer.
michael@0 5706 // The pointers must have the same tool type but it is possible for them to
michael@0 5707 // transition from hovering to touching or vice-versa while retaining the same id.
michael@0 5708 PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
michael@0 5709
michael@0 5710 uint32_t heapSize = 0;
michael@0 5711 for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
michael@0 5712 currentPointerIndex++) {
michael@0 5713 for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
michael@0 5714 lastPointerIndex++) {
michael@0 5715 const RawPointerData::Pointer& currentPointer =
michael@0 5716 mCurrentRawPointerData.pointers[currentPointerIndex];
michael@0 5717 const RawPointerData::Pointer& lastPointer =
michael@0 5718 mLastRawPointerData.pointers[lastPointerIndex];
michael@0 5719 if (currentPointer.toolType == lastPointer.toolType) {
michael@0 5720 int64_t deltaX = currentPointer.x - lastPointer.x;
michael@0 5721 int64_t deltaY = currentPointer.y - lastPointer.y;
michael@0 5722
michael@0 5723 uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
michael@0 5724
michael@0 5725 // Insert new element into the heap (sift up).
michael@0 5726 heap[heapSize].currentPointerIndex = currentPointerIndex;
michael@0 5727 heap[heapSize].lastPointerIndex = lastPointerIndex;
michael@0 5728 heap[heapSize].distance = distance;
michael@0 5729 heapSize += 1;
michael@0 5730 }
michael@0 5731 }
michael@0 5732 }
michael@0 5733
michael@0 5734 // Heapify
michael@0 5735 for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
michael@0 5736 startIndex -= 1;
michael@0 5737 for (uint32_t parentIndex = startIndex; ;) {
michael@0 5738 uint32_t childIndex = parentIndex * 2 + 1;
michael@0 5739 if (childIndex >= heapSize) {
michael@0 5740 break;
michael@0 5741 }
michael@0 5742
michael@0 5743 if (childIndex + 1 < heapSize
michael@0 5744 && heap[childIndex + 1].distance < heap[childIndex].distance) {
michael@0 5745 childIndex += 1;
michael@0 5746 }
michael@0 5747
michael@0 5748 if (heap[parentIndex].distance <= heap[childIndex].distance) {
michael@0 5749 break;
michael@0 5750 }
michael@0 5751
michael@0 5752 swap(heap[parentIndex], heap[childIndex]);
michael@0 5753 parentIndex = childIndex;
michael@0 5754 }
michael@0 5755 }
michael@0 5756
michael@0 5757 #if DEBUG_POINTER_ASSIGNMENT
michael@0 5758 ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize);
michael@0 5759 for (size_t i = 0; i < heapSize; i++) {
michael@0 5760 ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
michael@0 5761 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
michael@0 5762 heap[i].distance);
michael@0 5763 }
michael@0 5764 #endif
michael@0 5765
michael@0 5766 // Pull matches out by increasing order of distance.
michael@0 5767 // To avoid reassigning pointers that have already been matched, the loop keeps track
michael@0 5768 // of which last and current pointers have been matched using the matchedXXXBits variables.
michael@0 5769 // It also tracks the used pointer id bits.
michael@0 5770 BitSet32 matchedLastBits(0);
michael@0 5771 BitSet32 matchedCurrentBits(0);
michael@0 5772 BitSet32 usedIdBits(0);
michael@0 5773 bool first = true;
michael@0 5774 for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) {
michael@0 5775 while (heapSize > 0) {
michael@0 5776 if (first) {
michael@0 5777 // The first time through the loop, we just consume the root element of
michael@0 5778 // the heap (the one with smallest distance).
michael@0 5779 first = false;
michael@0 5780 } else {
michael@0 5781 // Previous iterations consumed the root element of the heap.
michael@0 5782 // Pop root element off of the heap (sift down).
michael@0 5783 heap[0] = heap[heapSize];
michael@0 5784 for (uint32_t parentIndex = 0; ;) {
michael@0 5785 uint32_t childIndex = parentIndex * 2 + 1;
michael@0 5786 if (childIndex >= heapSize) {
michael@0 5787 break;
michael@0 5788 }
michael@0 5789
michael@0 5790 if (childIndex + 1 < heapSize
michael@0 5791 && heap[childIndex + 1].distance < heap[childIndex].distance) {
michael@0 5792 childIndex += 1;
michael@0 5793 }
michael@0 5794
michael@0 5795 if (heap[parentIndex].distance <= heap[childIndex].distance) {
michael@0 5796 break;
michael@0 5797 }
michael@0 5798
michael@0 5799 swap(heap[parentIndex], heap[childIndex]);
michael@0 5800 parentIndex = childIndex;
michael@0 5801 }
michael@0 5802
michael@0 5803 #if DEBUG_POINTER_ASSIGNMENT
michael@0 5804 ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize);
michael@0 5805 for (size_t i = 0; i < heapSize; i++) {
michael@0 5806 ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
michael@0 5807 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
michael@0 5808 heap[i].distance);
michael@0 5809 }
michael@0 5810 #endif
michael@0 5811 }
michael@0 5812
michael@0 5813 heapSize -= 1;
michael@0 5814
michael@0 5815 uint32_t currentPointerIndex = heap[0].currentPointerIndex;
michael@0 5816 if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
michael@0 5817
michael@0 5818 uint32_t lastPointerIndex = heap[0].lastPointerIndex;
michael@0 5819 if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
michael@0 5820
michael@0 5821 matchedCurrentBits.markBit(currentPointerIndex);
michael@0 5822 matchedLastBits.markBit(lastPointerIndex);
michael@0 5823
michael@0 5824 uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id;
michael@0 5825 mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
michael@0 5826 mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
michael@0 5827 mCurrentRawPointerData.markIdBit(id,
michael@0 5828 mCurrentRawPointerData.isHovering(currentPointerIndex));
michael@0 5829 usedIdBits.markBit(id);
michael@0 5830
michael@0 5831 #if DEBUG_POINTER_ASSIGNMENT
michael@0 5832 ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
michael@0 5833 lastPointerIndex, currentPointerIndex, id, heap[0].distance);
michael@0 5834 #endif
michael@0 5835 break;
michael@0 5836 }
michael@0 5837 }
michael@0 5838
michael@0 5839 // Assign fresh ids to pointers that were not matched in the process.
michael@0 5840 for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) {
michael@0 5841 uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit();
michael@0 5842 uint32_t id = usedIdBits.markFirstUnmarkedBit();
michael@0 5843
michael@0 5844 mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
michael@0 5845 mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
michael@0 5846 mCurrentRawPointerData.markIdBit(id,
michael@0 5847 mCurrentRawPointerData.isHovering(currentPointerIndex));
michael@0 5848
michael@0 5849 #if DEBUG_POINTER_ASSIGNMENT
michael@0 5850 ALOGD("assignPointerIds - assigned: cur=%d, id=%d",
michael@0 5851 currentPointerIndex, id);
michael@0 5852 #endif
michael@0 5853 }
michael@0 5854 }
michael@0 5855
michael@0 5856 int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
michael@0 5857 if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) {
michael@0 5858 return AKEY_STATE_VIRTUAL;
michael@0 5859 }
michael@0 5860
michael@0 5861 size_t numVirtualKeys = mVirtualKeys.size();
michael@0 5862 for (size_t i = 0; i < numVirtualKeys; i++) {
michael@0 5863 const VirtualKey& virtualKey = mVirtualKeys[i];
michael@0 5864 if (virtualKey.keyCode == keyCode) {
michael@0 5865 return AKEY_STATE_UP;
michael@0 5866 }
michael@0 5867 }
michael@0 5868
michael@0 5869 return AKEY_STATE_UNKNOWN;
michael@0 5870 }
michael@0 5871
michael@0 5872 int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
michael@0 5873 if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) {
michael@0 5874 return AKEY_STATE_VIRTUAL;
michael@0 5875 }
michael@0 5876
michael@0 5877 size_t numVirtualKeys = mVirtualKeys.size();
michael@0 5878 for (size_t i = 0; i < numVirtualKeys; i++) {
michael@0 5879 const VirtualKey& virtualKey = mVirtualKeys[i];
michael@0 5880 if (virtualKey.scanCode == scanCode) {
michael@0 5881 return AKEY_STATE_UP;
michael@0 5882 }
michael@0 5883 }
michael@0 5884
michael@0 5885 return AKEY_STATE_UNKNOWN;
michael@0 5886 }
michael@0 5887
michael@0 5888 bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
michael@0 5889 const int32_t* keyCodes, uint8_t* outFlags) {
michael@0 5890 size_t numVirtualKeys = mVirtualKeys.size();
michael@0 5891 for (size_t i = 0; i < numVirtualKeys; i++) {
michael@0 5892 const VirtualKey& virtualKey = mVirtualKeys[i];
michael@0 5893
michael@0 5894 for (size_t i = 0; i < numCodes; i++) {
michael@0 5895 if (virtualKey.keyCode == keyCodes[i]) {
michael@0 5896 outFlags[i] = 1;
michael@0 5897 }
michael@0 5898 }
michael@0 5899 }
michael@0 5900
michael@0 5901 return true;
michael@0 5902 }
michael@0 5903
michael@0 5904
michael@0 5905 // --- SingleTouchInputMapper ---
michael@0 5906
michael@0 5907 SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) :
michael@0 5908 TouchInputMapper(device) {
michael@0 5909 }
michael@0 5910
michael@0 5911 SingleTouchInputMapper::~SingleTouchInputMapper() {
michael@0 5912 }
michael@0 5913
michael@0 5914 void SingleTouchInputMapper::reset(nsecs_t when) {
michael@0 5915 mSingleTouchMotionAccumulator.reset(getDevice());
michael@0 5916
michael@0 5917 TouchInputMapper::reset(when);
michael@0 5918 }
michael@0 5919
michael@0 5920 void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
michael@0 5921 TouchInputMapper::process(rawEvent);
michael@0 5922
michael@0 5923 mSingleTouchMotionAccumulator.process(rawEvent);
michael@0 5924 }
michael@0 5925
michael@0 5926 void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
michael@0 5927 if (mTouchButtonAccumulator.isToolActive()) {
michael@0 5928 mCurrentRawPointerData.pointerCount = 1;
michael@0 5929 mCurrentRawPointerData.idToIndex[0] = 0;
michael@0 5930
michael@0 5931 bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
michael@0 5932 && (mTouchButtonAccumulator.isHovering()
michael@0 5933 || (mRawPointerAxes.pressure.valid
michael@0 5934 && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0));
michael@0 5935 mCurrentRawPointerData.markIdBit(0, isHovering);
michael@0 5936
michael@0 5937 RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0];
michael@0 5938 outPointer.id = 0;
michael@0 5939 outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();
michael@0 5940 outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();
michael@0 5941 outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
michael@0 5942 outPointer.touchMajor = 0;
michael@0 5943 outPointer.touchMinor = 0;
michael@0 5944 outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
michael@0 5945 outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
michael@0 5946 outPointer.orientation = 0;
michael@0 5947 outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance();
michael@0 5948 outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX();
michael@0 5949 outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY();
michael@0 5950 outPointer.toolType = mTouchButtonAccumulator.getToolType();
michael@0 5951 if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
michael@0 5952 outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 5953 }
michael@0 5954 outPointer.isHovering = isHovering;
michael@0 5955 }
michael@0 5956 }
michael@0 5957
michael@0 5958 void SingleTouchInputMapper::configureRawPointerAxes() {
michael@0 5959 TouchInputMapper::configureRawPointerAxes();
michael@0 5960
michael@0 5961 getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x);
michael@0 5962 getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y);
michael@0 5963 getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure);
michael@0 5964 getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor);
michael@0 5965 getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance);
michael@0 5966 getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX);
michael@0 5967 getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY);
michael@0 5968 }
michael@0 5969
michael@0 5970 bool SingleTouchInputMapper::hasStylus() const {
michael@0 5971 return mTouchButtonAccumulator.hasStylus();
michael@0 5972 }
michael@0 5973
michael@0 5974
michael@0 5975 // --- MultiTouchInputMapper ---
michael@0 5976
michael@0 5977 MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) :
michael@0 5978 TouchInputMapper(device) {
michael@0 5979 }
michael@0 5980
michael@0 5981 MultiTouchInputMapper::~MultiTouchInputMapper() {
michael@0 5982 }
michael@0 5983
michael@0 5984 void MultiTouchInputMapper::reset(nsecs_t when) {
michael@0 5985 mMultiTouchMotionAccumulator.reset(getDevice());
michael@0 5986
michael@0 5987 mPointerIdBits.clear();
michael@0 5988
michael@0 5989 TouchInputMapper::reset(when);
michael@0 5990 }
michael@0 5991
michael@0 5992 void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
michael@0 5993 TouchInputMapper::process(rawEvent);
michael@0 5994
michael@0 5995 mMultiTouchMotionAccumulator.process(rawEvent);
michael@0 5996 }
michael@0 5997
michael@0 5998 void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
michael@0 5999 size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
michael@0 6000 size_t outCount = 0;
michael@0 6001 BitSet32 newPointerIdBits;
michael@0 6002
michael@0 6003 for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
michael@0 6004 const MultiTouchMotionAccumulator::Slot* inSlot =
michael@0 6005 mMultiTouchMotionAccumulator.getSlot(inIndex);
michael@0 6006 if (!inSlot->isInUse()) {
michael@0 6007 continue;
michael@0 6008 }
michael@0 6009
michael@0 6010 if (outCount >= MAX_POINTERS) {
michael@0 6011 #if DEBUG_POINTERS
michael@0 6012 ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
michael@0 6013 "ignoring the rest.",
michael@0 6014 getDeviceName().string(), MAX_POINTERS);
michael@0 6015 #endif
michael@0 6016 break; // too many fingers!
michael@0 6017 }
michael@0 6018
michael@0 6019 RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount];
michael@0 6020 outPointer.x = inSlot->getX();
michael@0 6021 outPointer.y = inSlot->getY();
michael@0 6022 outPointer.pressure = inSlot->getPressure();
michael@0 6023 outPointer.touchMajor = inSlot->getTouchMajor();
michael@0 6024 outPointer.touchMinor = inSlot->getTouchMinor();
michael@0 6025 outPointer.toolMajor = inSlot->getToolMajor();
michael@0 6026 outPointer.toolMinor = inSlot->getToolMinor();
michael@0 6027 outPointer.orientation = inSlot->getOrientation();
michael@0 6028 outPointer.distance = inSlot->getDistance();
michael@0 6029 outPointer.tiltX = 0;
michael@0 6030 outPointer.tiltY = 0;
michael@0 6031
michael@0 6032 outPointer.toolType = inSlot->getToolType();
michael@0 6033 if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
michael@0 6034 outPointer.toolType = mTouchButtonAccumulator.getToolType();
michael@0 6035 if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
michael@0 6036 outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
michael@0 6037 }
michael@0 6038 }
michael@0 6039
michael@0 6040 bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
michael@0 6041 && (mTouchButtonAccumulator.isHovering()
michael@0 6042 || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0));
michael@0 6043 outPointer.isHovering = isHovering;
michael@0 6044
michael@0 6045 // Assign pointer id using tracking id if available.
michael@0 6046 if (*outHavePointerIds) {
michael@0 6047 int32_t trackingId = inSlot->getTrackingId();
michael@0 6048 int32_t id = -1;
michael@0 6049 if (trackingId >= 0) {
michael@0 6050 for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
michael@0 6051 uint32_t n = idBits.clearFirstMarkedBit();
michael@0 6052 if (mPointerTrackingIdMap[n] == trackingId) {
michael@0 6053 id = n;
michael@0 6054 }
michael@0 6055 }
michael@0 6056
michael@0 6057 if (id < 0 && !mPointerIdBits.isFull()) {
michael@0 6058 id = mPointerIdBits.markFirstUnmarkedBit();
michael@0 6059 mPointerTrackingIdMap[id] = trackingId;
michael@0 6060 }
michael@0 6061 }
michael@0 6062 if (id < 0) {
michael@0 6063 *outHavePointerIds = false;
michael@0 6064 mCurrentRawPointerData.clearIdBits();
michael@0 6065 newPointerIdBits.clear();
michael@0 6066 } else {
michael@0 6067 outPointer.id = id;
michael@0 6068 mCurrentRawPointerData.idToIndex[id] = outCount;
michael@0 6069 mCurrentRawPointerData.markIdBit(id, isHovering);
michael@0 6070 newPointerIdBits.markBit(id);
michael@0 6071 }
michael@0 6072 }
michael@0 6073
michael@0 6074 outCount += 1;
michael@0 6075 }
michael@0 6076
michael@0 6077 mCurrentRawPointerData.pointerCount = outCount;
michael@0 6078 mPointerIdBits = newPointerIdBits;
michael@0 6079
michael@0 6080 mMultiTouchMotionAccumulator.finishSync();
michael@0 6081 }
michael@0 6082
michael@0 6083 void MultiTouchInputMapper::configureRawPointerAxes() {
michael@0 6084 TouchInputMapper::configureRawPointerAxes();
michael@0 6085
michael@0 6086 getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x);
michael@0 6087 getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y);
michael@0 6088 getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor);
michael@0 6089 getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor);
michael@0 6090 getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor);
michael@0 6091 getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor);
michael@0 6092 getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation);
michael@0 6093 getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure);
michael@0 6094 getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance);
michael@0 6095 getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId);
michael@0 6096 getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot);
michael@0 6097
michael@0 6098 if (mRawPointerAxes.trackingId.valid
michael@0 6099 && mRawPointerAxes.slot.valid
michael@0 6100 && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) {
michael@0 6101 size_t slotCount = mRawPointerAxes.slot.maxValue + 1;
michael@0 6102 if (slotCount > MAX_SLOTS) {
michael@0 6103 ALOGW("MultiTouch Device %s reported %d slots but the framework "
michael@0 6104 "only supports a maximum of %d slots at this time.",
michael@0 6105 getDeviceName().string(), slotCount, MAX_SLOTS);
michael@0 6106 slotCount = MAX_SLOTS;
michael@0 6107 }
michael@0 6108 mMultiTouchMotionAccumulator.configure(getDevice(),
michael@0 6109 slotCount, true /*usingSlotsProtocol*/);
michael@0 6110 } else {
michael@0 6111 mMultiTouchMotionAccumulator.configure(getDevice(),
michael@0 6112 MAX_POINTERS, false /*usingSlotsProtocol*/);
michael@0 6113 }
michael@0 6114 }
michael@0 6115
michael@0 6116 bool MultiTouchInputMapper::hasStylus() const {
michael@0 6117 return mMultiTouchMotionAccumulator.hasStylus()
michael@0 6118 || mTouchButtonAccumulator.hasStylus();
michael@0 6119 }
michael@0 6120
michael@0 6121
michael@0 6122 // --- JoystickInputMapper ---
michael@0 6123
michael@0 6124 JoystickInputMapper::JoystickInputMapper(InputDevice* device) :
michael@0 6125 InputMapper(device) {
michael@0 6126 }
michael@0 6127
michael@0 6128 JoystickInputMapper::~JoystickInputMapper() {
michael@0 6129 }
michael@0 6130
michael@0 6131 uint32_t JoystickInputMapper::getSources() {
michael@0 6132 return AINPUT_SOURCE_JOYSTICK;
michael@0 6133 }
michael@0 6134
michael@0 6135 void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
michael@0 6136 InputMapper::populateDeviceInfo(info);
michael@0 6137
michael@0 6138 for (size_t i = 0; i < mAxes.size(); i++) {
michael@0 6139 const Axis& axis = mAxes.valueAt(i);
michael@0 6140 addMotionRange(axis.axisInfo.axis, axis, info);
michael@0 6141
michael@0 6142 if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
michael@0 6143 addMotionRange(axis.axisInfo.highAxis, axis, info);
michael@0 6144
michael@0 6145 }
michael@0 6146 }
michael@0 6147 }
michael@0 6148
michael@0 6149 void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis,
michael@0 6150 InputDeviceInfo* info) {
michael@0 6151 info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK,
michael@0 6152 axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
michael@0 6153 /* In order to ease the transition for developers from using the old axes
michael@0 6154 * to the newer, more semantically correct axes, we'll continue to register
michael@0 6155 * the old axes as duplicates of their corresponding new ones. */
michael@0 6156 int32_t compatAxis = getCompatAxis(axisId);
michael@0 6157 if (compatAxis >= 0) {
michael@0 6158 info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK,
michael@0 6159 axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
michael@0 6160 }
michael@0 6161 }
michael@0 6162
michael@0 6163 /* A mapping from axes the joystick actually has to the axes that should be
michael@0 6164 * artificially created for compatibility purposes.
michael@0 6165 * Returns -1 if no compatibility axis is needed. */
michael@0 6166 int32_t JoystickInputMapper::getCompatAxis(int32_t axis) {
michael@0 6167 switch(axis) {
michael@0 6168 case AMOTION_EVENT_AXIS_LTRIGGER:
michael@0 6169 return AMOTION_EVENT_AXIS_BRAKE;
michael@0 6170 case AMOTION_EVENT_AXIS_RTRIGGER:
michael@0 6171 return AMOTION_EVENT_AXIS_GAS;
michael@0 6172 }
michael@0 6173 return -1;
michael@0 6174 }
michael@0 6175
michael@0 6176 void JoystickInputMapper::dump(String8& dump) {
michael@0 6177 dump.append(INDENT2 "Joystick Input Mapper:\n");
michael@0 6178
michael@0 6179 dump.append(INDENT3 "Axes:\n");
michael@0 6180 size_t numAxes = mAxes.size();
michael@0 6181 for (size_t i = 0; i < numAxes; i++) {
michael@0 6182 const Axis& axis = mAxes.valueAt(i);
michael@0 6183 const char* label = getAxisLabel(axis.axisInfo.axis);
michael@0 6184 if (label) {
michael@0 6185 dump.appendFormat(INDENT4 "%s", label);
michael@0 6186 } else {
michael@0 6187 dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis);
michael@0 6188 }
michael@0 6189 if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
michael@0 6190 label = getAxisLabel(axis.axisInfo.highAxis);
michael@0 6191 if (label) {
michael@0 6192 dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue);
michael@0 6193 } else {
michael@0 6194 dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis,
michael@0 6195 axis.axisInfo.splitValue);
michael@0 6196 }
michael@0 6197 } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) {
michael@0 6198 dump.append(" (invert)");
michael@0 6199 }
michael@0 6200
michael@0 6201 dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n",
michael@0 6202 axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
michael@0 6203 dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, "
michael@0 6204 "highScale=%0.5f, highOffset=%0.5f\n",
michael@0 6205 axis.scale, axis.offset, axis.highScale, axis.highOffset);
michael@0 6206 dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, "
michael@0 6207 "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n",
michael@0 6208 mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
michael@0 6209 axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution);
michael@0 6210 }
michael@0 6211 }
michael@0 6212
michael@0 6213 void JoystickInputMapper::configure(nsecs_t when,
michael@0 6214 const InputReaderConfiguration* config, uint32_t changes) {
michael@0 6215 InputMapper::configure(when, config, changes);
michael@0 6216
michael@0 6217 if (!changes) { // first time only
michael@0 6218 // Collect all axes.
michael@0 6219 for (int32_t abs = 0; abs <= ABS_MAX; abs++) {
michael@0 6220 if (!(getAbsAxisUsage(abs, getDevice()->getClasses())
michael@0 6221 & INPUT_DEVICE_CLASS_JOYSTICK)) {
michael@0 6222 continue; // axis must be claimed by a different device
michael@0 6223 }
michael@0 6224
michael@0 6225 RawAbsoluteAxisInfo rawAxisInfo;
michael@0 6226 getAbsoluteAxisInfo(abs, &rawAxisInfo);
michael@0 6227 if (rawAxisInfo.valid) {
michael@0 6228 // Map axis.
michael@0 6229 AxisInfo axisInfo;
michael@0 6230 bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo);
michael@0 6231 if (!explicitlyMapped) {
michael@0 6232 // Axis is not explicitly mapped, will choose a generic axis later.
michael@0 6233 axisInfo.mode = AxisInfo::MODE_NORMAL;
michael@0 6234 axisInfo.axis = -1;
michael@0 6235 }
michael@0 6236
michael@0 6237 // Apply flat override.
michael@0 6238 int32_t rawFlat = axisInfo.flatOverride < 0
michael@0 6239 ? rawAxisInfo.flat : axisInfo.flatOverride;
michael@0 6240
michael@0 6241 // Calculate scaling factors and limits.
michael@0 6242 Axis axis;
michael@0 6243 if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
michael@0 6244 float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
michael@0 6245 float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
michael@0 6246 axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
michael@0 6247 scale, 0.0f, highScale, 0.0f,
michael@0 6248 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
michael@0 6249 rawAxisInfo.resolution * scale);
michael@0 6250 } else if (isCenteredAxis(axisInfo.axis)) {
michael@0 6251 float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
michael@0 6252 float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
michael@0 6253 axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
michael@0 6254 scale, offset, scale, offset,
michael@0 6255 -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
michael@0 6256 rawAxisInfo.resolution * scale);
michael@0 6257 } else {
michael@0 6258 float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
michael@0 6259 axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
michael@0 6260 scale, 0.0f, scale, 0.0f,
michael@0 6261 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
michael@0 6262 rawAxisInfo.resolution * scale);
michael@0 6263 }
michael@0 6264
michael@0 6265 // To eliminate noise while the joystick is at rest, filter out small variations
michael@0 6266 // in axis values up front.
michael@0 6267 axis.filter = axis.flat * 0.25f;
michael@0 6268
michael@0 6269 mAxes.add(abs, axis);
michael@0 6270 }
michael@0 6271 }
michael@0 6272
michael@0 6273 // If there are too many axes, start dropping them.
michael@0 6274 // Prefer to keep explicitly mapped axes.
michael@0 6275 if (mAxes.size() > PointerCoords::MAX_AXES) {
michael@0 6276 ALOGI("Joystick '%s' has %d axes but the framework only supports a maximum of %d.",
michael@0 6277 getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES);
michael@0 6278 pruneAxes(true);
michael@0 6279 pruneAxes(false);
michael@0 6280 }
michael@0 6281
michael@0 6282 // Assign generic axis ids to remaining axes.
michael@0 6283 int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1;
michael@0 6284 size_t numAxes = mAxes.size();
michael@0 6285 for (size_t i = 0; i < numAxes; i++) {
michael@0 6286 Axis& axis = mAxes.editValueAt(i);
michael@0 6287 if (axis.axisInfo.axis < 0) {
michael@0 6288 while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16
michael@0 6289 && haveAxis(nextGenericAxisId)) {
michael@0 6290 nextGenericAxisId += 1;
michael@0 6291 }
michael@0 6292
michael@0 6293 if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) {
michael@0 6294 axis.axisInfo.axis = nextGenericAxisId;
michael@0 6295 nextGenericAxisId += 1;
michael@0 6296 } else {
michael@0 6297 ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
michael@0 6298 "have already been assigned to other axes.",
michael@0 6299 getDeviceName().string(), mAxes.keyAt(i));
michael@0 6300 mAxes.removeItemsAt(i--);
michael@0 6301 numAxes -= 1;
michael@0 6302 }
michael@0 6303 }
michael@0 6304 }
michael@0 6305 }
michael@0 6306 }
michael@0 6307
michael@0 6308 bool JoystickInputMapper::haveAxis(int32_t axisId) {
michael@0 6309 size_t numAxes = mAxes.size();
michael@0 6310 for (size_t i = 0; i < numAxes; i++) {
michael@0 6311 const Axis& axis = mAxes.valueAt(i);
michael@0 6312 if (axis.axisInfo.axis == axisId
michael@0 6313 || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT
michael@0 6314 && axis.axisInfo.highAxis == axisId)) {
michael@0 6315 return true;
michael@0 6316 }
michael@0 6317 }
michael@0 6318 return false;
michael@0 6319 }
michael@0 6320
michael@0 6321 void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) {
michael@0 6322 size_t i = mAxes.size();
michael@0 6323 while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) {
michael@0 6324 if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) {
michael@0 6325 continue;
michael@0 6326 }
michael@0 6327 ALOGI("Discarding joystick '%s' axis %d because there are too many axes.",
michael@0 6328 getDeviceName().string(), mAxes.keyAt(i));
michael@0 6329 mAxes.removeItemsAt(i);
michael@0 6330 }
michael@0 6331 }
michael@0 6332
michael@0 6333 bool JoystickInputMapper::isCenteredAxis(int32_t axis) {
michael@0 6334 switch (axis) {
michael@0 6335 case AMOTION_EVENT_AXIS_X:
michael@0 6336 case AMOTION_EVENT_AXIS_Y:
michael@0 6337 case AMOTION_EVENT_AXIS_Z:
michael@0 6338 case AMOTION_EVENT_AXIS_RX:
michael@0 6339 case AMOTION_EVENT_AXIS_RY:
michael@0 6340 case AMOTION_EVENT_AXIS_RZ:
michael@0 6341 case AMOTION_EVENT_AXIS_HAT_X:
michael@0 6342 case AMOTION_EVENT_AXIS_HAT_Y:
michael@0 6343 case AMOTION_EVENT_AXIS_ORIENTATION:
michael@0 6344 case AMOTION_EVENT_AXIS_RUDDER:
michael@0 6345 case AMOTION_EVENT_AXIS_WHEEL:
michael@0 6346 return true;
michael@0 6347 default:
michael@0 6348 return false;
michael@0 6349 }
michael@0 6350 }
michael@0 6351
michael@0 6352 void JoystickInputMapper::reset(nsecs_t when) {
michael@0 6353 // Recenter all axes.
michael@0 6354 size_t numAxes = mAxes.size();
michael@0 6355 for (size_t i = 0; i < numAxes; i++) {
michael@0 6356 Axis& axis = mAxes.editValueAt(i);
michael@0 6357 axis.resetValue();
michael@0 6358 }
michael@0 6359
michael@0 6360 InputMapper::reset(when);
michael@0 6361 }
michael@0 6362
michael@0 6363 void JoystickInputMapper::process(const RawEvent* rawEvent) {
michael@0 6364 switch (rawEvent->type) {
michael@0 6365 case EV_ABS: {
michael@0 6366 ssize_t index = mAxes.indexOfKey(rawEvent->code);
michael@0 6367 if (index >= 0) {
michael@0 6368 Axis& axis = mAxes.editValueAt(index);
michael@0 6369 float newValue, highNewValue;
michael@0 6370 switch (axis.axisInfo.mode) {
michael@0 6371 case AxisInfo::MODE_INVERT:
michael@0 6372 newValue = (axis.rawAxisInfo.maxValue - rawEvent->value)
michael@0 6373 * axis.scale + axis.offset;
michael@0 6374 highNewValue = 0.0f;
michael@0 6375 break;
michael@0 6376 case AxisInfo::MODE_SPLIT:
michael@0 6377 if (rawEvent->value < axis.axisInfo.splitValue) {
michael@0 6378 newValue = (axis.axisInfo.splitValue - rawEvent->value)
michael@0 6379 * axis.scale + axis.offset;
michael@0 6380 highNewValue = 0.0f;
michael@0 6381 } else if (rawEvent->value > axis.axisInfo.splitValue) {
michael@0 6382 newValue = 0.0f;
michael@0 6383 highNewValue = (rawEvent->value - axis.axisInfo.splitValue)
michael@0 6384 * axis.highScale + axis.highOffset;
michael@0 6385 } else {
michael@0 6386 newValue = 0.0f;
michael@0 6387 highNewValue = 0.0f;
michael@0 6388 }
michael@0 6389 break;
michael@0 6390 default:
michael@0 6391 newValue = rawEvent->value * axis.scale + axis.offset;
michael@0 6392 highNewValue = 0.0f;
michael@0 6393 break;
michael@0 6394 }
michael@0 6395 axis.newValue = newValue;
michael@0 6396 axis.highNewValue = highNewValue;
michael@0 6397 }
michael@0 6398 break;
michael@0 6399 }
michael@0 6400
michael@0 6401 case EV_SYN:
michael@0 6402 switch (rawEvent->code) {
michael@0 6403 case SYN_REPORT:
michael@0 6404 sync(rawEvent->when, false /*force*/);
michael@0 6405 break;
michael@0 6406 }
michael@0 6407 break;
michael@0 6408 }
michael@0 6409 }
michael@0 6410
michael@0 6411 void JoystickInputMapper::sync(nsecs_t when, bool force) {
michael@0 6412 if (!filterAxes(force)) {
michael@0 6413 return;
michael@0 6414 }
michael@0 6415
michael@0 6416 int32_t metaState = mContext->getGlobalMetaState();
michael@0 6417 int32_t buttonState = 0;
michael@0 6418
michael@0 6419 PointerProperties pointerProperties;
michael@0 6420 pointerProperties.clear();
michael@0 6421 pointerProperties.id = 0;
michael@0 6422 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
michael@0 6423
michael@0 6424 PointerCoords pointerCoords;
michael@0 6425 pointerCoords.clear();
michael@0 6426
michael@0 6427 size_t numAxes = mAxes.size();
michael@0 6428 for (size_t i = 0; i < numAxes; i++) {
michael@0 6429 const Axis& axis = mAxes.valueAt(i);
michael@0 6430 setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue);
michael@0 6431 if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
michael@0 6432 setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis,
michael@0 6433 axis.highCurrentValue);
michael@0 6434 }
michael@0 6435 }
michael@0 6436
michael@0 6437 // Moving a joystick axis should not wake the device because joysticks can
michael@0 6438 // be fairly noisy even when not in use. On the other hand, pushing a gamepad
michael@0 6439 // button will likely wake the device.
michael@0 6440 // TODO: Use the input device configuration to control this behavior more finely.
michael@0 6441 uint32_t policyFlags = 0;
michael@0 6442
michael@0 6443 NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
michael@0 6444 AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
michael@0 6445 ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0);
michael@0 6446 getListener()->notifyMotion(&args);
michael@0 6447 }
michael@0 6448
michael@0 6449 void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords,
michael@0 6450 int32_t axis, float value) {
michael@0 6451 pointerCoords->setAxisValue(axis, value);
michael@0 6452 /* In order to ease the transition for developers from using the old axes
michael@0 6453 * to the newer, more semantically correct axes, we'll continue to produce
michael@0 6454 * values for the old axes as mirrors of the value of their corresponding
michael@0 6455 * new axes. */
michael@0 6456 int32_t compatAxis = getCompatAxis(axis);
michael@0 6457 if (compatAxis >= 0) {
michael@0 6458 pointerCoords->setAxisValue(compatAxis, value);
michael@0 6459 }
michael@0 6460 }
michael@0 6461
michael@0 6462 bool JoystickInputMapper::filterAxes(bool force) {
michael@0 6463 bool atLeastOneSignificantChange = force;
michael@0 6464 size_t numAxes = mAxes.size();
michael@0 6465 for (size_t i = 0; i < numAxes; i++) {
michael@0 6466 Axis& axis = mAxes.editValueAt(i);
michael@0 6467 if (force || hasValueChangedSignificantly(axis.filter,
michael@0 6468 axis.newValue, axis.currentValue, axis.min, axis.max)) {
michael@0 6469 axis.currentValue = axis.newValue;
michael@0 6470 atLeastOneSignificantChange = true;
michael@0 6471 }
michael@0 6472 if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
michael@0 6473 if (force || hasValueChangedSignificantly(axis.filter,
michael@0 6474 axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) {
michael@0 6475 axis.highCurrentValue = axis.highNewValue;
michael@0 6476 atLeastOneSignificantChange = true;
michael@0 6477 }
michael@0 6478 }
michael@0 6479 }
michael@0 6480 return atLeastOneSignificantChange;
michael@0 6481 }
michael@0 6482
michael@0 6483 bool JoystickInputMapper::hasValueChangedSignificantly(
michael@0 6484 float filter, float newValue, float currentValue, float min, float max) {
michael@0 6485 if (newValue != currentValue) {
michael@0 6486 // Filter out small changes in value unless the value is converging on the axis
michael@0 6487 // bounds or center point. This is intended to reduce the amount of information
michael@0 6488 // sent to applications by particularly noisy joysticks (such as PS3).
michael@0 6489 if (fabs(newValue - currentValue) > filter
michael@0 6490 || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min)
michael@0 6491 || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max)
michael@0 6492 || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) {
michael@0 6493 return true;
michael@0 6494 }
michael@0 6495 }
michael@0 6496 return false;
michael@0 6497 }
michael@0 6498
michael@0 6499 bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange(
michael@0 6500 float filter, float newValue, float currentValue, float thresholdValue) {
michael@0 6501 float newDistance = fabs(newValue - thresholdValue);
michael@0 6502 if (newDistance < filter) {
michael@0 6503 float oldDistance = fabs(currentValue - thresholdValue);
michael@0 6504 if (newDistance < oldDistance) {
michael@0 6505 return true;
michael@0 6506 }
michael@0 6507 }
michael@0 6508 return false;
michael@0 6509 }
michael@0 6510
michael@0 6511 } // namespace android

mercurial