Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6523587 authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

MotionEvent: Rotate relative axes according to window orientation

We rotate the X and Y coordinates of MotionEvents when the window
transform also contains a rotation. This means we should rotate the
relative axes (AXIS_RELATIVE_{X,Y}) as well, making sure not to
translate these relative values.

Bug: 179274888
Test: libinput_tests
Test: manual with test app
Change-Id: I8c716b14ee2b3cd5362f4e9f1554ee37d6875c2d
parent 664834b6
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -318,6 +318,8 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor);
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor);
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor);
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_X, windowXScale);
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale);
}

void PointerCoords::scale(float globalScaleFactor) {
@@ -386,6 +388,15 @@ void PointerCoords::transform(const ui::Transform& transform) {
    setAxisValue(AMOTION_EVENT_AXIS_X, xy.x);
    setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y);

    if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_X) ||
        BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_Y)) {
        const ui::Transform rotation(transform.getOrientation());
        const vec2 relativeXy = rotation.transform(getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
                                                   getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
        setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, relativeXy.x);
        setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, relativeXy.y);
    }

    if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_ORIENTATION)) {
        const float val = getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
        setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(transform, val));
@@ -530,6 +541,15 @@ float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
        return xy[axis];
    }

    if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
        // For compatibility, since we convert raw coordinates into "oriented screen space", we
        // need to convert the relative axes into the same orientation for consistency.
        const vec2 relativeXy =
                rotatePoint(mTransform, coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
                            coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
        return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
    }

    return coords->getAxisValue(axis);
}

@@ -545,6 +565,16 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
        return xy[axis];
    }

    if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
        const vec2 relativeXy =
                applyTransformWithoutTranslation(mTransform,
                                                 coords->getAxisValue(
                                                         AMOTION_EVENT_AXIS_RELATIVE_X),
                                                 coords->getAxisValue(
                                                         AMOTION_EVENT_AXIS_RELATIVE_Y));
        return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
    }

    return coords->getAxisValue(axis);
}

+35 −10
Original line number Diff line number Diff line
@@ -636,13 +636,16 @@ TEST_F(MotionEventTest, Transform) {
    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
}

MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) {
MotionEvent createTouchDownEvent(float x, float y, float dx, float dy,
                                 const ui::Transform& transform) {
    std::vector<PointerProperties> pointerProperties;
    pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER});
    std::vector<PointerCoords> pointerCoords;
    pointerCoords.emplace_back().clear();
    pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, x);
    pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, y);
    pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, dx);
    pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy);
    nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
    MotionEvent event;
    event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN,
@@ -661,26 +664,36 @@ TEST_F(MotionEventTest, ApplyTransform) {
    ui::Transform identity;
    ui::Transform xform(ui::Transform::ROT_90, 800, 400);
    xform.set(xform.tx() + 20, xform.ty() + 40);
    MotionEvent event = createTouchDownEvent(60, 100, xform);
    MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
    ASSERT_EQ(700, event.getRawX(0));
    ASSERT_EQ(60, event.getRawY(0));
    ASSERT_NE(event.getRawX(0), event.getX(0));
    ASSERT_NE(event.getRawY(0), event.getY(0));
    // Relative values should be rotated but not translated.
    ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
    ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));

    MotionEvent changedEvent = createTouchDownEvent(60, 100, identity);
    MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity);
    const std::array<float, 9> rowMajor{xform[0][0], xform[1][0], xform[2][0],
                                        xform[0][1], xform[1][1], xform[2][1],
                                        xform[0][2], xform[1][2], xform[2][2]};
    changedEvent.applyTransform(rowMajor);

    // transformContent effectively rotates the raw coordinates, so those should now include
    // both rotation AND offset
    // both rotation AND offset.
    ASSERT_EQ(720, changedEvent.getRawX(0));
    ASSERT_EQ(100, changedEvent.getRawY(0));
    // Relative values should be rotated but not translated.
    ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
    ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));

    // The transformed output should be the same then
    // The transformed output should be the same then.
    ASSERT_NEAR(event.getX(0), changedEvent.getX(0), 0.001);
    ASSERT_NEAR(event.getY(0), changedEvent.getY(0), 0.001);
    ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0),
                changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), 0.001);
    ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0),
                changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), 0.001);
}

TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) {
@@ -691,7 +704,7 @@ TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) {
        // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
        ui::Transform xform(ui::Transform::ROT_90, 800, 400);
        xform.set(xform.tx() + 20, xform.ty() + 40);
        MotionEvent event = createTouchDownEvent(60, 100, xform);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        event.setSource(source);

        // Since this event comes from a non-pointer source, it should include rotation but not
@@ -708,11 +721,14 @@ TEST_F(MotionEventTest, RawCompatTransform) {
        // Make sure raw is raw regardless of transform translation.
        ui::Transform xform;
        xform.set(20, 40);
        MotionEvent event = createTouchDownEvent(60, 100, xform);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        ASSERT_EQ(60, event.getRawX(0));
        ASSERT_EQ(100, event.getRawY(0));
        ASSERT_NE(event.getRawX(0), event.getX(0));
        ASSERT_NE(event.getRawY(0), event.getY(0));
        // Relative values should not be modified.
        ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
        ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
    }

    // Next check that getRaw contains rotation (for compatibility) but otherwise is still
@@ -721,29 +737,38 @@ TEST_F(MotionEventTest, RawCompatTransform) {
        // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
        ui::Transform xform(ui::Transform::ROT_90, 800, 400);
        xform.set(xform.tx() + 20, xform.ty() + 40);
        MotionEvent event = createTouchDownEvent(60, 100, xform);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        ASSERT_EQ(700, event.getRawX(0));
        ASSERT_EQ(60, event.getRawY(0));
        ASSERT_NE(event.getRawX(0), event.getX(0));
        ASSERT_NE(event.getRawY(0), event.getY(0));
        // Relative values should be rotated but not translated.
        ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
        ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
    }

    {
        // Same as above, but check rotate-180.
        ui::Transform xform(ui::Transform::ROT_180, 400, 800);
        xform.set(xform.tx() + 20, xform.ty() + 40);
        MotionEvent event = createTouchDownEvent(60, 100, xform);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        ASSERT_EQ(340, event.getRawX(0));
        ASSERT_EQ(700, event.getRawY(0));
        // Relative values should be rotated but not translated.
        ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
        ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
    }

    {
        // Same as above, but check rotate-270.
        ui::Transform xform(ui::Transform::ROT_270, 800, 400);
        xform.set(xform.tx() + 20, xform.ty() + 40);
        MotionEvent event = createTouchDownEvent(60, 100, xform);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        ASSERT_EQ(100, event.getRawX(0));
        ASSERT_EQ(340, event.getRawY(0));
        // Relative values should be rotated but not translated.
        ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
        ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
    }
}