diff options
-rw-r--r-- | include/input/AccelerationCurve.h | 11 | ||||
-rw-r--r-- | libs/input/AccelerationCurve.cpp | 21 | ||||
-rw-r--r-- | services/inputflinger/include/InputReaderBase.h | 11 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/CursorInputMapper.cpp | 22 | ||||
-rw-r--r-- | services/inputflinger/tests/CursorInputMapper_test.cpp | 29 | ||||
-rw-r--r-- | services/inputflinger/tests/TestEventMatchers.h | 17 |
6 files changed, 100 insertions, 11 deletions
diff --git a/include/input/AccelerationCurve.h b/include/input/AccelerationCurve.h index 0cf648a2f7..8a4a5d429b 100644 --- a/include/input/AccelerationCurve.h +++ b/include/input/AccelerationCurve.h @@ -46,4 +46,15 @@ struct AccelerationCurveSegment { std::vector<AccelerationCurveSegment> createAccelerationCurveForPointerSensitivity( int32_t sensitivity); +/* + * Creates a flat acceleration curve for disabling pointer acceleration. + * + * This method generates a single AccelerationCurveSegment with specific values + * to effectively disable acceleration for both mice and touchpads. + * A flat acceleration curve ensures a constant gain, meaning that the output + * velocity is directly proportional to the input velocity, resulting in + * a 1:1 movement ratio between the input device and the on-screen pointer. + */ +std::vector<AccelerationCurveSegment> createFlatAccelerationCurve(int32_t sensitivity); + } // namespace android diff --git a/libs/input/AccelerationCurve.cpp b/libs/input/AccelerationCurve.cpp index 0a92a71596..0b47f3e6e7 100644 --- a/libs/input/AccelerationCurve.cpp +++ b/libs/input/AccelerationCurve.cpp @@ -40,6 +40,18 @@ static_assert(kSegments.back().maxPointerSpeedMmPerS == std::numeric_limits<doub constexpr std::array<double, 15> kSensitivityFactors = {1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20}; +// Calculates the base gain for a given pointer sensitivity value. +// +// The base gain is a scaling factor that is applied to the pointer movement. +// Higher sensitivity values result in larger base gains, which in turn result +// in faster pointer movements. +// +// The base gain is calculated using a linear mapping function that maps the +// sensitivity range [-7, 7] to a base gain range [0.5, 2.0]. +double calculateBaseGain(int32_t sensitivity) { + return 0.5 + (sensitivity + 7) * (2.0 - 0.5) / (7 + 7); +} + } // namespace std::vector<AccelerationCurveSegment> createAccelerationCurveForPointerSensitivity( @@ -60,4 +72,13 @@ std::vector<AccelerationCurveSegment> createAccelerationCurveForPointerSensitivi return output; } +std::vector<AccelerationCurveSegment> createFlatAccelerationCurve(int32_t sensitivity) { + LOG_ALWAYS_FATAL_IF(sensitivity < -7 || sensitivity > 7, "Invalid pointer sensitivity value"); + std::vector<AccelerationCurveSegment> output = { + AccelerationCurveSegment{std::numeric_limits<double>::infinity(), + calculateBaseGain(sensitivity), + /* reciprocal = */ 0}}; + return output; +} + } // namespace android
\ No newline at end of file diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 42b269e651..404a509247 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -139,9 +139,17 @@ struct InputReaderConfiguration { // The mouse pointer speed, as a number from -7 (slowest) to 7 (fastest). int32_t mousePointerSpeed; - // Displays on which an acceleration curve shouldn't be applied for pointer movements from mice. + // Displays on which all pointer scaling, including linear scaling based on the + // user's pointer speed setting, should be disabled for mice. This differs from + // disabling acceleration via the 'mousePointerAccelerationEnabled' setting, where + // the pointer speed setting still influences the scaling factor. std::set<ui::LogicalDisplayId> displaysWithMousePointerAccelerationDisabled; + // True if the connected mouse should exhibit pointer acceleration. If false, + // a flat acceleration curve (linear scaling) is used, but the user's pointer + // speed setting still affects the scaling factor. + bool mousePointerAccelerationEnabled; + // Velocity control parameters for touchpad pointer movements on the old touchpad stack (based // on TouchInputMapper). // @@ -275,6 +283,7 @@ struct InputReaderConfiguration { defaultPointerDisplayId(ui::LogicalDisplayId::DEFAULT), mousePointerSpeed(0), displaysWithMousePointerAccelerationDisabled(), + mousePointerAccelerationEnabled(true), pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, static_cast<float>( android::os::IInputConstants:: diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index b33659cae1..e9f17e796f 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -481,15 +481,21 @@ void CursorInputMapper::configureOnChangePointerSpeed(const InputReaderConfigura mPointerVelocityControl.setAccelerationEnabled(false); mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); - } else { - mPointerVelocityControl.setAccelerationEnabled( - config.displaysWithMousePointerAccelerationDisabled.count( - mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) == 0); - mPointerVelocityControl.setCurve( - createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed)); - mWheelXVelocityControl.setParameters(config.wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(config.wheelVelocityControlParameters); + return; } + + bool disableAllScaling = config.displaysWithMousePointerAccelerationDisabled.count( + mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) != 0; + + mPointerVelocityControl.setAccelerationEnabled(!disableAllScaling); + + mPointerVelocityControl.setCurve( + config.mousePointerAccelerationEnabled + ? createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed) + : createFlatAccelerationCurve(config.mousePointerSpeed)); + + mWheelXVelocityControl.setParameters(config.wheelVelocityControlParameters); + mWheelYVelocityControl.setParameters(config.wheelVelocityControlParameters); } void CursorInputMapper::configureOnChangeDisplayInfo(const InputReaderConfiguration& config) { diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp index d4e8fdfdc5..a31c4e96d7 100644 --- a/services/inputflinger/tests/CursorInputMapper_test.cpp +++ b/services/inputflinger/tests/CursorInputMapper_test.cpp @@ -27,6 +27,7 @@ #include <com_android_input_flags.h> #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <input/AccelerationCurve.h> #include <input/DisplayViewport.h> #include <input/InputEventLabels.h> #include <linux/input-event-codes.h> @@ -1028,6 +1029,34 @@ TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdNoAssociatedViewport) { WithCoords(0.0f, 0.0f))))); } +TEST_F(CursorInputMapperUnitTest, PointerAccelerationDisabled) { + mReaderConfiguration.mousePointerAccelerationEnabled = false; + mReaderConfiguration.mousePointerSpeed = 3; + mPropertyMap.addProperty("cursor.mode", "pointer"); + createMapper(); + + std::list<NotifyArgs> reconfigureArgs; + + reconfigureArgs += mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration, + InputReaderConfiguration::Change::POINTER_SPEED); + + std::vector<AccelerationCurveSegment> curve = + createFlatAccelerationCurve(mReaderConfiguration.mousePointerSpeed); + double baseGain = curve[0].baseGain; + + std::list<NotifyArgs> motionArgs; + motionArgs += process(ARBITRARY_TIME, EV_REL, REL_X, 10); + motionArgs += process(ARBITRARY_TIME, EV_REL, REL_Y, 20); + motionArgs += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); + + const float expectedRelX = 10 * baseGain; + const float expectedRelY = 20 * baseGain; + ASSERT_THAT(motionArgs, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(HOVER_MOVE), + WithRelativeMotion(expectedRelX, expectedRelY))))); +} + TEST_F(CursorInputMapperUnitTest, ConfigureAccelerationWithAssociatedViewport) { mPropertyMap.addProperty("cursor.mode", "pointer"); DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0); diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h index 7078e49343..7fb8895719 100644 --- a/services/inputflinger/tests/TestEventMatchers.h +++ b/services/inputflinger/tests/TestEventMatchers.h @@ -32,6 +32,17 @@ namespace android { +namespace { + +template <typename T> +static bool valuesMatch(T value1, T value2) { + if constexpr (std::is_floating_point_v<T>) { + return std::abs(value1 - value2) < EPSILON; + } else { + return value1 == value2; + } +} + struct PointF { float x; float y; @@ -42,6 +53,8 @@ inline std::string pointFToString(const PointF& p) { return std::string("(") + std::to_string(p.x) + ", " + std::to_string(p.y) + ")"; } +} // namespace + /// Source class WithSourceMatcher { public: @@ -706,8 +719,8 @@ public: } const PointerCoords& coords = event.pointerCoords[mPointerIndex]; - bool matches = mRelX == coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X) && - mRelY == coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); + bool matches = valuesMatch(mRelX, coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X)) && + valuesMatch(mRelY, coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); if (!matches) { *os << "expected relative motion (" << mRelX << ", " << mRelY << ") at pointer index " << mPointerIndex << ", but got (" |