summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/ui/Input.h81
-rw-r--r--libs/ui/Input.cpp89
-rw-r--r--services/input/InputReader.cpp176
-rw-r--r--services/input/InputReader.h20
4 files changed, 299 insertions, 67 deletions
diff --git a/include/ui/Input.h b/include/ui/Input.h
index ba1c6b4..3b5aba4 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -674,6 +674,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.
*/
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 1ba38a7..e95dbe4 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -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>
@@ -20,6 +24,7 @@
#include <ui/Input.h>
#include <math.h>
+#include <limits.h>
#ifdef HAVE_ANDROID_OS
#include <binder/Parcel.h>
@@ -693,6 +698,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();
}
@@ -902,6 +912,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() {
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index cb64da6..8c9bad8 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -748,6 +748,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);
@@ -1430,6 +1444,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() {
@@ -1491,6 +1509,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();
@@ -1654,11 +1677,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
@@ -1900,6 +1928,7 @@ void TouchInputMapper::initializeLocked() {
mLocked.orientedRanges.haveDistance = false;
mPointerGesture.reset();
+ mPointerGesture.pointerVelocityControl.setParameters(mConfig->pointerVelocityControlParameters);
}
void TouchInputMapper::configure() {
@@ -2369,11 +2398,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;
@@ -3463,6 +3491,9 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
if (!sendEvents) {
return;
}
+ if (finishPreviousGesture) {
+ cancelPreviousGesture = false;
+ }
// Switch pointer presentation.
mPointerController->setPresentation(
@@ -3666,6 +3697,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();
@@ -3760,6 +3793,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();
@@ -3791,46 +3826,48 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
// Switch pointers if needed.
// Find the fastest pointer and follow it.
- if (activeTouchId >= 0) {
- if (mCurrentTouch.pointerCount > 1) {
- int32_t bestId = -1;
- float bestSpeed = mConfig->pointerGestureDragMinSwitchSpeed;
- for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
- uint32_t id = mCurrentTouch.pointers[i].id;
- float vx, vy;
- if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
- float speed = hypotf(vx, vy);
- if (speed > bestSpeed) {
- bestId = id;
- bestSpeed = speed;
- }
+ if (activeTouchId >= 0 && mCurrentTouch.pointerCount > 1) {
+ int32_t bestId = -1;
+ float bestSpeed = mConfig->pointerGestureDragMinSwitchSpeed;
+ for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
+ uint32_t id = mCurrentTouch.pointers[i].id;
+ float vx, vy;
+ if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
+ float speed = hypotf(vx, vy);
+ if (speed > bestSpeed) {
+ bestId = id;
+ bestSpeed = speed;
}
}
- if (bestId >= 0 && bestId != activeTouchId) {
- mPointerGesture.activeTouchId = activeTouchId = bestId;
- activeTouchChanged = true;
+ }
+ if (bestId >= 0 && bestId != activeTouchId) {
+ mPointerGesture.activeTouchId = activeTouchId = bestId;
+ activeTouchChanged = true;
#if DEBUG_GESTURES
- LOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
- "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
+ LOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
+ "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
#endif
- }
}
+ }
- if (mLastTouch.idBits.hasBit(activeTouchId)) {
- const PointerData& currentPointer =
- mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]];
- const PointerData& lastPointer =
- mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]];
- float deltaX = (currentPointer.x - lastPointer.x)
- * mLocked.pointerGestureXMovementScale;
- float deltaY = (currentPointer.y - lastPointer.y)
- * mLocked.pointerGestureYMovementScale;
-
- // 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);
- }
+ if (activeTouchId >= 0 && mLastTouch.idBits.hasBit(activeTouchId)) {
+ const PointerData& currentPointer =
+ mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]];
+ const PointerData& lastPointer =
+ mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]];
+ float deltaX = (currentPointer.x - lastPointer.x)
+ * mLocked.pointerGestureXMovementScale;
+ 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;
@@ -3939,6 +3976,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
}
}
+ mPointerGesture.pointerVelocityControl.reset();
+
if (!tapped) {
#if DEBUG_GESTURES
LOGD("Gestures: NEUTRAL");
@@ -3995,9 +4034,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;
@@ -4063,16 +4106,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)) {
@@ -4093,37 +4152,18 @@ 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;
+ mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX,
+ &mPointerGesture.referenceTouchY);
+ mPointerController->getPosition(&mPointerGesture.referenceGestureX,
+ &mPointerGesture.referenceGestureY);
}
- } 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) {
@@ -4253,10 +4293,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);
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index a7c6629..5abf404 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -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.
@@ -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
@@ -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) { }
};
@@ -630,6 +638,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 {
@@ -1160,6 +1174,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;
@@ -1174,6 +1191,7 @@ private:
velocityTracker.clear();
resetTap();
resetQuietTime();
+ pointerVelocityControl.reset();
}
void resetTap() {