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

Commit 6443d46f authored by Harry Cutts's avatar Harry Cutts Committed by Automerger Merge Worker
Browse files

Merge "CapturedTouchpadEventConverter: fix button reporting" into udc-dev am: 66fe0d35

parents 8b5c3083 66fe0d35
Loading
Loading
Loading
Loading
+23 −5
Original line number Diff line number Diff line
@@ -199,6 +199,29 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t
        }
    }

    // Send BUTTON_RELEASE events. (This has to happen before any UP events to avoid sending
    // BUTTON_RELEASE events without any pointers.)
    uint32_t newButtonState;
    if (coords.size() - upSlots.size() + downSlots.size() == 0) {
        // If there won't be any pointers down after this evdev sync, we won't be able to send
        // button updates on their own, as motion events without pointers are invalid. To avoid
        // erroneously reporting buttons being held for long periods, send BUTTON_RELEASE events for
        // all pressed buttons when the last pointer is lifted.
        //
        // This also prevents us from sending BUTTON_PRESS events too early in the case of touchpads
        // which report a button press one evdev sync before reporting a touch going down.
        newButtonState = 0;
    } else {
        newButtonState = mCursorButtonAccumulator.getButtonState();
    }
    for (uint32_t button = 1; button <= AMOTION_EVENT_BUTTON_FORWARD; button <<= 1) {
        if (!(newButtonState & button) && mButtonState & button) {
            mButtonState &= ~button;
            out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
                                         coords, properties, /*actionButton=*/button));
        }
    }

    // For any touches that were lifted, send UP or POINTER_UP events.
    for (size_t slotNumber : upSlots) {
        const size_t indexToRemove = coordsIndexForSlotNumber.at(slotNumber);
@@ -240,16 +263,11 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t
        out.push_back(makeMotionArgs(when, readTime, action, coords, properties));
    }

    const uint32_t newButtonState = mCursorButtonAccumulator.getButtonState();
    for (uint32_t button = 1; button <= AMOTION_EVENT_BUTTON_FORWARD; button <<= 1) {
        if (newButtonState & button && !(mButtonState & button)) {
            mButtonState |= button;
            out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_PRESS, coords,
                                         properties, /*actionButton=*/button));
        } else if (!(newButtonState & button) && mButtonState & button) {
            mButtonState &= ~button;
            out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
                                         coords, properties, /*actionButton=*/button));
        }
    }
    return out;
+171 −0
Original line number Diff line number Diff line
@@ -781,4 +781,175 @@ TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) {
                      WithPointerId(/*index=*/1, /*id=*/0)));
}

// Motion events without any pointers are invalid, so when a button press is reported in the same
// frame as a touch down, the button press must be reported second. Similarly with a button release
// and a touch lift.
TEST_F(CapturedTouchpadEventConverterTest,
       ButtonPressedAndReleasedInSameFrameAsTouch_ReportedWithPointers) {
    CapturedTouchpadEventConverter conv = createConverter();

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);

    processAxis(conv, EV_KEY, BTN_LEFT, 1);

    std::list<NotifyArgs> args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u),
                      WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
                      WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)));

    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
    processAxis(conv, EV_KEY, BTN_TOUCH, 0);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);

    processAxis(conv, EV_KEY, BTN_LEFT, 0);
    args = processSync(conv);
    ASSERT_EQ(3u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u),
                      WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
                      WithButtonState(0)));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_UP));
}

// Some touchpads sometimes report a button press before they report the finger touching the pad. In
// that case we need to wait until the touch comes to report the button press.
TEST_F(CapturedTouchpadEventConverterTest, ButtonPressedBeforeTouch_ReportedOnceTouchOccurs) {
    CapturedTouchpadEventConverter conv = createConverter();

    processAxis(conv, EV_KEY, BTN_LEFT, 1);
    ASSERT_EQ(0u, processSync(conv).size());

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);

    std::list<NotifyArgs> args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u),
                      WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
                      WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)));
}

// When all fingers are lifted from a touchpad, we should release any buttons that are down, since
// we won't be able to report them being lifted later if no pointers are present.
TEST_F(CapturedTouchpadEventConverterTest, ButtonReleasedAfterTouchLifts_ReportedWithLift) {
    CapturedTouchpadEventConverter conv = createConverter();

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);

    processAxis(conv, EV_KEY, BTN_LEFT, 1);

    std::list<NotifyArgs> args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));

    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
    processAxis(conv, EV_KEY, BTN_TOUCH, 0);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
    args = processSync(conv);
    ASSERT_EQ(3u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u),
                      WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
                      WithButtonState(0)));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_UP));

    processAxis(conv, EV_KEY, BTN_LEFT, 0);
    ASSERT_EQ(0u, processSync(conv).size());
}

TEST_F(CapturedTouchpadEventConverterTest, MultipleButtonsPressedDuringTouch_ReportedCorrectly) {
    CapturedTouchpadEventConverter conv = createConverter();

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                WithMotionAction(AMOTION_EVENT_ACTION_DOWN));

    processAxis(conv, EV_KEY, BTN_LEFT, 1);
    std::list<NotifyArgs> args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
                      WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
                      WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)));

    processAxis(conv, EV_KEY, BTN_RIGHT, 1);
    args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
                      WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY),
                      WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY |
                                      AMOTION_EVENT_BUTTON_SECONDARY)));

    processAxis(conv, EV_KEY, BTN_LEFT, 0);
    args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
                      WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
                      WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY)));

    processAxis(conv, EV_KEY, BTN_RIGHT, 0);
    args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
                      WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0)));
}

} // namespace android