Loading include/ui/Input.h +81 −0 Original line number Diff line number Diff line Loading @@ -627,6 +627,87 @@ private: int32_t mActivePointerId; }; /* * Specifies parameters that govern pointer or wheel acceleration. */ struct VelocityControlParameters { // A scale factor that is multiplied with the raw velocity deltas // prior to applying any other velocity control factors. The scale // factor should be used to adapt the input device resolution // (eg. counts per inch) to the output device resolution (eg. pixels per inch). // // Must be a positive value. // Default is 1.0 (no scaling). float scale; // The scaled speed at which acceleration begins to be applied. // This value establishes the upper bound of a low speed regime for // small precise motions that are performed without any acceleration. // // Must be a non-negative value. // Default is 0.0 (no low threshold). float lowThreshold; // The scaled speed at which maximum acceleration is applied. // The difference between highThreshold and lowThreshold controls // the range of speeds over which the acceleration factor is interpolated. // The wider the range, the smoother the acceleration. // // Must be a non-negative value greater than or equal to lowThreshold. // Default is 0.0 (no high threshold). float highThreshold; // The acceleration factor. // When the speed is above the low speed threshold, the velocity will scaled // by an interpolated value between 1.0 and this amount. // // Must be a positive greater than or equal to 1.0. // Default is 1.0 (no acceleration). float acceleration; VelocityControlParameters() : scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) { } VelocityControlParameters(float scale, float lowThreshold, float highThreshold, float acceleration) : scale(scale), lowThreshold(lowThreshold), highThreshold(highThreshold), acceleration(acceleration) { } }; /* * Implements mouse pointer and wheel speed control and acceleration. */ class VelocityControl { public: VelocityControl(); /* Sets the various parameters. */ void setParameters(const VelocityControlParameters& parameters); /* Resets the current movement counters to zero. * This has the effect of nullifying any acceleration. */ void reset(); /* Translates a raw movement delta into an appropriately * scaled / accelerated delta based on the current velocity. */ void move(nsecs_t eventTime, float* deltaX, float* deltaY); private: // If no movements are received within this amount of time, // we assume the movement has stopped and reset the movement counters. static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms VelocityControlParameters mParameters; nsecs_t mLastMovementTime; VelocityTracker::Position mRawPosition; VelocityTracker mVelocityTracker; }; /* * Describes the characteristics and capabilities of an input device. */ Loading libs/ui/Input.cpp +89 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,10 @@ // Log debug messages about velocity tracking. #define DEBUG_VELOCITY 0 // Log debug messages about acceleration. #define DEBUG_ACCELERATION 0 #include <stdlib.h> #include <unistd.h> #include <ctype.h> Loading @@ -20,6 +24,7 @@ #include <ui/Input.h> #include <math.h> #include <limits.h> #ifdef HAVE_ANDROID_OS #include <binder/Parcel.h> Loading Loading @@ -670,6 +675,11 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { // --- VelocityTracker --- const uint32_t VelocityTracker::HISTORY_SIZE; const nsecs_t VelocityTracker::MAX_AGE; const nsecs_t VelocityTracker::MIN_WINDOW; const nsecs_t VelocityTracker::MIN_DURATION; VelocityTracker::VelocityTracker() { clear(); } Loading Loading @@ -879,6 +889,85 @@ bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const } // --- VelocityControl --- const nsecs_t VelocityControl::STOP_TIME; VelocityControl::VelocityControl() { reset(); } void VelocityControl::setParameters(const VelocityControlParameters& parameters) { mParameters = parameters; reset(); } void VelocityControl::reset() { mLastMovementTime = LLONG_MIN; mRawPosition.x = 0; mRawPosition.y = 0; mVelocityTracker.clear(); } void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { if ((deltaX && *deltaX) || (deltaY && *deltaY)) { if (eventTime >= mLastMovementTime + STOP_TIME) { #if DEBUG_ACCELERATION LOGD("VelocityControl: stopped, last movement was %0.3fms ago", (eventTime - mLastMovementTime) * 0.000001f); #endif reset(); } mLastMovementTime = eventTime; if (deltaX) { mRawPosition.x += *deltaX; } if (deltaY) { mRawPosition.y += *deltaY; } mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition); float vx, vy; float scale = mParameters.scale; if (mVelocityTracker.getVelocity(0, &vx, &vy)) { float speed = hypotf(vx, vy) * scale; if (speed >= mParameters.highThreshold) { // Apply full acceleration above the high speed threshold. scale *= mParameters.acceleration; } else if (speed > mParameters.lowThreshold) { // Linearly interpolate the acceleration to apply between the low and high // speed thresholds. scale *= 1 + (speed - mParameters.lowThreshold) / (mParameters.highThreshold - mParameters.lowThreshold) * (mParameters.acceleration - 1); } #if DEBUG_ACCELERATION LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): " "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, mParameters.acceleration, vx, vy, speed, scale / mParameters.scale); #endif } else { #if DEBUG_ACCELERATION LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity", mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, mParameters.acceleration); #endif } if (deltaX) { *deltaX *= scale; } if (deltaY) { *deltaY *= scale; } } } // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { Loading services/input/InputReader.cpp +110 −66 Original line number Diff line number Diff line Loading @@ -707,6 +707,20 @@ void InputReader::dump(String8& dump) { dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", mConfig.virtualKeyQuietTime * 0.000001f); dump.appendFormat(INDENT2 "PointerVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.pointerVelocityControlParameters.scale, mConfig.pointerVelocityControlParameters.lowThreshold, mConfig.pointerVelocityControlParameters.highThreshold, mConfig.pointerVelocityControlParameters.acceleration); dump.appendFormat(INDENT2 "WheelVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.wheelVelocityControlParameters.scale, mConfig.wheelVelocityControlParameters.lowThreshold, mConfig.wheelVelocityControlParameters.highThreshold, mConfig.wheelVelocityControlParameters.acceleration); dump.appendFormat(INDENT2 "PointerGesture:\n"); dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n", mConfig.pointerGestureQuietInterval * 0.000001f); Loading Loading @@ -1371,6 +1385,10 @@ void CursorInputMapper::configure() { mHaveVWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_WHEEL); mHaveHWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_HWHEEL); mPointerVelocityControl.setParameters(getConfig()->pointerVelocityControlParameters); mWheelXVelocityControl.setParameters(getConfig()->wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(getConfig()->wheelVelocityControlParameters); } void CursorInputMapper::configureParameters() { Loading Loading @@ -1432,6 +1450,11 @@ void CursorInputMapper::reset() { } } // release lock // Reset velocity. mPointerVelocityControl.reset(); mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); // Synthesize button up event on reset. nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); mAccumulator.clear(); Loading Loading @@ -1585,11 +1608,16 @@ void CursorInputMapper::sync(nsecs_t when) { } else { vscroll = 0; } mWheelYVelocityControl.move(when, NULL, &vscroll); if (mHaveHWheel && (fields & Accumulator::FIELD_REL_HWHEEL)) { hscroll = mAccumulator.relHWheel; } else { hscroll = 0; } mWheelXVelocityControl.move(when, &hscroll, NULL); mPointerVelocityControl.move(when, &deltaX, &deltaY); if (mPointerController != NULL) { if (deltaX != 0 || deltaY != 0 || vscroll != 0 || hscroll != 0 Loading Loading @@ -1806,6 +1834,7 @@ void TouchInputMapper::initializeLocked() { mLocked.orientedRanges.haveOrientation = false; mPointerGesture.reset(); mPointerGesture.pointerVelocityControl.setParameters(mConfig->pointerVelocityControlParameters); } void TouchInputMapper::configure() { Loading Loading @@ -2239,11 +2268,10 @@ bool TouchInputMapper::configureSurfaceLocked() { mLocked.associatedDisplayHeight); // Scale movements such that one whole swipe of the touch pad covers a // given area relative to the diagonal size of the display. // given area relative to the diagonal size of the display when no acceleration // is applied. // Assume that the touch pad has a square aspect ratio such that movements in // X and Y of the same number of raw units cover the same physical distance. const float scaleFactor = 0.8f; mLocked.pointerGestureXMovementScale = mConfig->pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal; mLocked.pointerGestureYMovementScale = mLocked.pointerGestureXMovementScale; Loading Loading @@ -3247,6 +3275,9 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag if (!sendEvents) { return; } if (finishPreviousGesture) { cancelPreviousGesture = false; } // Switch pointer presentation. mPointerController->setPresentation( Loading Loading @@ -3436,6 +3467,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.pointerVelocityControl.reset(); if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; mPointerGesture.spotIdBits.clear(); Loading Loading @@ -3530,6 +3563,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::QUIET; mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.pointerVelocityControl.reset(); if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; mPointerGesture.spotIdBits.clear(); Loading Loading @@ -3561,8 +3596,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // Switch pointers if needed. // Find the fastest pointer and follow it. if (activeTouchId >= 0) { if (mCurrentTouch.pointerCount > 1) { if (activeTouchId >= 0 && mCurrentTouch.pointerCount > 1) { int32_t bestId = -1; float bestSpeed = mConfig->pointerGestureDragMinSwitchSpeed; for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) { Loading @@ -3586,7 +3620,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } if (mLastTouch.idBits.hasBit(activeTouchId)) { if (activeTouchId >= 0 && mLastTouch.idBits.hasBit(activeTouchId)) { const PointerData& currentPointer = mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]]; const PointerData& lastPointer = Loading @@ -3596,11 +3630,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, float deltaY = (currentPointer.y - lastPointer.y) * mLocked.pointerGestureYMovementScale; mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. mPointerController->move(deltaX, deltaY); } } else { mPointerGesture.pointerVelocityControl.reset(); } float x, y; Loading Loading @@ -3700,6 +3737,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } mPointerGesture.pointerVelocityControl.reset(); if (!tapped) { #if DEBUG_GESTURES LOGD("Gestures: NEUTRAL"); Loading Loading @@ -3756,9 +3795,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, float deltaY = (currentPointer.y - lastPointer.y) * mLocked.pointerGestureYMovementScale; mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. mPointerController->move(deltaX, deltaY); } else { mPointerGesture.pointerVelocityControl.reset(); } bool down; Loading Loading @@ -3820,16 +3863,32 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // a decision to transition into SWIPE or FREEFORM mode accordingly. LOG_ASSERT(activeTouchId >= 0); bool needReference = false; bool settled = when >= mPointerGesture.firstTouchTime + mConfig->pointerGestureMultitouchSettleInterval; if (mPointerGesture.lastGestureMode != PointerGesture::PRESS && mPointerGesture.lastGestureMode != PointerGesture::SWIPE && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { *outFinishPreviousGesture = true; } else if (!settled && mCurrentTouch.pointerCount > mLastTouch.pointerCount) { // Additional pointers have gone down but not yet settled. // Reset the gesture. #if DEBUG_GESTURES LOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when) * 0.000001f); #endif *outCancelPreviousGesture = true; } else { // Continue previous gesture. mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; } if (*outFinishPreviousGesture || *outCancelPreviousGesture) { mPointerGesture.currentGestureMode = PointerGesture::PRESS; mPointerGesture.activeGestureId = 0; mPointerGesture.referenceIdBits.clear(); mPointerGesture.pointerVelocityControl.reset(); if (settled && mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS && mLastTouch.idBits.hasBit(mPointerGesture.activeTouchId)) { Loading @@ -3850,38 +3909,19 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.referenceGestureX = c.getAxisValue(AMOTION_EVENT_AXIS_X); mPointerGesture.referenceGestureY = c.getAxisValue(AMOTION_EVENT_AXIS_Y); } else { // Use the centroid and pointer location as the reference points for the gesture. #if DEBUG_GESTURES LOGD("Gestures: Using centroid as reference for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when) * 0.000001f); #endif needReference = true; } } else if (!settled && mCurrentTouch.pointerCount > mLastTouch.pointerCount) { // Additional pointers have gone down but not yet settled. // Reset the gesture. #if DEBUG_GESTURES LOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when) * 0.000001f); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::PRESS; mPointerGesture.activeGestureId = 0; } else { // Continue previous gesture. mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; } if (needReference) { // Use the centroid and pointer location as the reference points for the gesture. mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); mPointerController->getPosition(&mPointerGesture.referenceGestureX, &mPointerGesture.referenceGestureY); } } if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { float d; Loading Loading @@ -4010,10 +4050,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.referenceTouchX += commonDeltaX; mPointerGesture.referenceTouchY += commonDeltaY; mPointerGesture.referenceGestureX += commonDeltaX * mLocked.pointerGestureXMovementScale; mPointerGesture.referenceGestureY += commonDeltaY * mLocked.pointerGestureYMovementScale; commonDeltaX *= mLocked.pointerGestureXMovementScale; commonDeltaY *= mLocked.pointerGestureYMovementScale; mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); mPointerGesture.referenceGestureX += commonDeltaX; mPointerGesture.referenceGestureY += commonDeltaY; clampPositionUsingPointerBounds(mPointerController, &mPointerGesture.referenceGestureX, &mPointerGesture.referenceGestureY); Loading services/input/InputReader.h +19 −1 Original line number Diff line number Diff line Loading @@ -62,6 +62,12 @@ struct InputReaderConfiguration { // Devices with these names will be ignored. Vector<String8> excludedDeviceNames; // Velocity control parameters for mouse pointer movements. VelocityControlParameters pointerVelocityControlParameters; // Velocity control parameters for mouse wheel movements. VelocityControlParameters wheelVelocityControlParameters; // Quiet time between certain pointer gesture transitions. // Time to allow for all fingers or buttons to settle into a stable state before // starting a new gesture. Loading Loading @@ -128,6 +134,8 @@ struct InputReaderConfiguration { filterTouchEvents(false), filterJumpyTouchEvents(false), virtualKeyQuietTime(0), pointerVelocityControlParameters(1.0f, 80.0f, 400.0f, 4.0f), wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f), pointerGestureQuietInterval(100 * 1000000LL), // 100 ms pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second pointerGestureTapInterval(150 * 1000000LL), // 150 ms Loading @@ -137,7 +145,7 @@ struct InputReaderConfiguration { pointerGestureMultitouchMinSpeed(150.0f), // 150 pixels per second pointerGestureSwipeTransitionAngleCosine(0.5f), // cosine of 45degrees pointerGestureSwipeMaxWidthRatio(0.333f), pointerGestureMovementSpeedRatio(0.8f), pointerGestureMovementSpeedRatio(0.5f), pointerGestureZoomSpeedRatio(0.3f) { } }; Loading Loading @@ -629,6 +637,12 @@ private: float mVWheelScale; float mHWheelScale; // Velocity controls for mouse pointer and wheel movements. // The controls for X and Y wheel movements are separate to keep them decoupled. VelocityControl mPointerVelocityControl; VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; sp<PointerControllerInterface> mPointerController; struct LockedState { Loading Loading @@ -1133,6 +1147,9 @@ private: // A velocity tracker for determining whether to switch active pointers during drags. VelocityTracker velocityTracker; // Velocity control for pointer movements. VelocityControl pointerVelocityControl; void reset() { firstTouchTime = LLONG_MIN; activeTouchId = -1; Loading @@ -1147,6 +1164,7 @@ private: velocityTracker.clear(); resetTap(); resetQuietTime(); pointerVelocityControl.reset(); } void resetTap() { Loading Loading
include/ui/Input.h +81 −0 Original line number Diff line number Diff line Loading @@ -627,6 +627,87 @@ private: int32_t mActivePointerId; }; /* * Specifies parameters that govern pointer or wheel acceleration. */ struct VelocityControlParameters { // A scale factor that is multiplied with the raw velocity deltas // prior to applying any other velocity control factors. The scale // factor should be used to adapt the input device resolution // (eg. counts per inch) to the output device resolution (eg. pixels per inch). // // Must be a positive value. // Default is 1.0 (no scaling). float scale; // The scaled speed at which acceleration begins to be applied. // This value establishes the upper bound of a low speed regime for // small precise motions that are performed without any acceleration. // // Must be a non-negative value. // Default is 0.0 (no low threshold). float lowThreshold; // The scaled speed at which maximum acceleration is applied. // The difference between highThreshold and lowThreshold controls // the range of speeds over which the acceleration factor is interpolated. // The wider the range, the smoother the acceleration. // // Must be a non-negative value greater than or equal to lowThreshold. // Default is 0.0 (no high threshold). float highThreshold; // The acceleration factor. // When the speed is above the low speed threshold, the velocity will scaled // by an interpolated value between 1.0 and this amount. // // Must be a positive greater than or equal to 1.0. // Default is 1.0 (no acceleration). float acceleration; VelocityControlParameters() : scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) { } VelocityControlParameters(float scale, float lowThreshold, float highThreshold, float acceleration) : scale(scale), lowThreshold(lowThreshold), highThreshold(highThreshold), acceleration(acceleration) { } }; /* * Implements mouse pointer and wheel speed control and acceleration. */ class VelocityControl { public: VelocityControl(); /* Sets the various parameters. */ void setParameters(const VelocityControlParameters& parameters); /* Resets the current movement counters to zero. * This has the effect of nullifying any acceleration. */ void reset(); /* Translates a raw movement delta into an appropriately * scaled / accelerated delta based on the current velocity. */ void move(nsecs_t eventTime, float* deltaX, float* deltaY); private: // If no movements are received within this amount of time, // we assume the movement has stopped and reset the movement counters. static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms VelocityControlParameters mParameters; nsecs_t mLastMovementTime; VelocityTracker::Position mRawPosition; VelocityTracker mVelocityTracker; }; /* * Describes the characteristics and capabilities of an input device. */ Loading
libs/ui/Input.cpp +89 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,10 @@ // Log debug messages about velocity tracking. #define DEBUG_VELOCITY 0 // Log debug messages about acceleration. #define DEBUG_ACCELERATION 0 #include <stdlib.h> #include <unistd.h> #include <ctype.h> Loading @@ -20,6 +24,7 @@ #include <ui/Input.h> #include <math.h> #include <limits.h> #ifdef HAVE_ANDROID_OS #include <binder/Parcel.h> Loading Loading @@ -670,6 +675,11 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { // --- VelocityTracker --- const uint32_t VelocityTracker::HISTORY_SIZE; const nsecs_t VelocityTracker::MAX_AGE; const nsecs_t VelocityTracker::MIN_WINDOW; const nsecs_t VelocityTracker::MIN_DURATION; VelocityTracker::VelocityTracker() { clear(); } Loading Loading @@ -879,6 +889,85 @@ bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const } // --- VelocityControl --- const nsecs_t VelocityControl::STOP_TIME; VelocityControl::VelocityControl() { reset(); } void VelocityControl::setParameters(const VelocityControlParameters& parameters) { mParameters = parameters; reset(); } void VelocityControl::reset() { mLastMovementTime = LLONG_MIN; mRawPosition.x = 0; mRawPosition.y = 0; mVelocityTracker.clear(); } void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { if ((deltaX && *deltaX) || (deltaY && *deltaY)) { if (eventTime >= mLastMovementTime + STOP_TIME) { #if DEBUG_ACCELERATION LOGD("VelocityControl: stopped, last movement was %0.3fms ago", (eventTime - mLastMovementTime) * 0.000001f); #endif reset(); } mLastMovementTime = eventTime; if (deltaX) { mRawPosition.x += *deltaX; } if (deltaY) { mRawPosition.y += *deltaY; } mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition); float vx, vy; float scale = mParameters.scale; if (mVelocityTracker.getVelocity(0, &vx, &vy)) { float speed = hypotf(vx, vy) * scale; if (speed >= mParameters.highThreshold) { // Apply full acceleration above the high speed threshold. scale *= mParameters.acceleration; } else if (speed > mParameters.lowThreshold) { // Linearly interpolate the acceleration to apply between the low and high // speed thresholds. scale *= 1 + (speed - mParameters.lowThreshold) / (mParameters.highThreshold - mParameters.lowThreshold) * (mParameters.acceleration - 1); } #if DEBUG_ACCELERATION LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): " "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, mParameters.acceleration, vx, vy, speed, scale / mParameters.scale); #endif } else { #if DEBUG_ACCELERATION LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity", mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, mParameters.acceleration); #endif } if (deltaX) { *deltaX *= scale; } if (deltaY) { *deltaY *= scale; } } } // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { Loading
services/input/InputReader.cpp +110 −66 Original line number Diff line number Diff line Loading @@ -707,6 +707,20 @@ void InputReader::dump(String8& dump) { dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", mConfig.virtualKeyQuietTime * 0.000001f); dump.appendFormat(INDENT2 "PointerVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.pointerVelocityControlParameters.scale, mConfig.pointerVelocityControlParameters.lowThreshold, mConfig.pointerVelocityControlParameters.highThreshold, mConfig.pointerVelocityControlParameters.acceleration); dump.appendFormat(INDENT2 "WheelVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.wheelVelocityControlParameters.scale, mConfig.wheelVelocityControlParameters.lowThreshold, mConfig.wheelVelocityControlParameters.highThreshold, mConfig.wheelVelocityControlParameters.acceleration); dump.appendFormat(INDENT2 "PointerGesture:\n"); dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n", mConfig.pointerGestureQuietInterval * 0.000001f); Loading Loading @@ -1371,6 +1385,10 @@ void CursorInputMapper::configure() { mHaveVWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_WHEEL); mHaveHWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_HWHEEL); mPointerVelocityControl.setParameters(getConfig()->pointerVelocityControlParameters); mWheelXVelocityControl.setParameters(getConfig()->wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(getConfig()->wheelVelocityControlParameters); } void CursorInputMapper::configureParameters() { Loading Loading @@ -1432,6 +1450,11 @@ void CursorInputMapper::reset() { } } // release lock // Reset velocity. mPointerVelocityControl.reset(); mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); // Synthesize button up event on reset. nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); mAccumulator.clear(); Loading Loading @@ -1585,11 +1608,16 @@ void CursorInputMapper::sync(nsecs_t when) { } else { vscroll = 0; } mWheelYVelocityControl.move(when, NULL, &vscroll); if (mHaveHWheel && (fields & Accumulator::FIELD_REL_HWHEEL)) { hscroll = mAccumulator.relHWheel; } else { hscroll = 0; } mWheelXVelocityControl.move(when, &hscroll, NULL); mPointerVelocityControl.move(when, &deltaX, &deltaY); if (mPointerController != NULL) { if (deltaX != 0 || deltaY != 0 || vscroll != 0 || hscroll != 0 Loading Loading @@ -1806,6 +1834,7 @@ void TouchInputMapper::initializeLocked() { mLocked.orientedRanges.haveOrientation = false; mPointerGesture.reset(); mPointerGesture.pointerVelocityControl.setParameters(mConfig->pointerVelocityControlParameters); } void TouchInputMapper::configure() { Loading Loading @@ -2239,11 +2268,10 @@ bool TouchInputMapper::configureSurfaceLocked() { mLocked.associatedDisplayHeight); // Scale movements such that one whole swipe of the touch pad covers a // given area relative to the diagonal size of the display. // given area relative to the diagonal size of the display when no acceleration // is applied. // Assume that the touch pad has a square aspect ratio such that movements in // X and Y of the same number of raw units cover the same physical distance. const float scaleFactor = 0.8f; mLocked.pointerGestureXMovementScale = mConfig->pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal; mLocked.pointerGestureYMovementScale = mLocked.pointerGestureXMovementScale; Loading Loading @@ -3247,6 +3275,9 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag if (!sendEvents) { return; } if (finishPreviousGesture) { cancelPreviousGesture = false; } // Switch pointer presentation. mPointerController->setPresentation( Loading Loading @@ -3436,6 +3467,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.pointerVelocityControl.reset(); if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; mPointerGesture.spotIdBits.clear(); Loading Loading @@ -3530,6 +3563,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::QUIET; mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.pointerVelocityControl.reset(); if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; mPointerGesture.spotIdBits.clear(); Loading Loading @@ -3561,8 +3596,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // Switch pointers if needed. // Find the fastest pointer and follow it. if (activeTouchId >= 0) { if (mCurrentTouch.pointerCount > 1) { if (activeTouchId >= 0 && mCurrentTouch.pointerCount > 1) { int32_t bestId = -1; float bestSpeed = mConfig->pointerGestureDragMinSwitchSpeed; for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) { Loading @@ -3586,7 +3620,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } if (mLastTouch.idBits.hasBit(activeTouchId)) { if (activeTouchId >= 0 && mLastTouch.idBits.hasBit(activeTouchId)) { const PointerData& currentPointer = mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]]; const PointerData& lastPointer = Loading @@ -3596,11 +3630,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, float deltaY = (currentPointer.y - lastPointer.y) * mLocked.pointerGestureYMovementScale; mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. mPointerController->move(deltaX, deltaY); } } else { mPointerGesture.pointerVelocityControl.reset(); } float x, y; Loading Loading @@ -3700,6 +3737,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } mPointerGesture.pointerVelocityControl.reset(); if (!tapped) { #if DEBUG_GESTURES LOGD("Gestures: NEUTRAL"); Loading Loading @@ -3756,9 +3795,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, float deltaY = (currentPointer.y - lastPointer.y) * mLocked.pointerGestureYMovementScale; mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. mPointerController->move(deltaX, deltaY); } else { mPointerGesture.pointerVelocityControl.reset(); } bool down; Loading Loading @@ -3820,16 +3863,32 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // a decision to transition into SWIPE or FREEFORM mode accordingly. LOG_ASSERT(activeTouchId >= 0); bool needReference = false; bool settled = when >= mPointerGesture.firstTouchTime + mConfig->pointerGestureMultitouchSettleInterval; if (mPointerGesture.lastGestureMode != PointerGesture::PRESS && mPointerGesture.lastGestureMode != PointerGesture::SWIPE && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { *outFinishPreviousGesture = true; } else if (!settled && mCurrentTouch.pointerCount > mLastTouch.pointerCount) { // Additional pointers have gone down but not yet settled. // Reset the gesture. #if DEBUG_GESTURES LOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when) * 0.000001f); #endif *outCancelPreviousGesture = true; } else { // Continue previous gesture. mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; } if (*outFinishPreviousGesture || *outCancelPreviousGesture) { mPointerGesture.currentGestureMode = PointerGesture::PRESS; mPointerGesture.activeGestureId = 0; mPointerGesture.referenceIdBits.clear(); mPointerGesture.pointerVelocityControl.reset(); if (settled && mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS && mLastTouch.idBits.hasBit(mPointerGesture.activeTouchId)) { Loading @@ -3850,38 +3909,19 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.referenceGestureX = c.getAxisValue(AMOTION_EVENT_AXIS_X); mPointerGesture.referenceGestureY = c.getAxisValue(AMOTION_EVENT_AXIS_Y); } else { // Use the centroid and pointer location as the reference points for the gesture. #if DEBUG_GESTURES LOGD("Gestures: Using centroid as reference for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when) * 0.000001f); #endif needReference = true; } } else if (!settled && mCurrentTouch.pointerCount > mLastTouch.pointerCount) { // Additional pointers have gone down but not yet settled. // Reset the gesture. #if DEBUG_GESTURES LOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when) * 0.000001f); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::PRESS; mPointerGesture.activeGestureId = 0; } else { // Continue previous gesture. mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; } if (needReference) { // Use the centroid and pointer location as the reference points for the gesture. mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); mPointerController->getPosition(&mPointerGesture.referenceGestureX, &mPointerGesture.referenceGestureY); } } if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { float d; Loading Loading @@ -4010,10 +4050,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.referenceTouchX += commonDeltaX; mPointerGesture.referenceTouchY += commonDeltaY; mPointerGesture.referenceGestureX += commonDeltaX * mLocked.pointerGestureXMovementScale; mPointerGesture.referenceGestureY += commonDeltaY * mLocked.pointerGestureYMovementScale; commonDeltaX *= mLocked.pointerGestureXMovementScale; commonDeltaY *= mLocked.pointerGestureYMovementScale; mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); mPointerGesture.referenceGestureX += commonDeltaX; mPointerGesture.referenceGestureY += commonDeltaY; clampPositionUsingPointerBounds(mPointerController, &mPointerGesture.referenceGestureX, &mPointerGesture.referenceGestureY); Loading
services/input/InputReader.h +19 −1 Original line number Diff line number Diff line Loading @@ -62,6 +62,12 @@ struct InputReaderConfiguration { // Devices with these names will be ignored. Vector<String8> excludedDeviceNames; // Velocity control parameters for mouse pointer movements. VelocityControlParameters pointerVelocityControlParameters; // Velocity control parameters for mouse wheel movements. VelocityControlParameters wheelVelocityControlParameters; // Quiet time between certain pointer gesture transitions. // Time to allow for all fingers or buttons to settle into a stable state before // starting a new gesture. Loading Loading @@ -128,6 +134,8 @@ struct InputReaderConfiguration { filterTouchEvents(false), filterJumpyTouchEvents(false), virtualKeyQuietTime(0), pointerVelocityControlParameters(1.0f, 80.0f, 400.0f, 4.0f), wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f), pointerGestureQuietInterval(100 * 1000000LL), // 100 ms pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second pointerGestureTapInterval(150 * 1000000LL), // 150 ms Loading @@ -137,7 +145,7 @@ struct InputReaderConfiguration { pointerGestureMultitouchMinSpeed(150.0f), // 150 pixels per second pointerGestureSwipeTransitionAngleCosine(0.5f), // cosine of 45degrees pointerGestureSwipeMaxWidthRatio(0.333f), pointerGestureMovementSpeedRatio(0.8f), pointerGestureMovementSpeedRatio(0.5f), pointerGestureZoomSpeedRatio(0.3f) { } }; Loading Loading @@ -629,6 +637,12 @@ private: float mVWheelScale; float mHWheelScale; // Velocity controls for mouse pointer and wheel movements. // The controls for X and Y wheel movements are separate to keep them decoupled. VelocityControl mPointerVelocityControl; VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; sp<PointerControllerInterface> mPointerController; struct LockedState { Loading Loading @@ -1133,6 +1147,9 @@ private: // A velocity tracker for determining whether to switch active pointers during drags. VelocityTracker velocityTracker; // Velocity control for pointer movements. VelocityControl pointerVelocityControl; void reset() { firstTouchTime = LLONG_MIN; activeTouchId = -1; Loading @@ -1147,6 +1164,7 @@ private: velocityTracker.clear(); resetTap(); resetQuietTime(); pointerVelocityControl.reset(); } void resetTap() { Loading