summaryrefslogtreecommitdiff
path: root/libs/input/VelocityControl.cpp
diff options
context:
space:
mode:
author Xin Li <delphij@google.com> 2024-05-24 08:27:45 -0700
committer Xin Li <delphij@google.com> 2024-05-24 08:27:45 -0700
commit5968781840bb5bead4758c9adb1e41bbea1c24c7 (patch)
treed0c6e21063ef3a2265bd3071e363ddfe9ccf618b /libs/input/VelocityControl.cpp
parenta99e1cd67b5d2237200bf23b44a03e0eb31e9326 (diff)
parent8bf4487ae52ce8d1797ea58dd0b1109255518ceb (diff)
Merge Android 24Q2 Release (ab/11526283) to aosp-main-future
Bug: 337098550 Merged-In: I8d975b81afd2cde1d543e8bc7e730a6e42393bec Change-Id: I714982d2b0df34afc9f9729deb2636de5d0c7b64
Diffstat (limited to 'libs/input/VelocityControl.cpp')
-rw-r--r--libs/input/VelocityControl.cpp210
1 files changed, 146 insertions, 64 deletions
diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp
index c835a081a5..edd31e91d3 100644
--- a/libs/input/VelocityControl.cpp
+++ b/libs/input/VelocityControl.cpp
@@ -15,7 +15,6 @@
*/
#define LOG_TAG "VelocityControl"
-//#define LOG_NDEBUG 0
// Log debug messages about acceleration.
static constexpr bool DEBUG_ACCELERATION = false;
@@ -23,6 +22,7 @@ static constexpr bool DEBUG_ACCELERATION = false;
#include <math.h>
#include <limits.h>
+#include <android-base/logging.h>
#include <input/VelocityControl.h>
#include <utils/BitSet.h>
#include <utils/Timers.h>
@@ -37,15 +37,6 @@ VelocityControl::VelocityControl() {
reset();
}
-const VelocityControlParameters& VelocityControl::getParameters() const{
- return mParameters;
-}
-
-void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
- mParameters = parameters;
- reset();
-}
-
void VelocityControl::reset() {
mLastMovementTime = LLONG_MIN;
mRawPositionX = 0;
@@ -54,65 +45,156 @@ void VelocityControl::reset() {
}
void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
- if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
- if (eventTime >= mLastMovementTime + STOP_TIME) {
- if (DEBUG_ACCELERATION && mLastMovementTime != LLONG_MIN) {
- ALOGD("VelocityControl: stopped, last movement was %0.3fms ago",
- (eventTime - mLastMovementTime) * 0.000001f);
- }
- reset();
- }
+ if ((deltaX == nullptr || *deltaX == 0) && (deltaY == nullptr || *deltaY == 0)) {
+ return;
+ }
+ if (eventTime >= mLastMovementTime + STOP_TIME) {
+ ALOGD_IF(DEBUG_ACCELERATION && mLastMovementTime != LLONG_MIN,
+ "VelocityControl: stopped, last movement was %0.3fms ago",
+ (eventTime - mLastMovementTime) * 0.000001f);
+ reset();
+ }
- mLastMovementTime = eventTime;
- if (deltaX) {
- mRawPositionX += *deltaX;
- }
- if (deltaY) {
- mRawPositionY += *deltaY;
- }
- mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_X,
- mRawPositionX);
- mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_Y,
- mRawPositionY);
-
- std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0);
- std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
- float scale = mParameters.scale;
- if (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) {
- ALOGD("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);
- }
-
- } else {
- if (DEBUG_ACCELERATION) {
- ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
- mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
- mParameters.acceleration);
- }
- }
+ mLastMovementTime = eventTime;
+ if (deltaX) {
+ mRawPositionX += *deltaX;
+ }
+ if (deltaY) {
+ mRawPositionY += *deltaY;
+ }
+ mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_X, mRawPositionX);
+ mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_Y, mRawPositionY);
+ scaleDeltas(deltaX, deltaY);
+}
+
+// --- SimpleVelocityControl ---
+
+const VelocityControlParameters& SimpleVelocityControl::getParameters() const {
+ return mParameters;
+}
- if (deltaX) {
- *deltaX *= scale;
+void SimpleVelocityControl::setParameters(const VelocityControlParameters& parameters) {
+ mParameters = parameters;
+ reset();
+}
+
+void SimpleVelocityControl::scaleDeltas(float* deltaX, float* deltaY) {
+ std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0);
+ std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
+ float scale = mParameters.scale;
+ if (vx.has_value() && vy.has_value()) {
+ 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 (deltaY) {
- *deltaY *= scale;
+
+ ALOGD_IF(DEBUG_ACCELERATION,
+ "SimpleVelocityControl(%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);
+
+ } else {
+ ALOGD_IF(DEBUG_ACCELERATION,
+ "SimpleVelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
+ mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+ mParameters.acceleration);
+ }
+
+ if (deltaX != nullptr) {
+ *deltaX *= scale;
+ }
+ if (deltaY != nullptr) {
+ *deltaY *= scale;
+ }
+}
+
+// --- CurvedVelocityControl ---
+
+namespace {
+
+/**
+ * The resolution that we assume a mouse to have, in counts per inch.
+ *
+ * Mouse resolutions vary wildly, but 800 CPI is probably the most common. There should be enough
+ * range in the available sensitivity settings to accommodate users of mice with other resolutions.
+ */
+constexpr int32_t MOUSE_CPI = 800;
+
+float countsToMm(float counts) {
+ return counts / MOUSE_CPI * 25.4;
+}
+
+} // namespace
+
+CurvedVelocityControl::CurvedVelocityControl()
+ : mCurveSegments(createAccelerationCurveForPointerSensitivity(0)) {}
+
+void CurvedVelocityControl::setCurve(const std::vector<AccelerationCurveSegment>& curve) {
+ mCurveSegments = curve;
+}
+
+void CurvedVelocityControl::setAccelerationEnabled(bool enabled) {
+ mAccelerationEnabled = enabled;
+}
+
+void CurvedVelocityControl::scaleDeltas(float* deltaX, float* deltaY) {
+ if (!mAccelerationEnabled) {
+ ALOGD_IF(DEBUG_ACCELERATION, "CurvedVelocityControl: acceleration disabled");
+ return;
+ }
+
+ std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0);
+ std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
+
+ float ratio;
+ if (vx.has_value() && vy.has_value()) {
+ float vxMmPerS = countsToMm(*vx);
+ float vyMmPerS = countsToMm(*vy);
+ float speedMmPerS = sqrtf(vxMmPerS * vxMmPerS + vyMmPerS * vyMmPerS);
+
+ const AccelerationCurveSegment& seg = segmentForSpeed(speedMmPerS);
+ ratio = seg.baseGain + seg.reciprocal / speedMmPerS;
+ ALOGD_IF(DEBUG_ACCELERATION,
+ "CurvedVelocityControl: velocities (%0.3f, %0.3f) → speed %0.3f → ratio %0.3f",
+ vxMmPerS, vyMmPerS, speedMmPerS, ratio);
+ } else {
+ // We don't have enough data to compute a velocity yet. This happens early in the movement,
+ // when the speed is presumably low, so use the base gain of the first segment of the curve.
+ // (This would behave oddly for curves with a reciprocal term on the first segment, but we
+ // don't have any of those, and they'd be very strange at velocities close to zero anyway.)
+ ratio = mCurveSegments[0].baseGain;
+ ALOGD_IF(DEBUG_ACCELERATION,
+ "CurvedVelocityControl: unknown velocity, using base gain of first segment (%.3f)",
+ ratio);
+ }
+
+ if (deltaX != nullptr) {
+ *deltaX *= ratio;
+ }
+ if (deltaY != nullptr) {
+ *deltaY *= ratio;
+ }
+}
+
+const AccelerationCurveSegment& CurvedVelocityControl::segmentForSpeed(float speedMmPerS) {
+ for (const AccelerationCurveSegment& seg : mCurveSegments) {
+ if (speedMmPerS <= seg.maxPointerSpeedMmPerS) {
+ return seg;
}
}
+ ALOGE("CurvedVelocityControl: No segment found for speed %.3f; last segment should always have "
+ "a max speed of infinity.",
+ speedMmPerS);
+ return mCurveSegments.back();
}
} // namespace android