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

Commit ee6268f0 authored by Byoungho Jung's avatar Byoungho Jung Committed by Prabir Pradhan
Browse files

Pointer icon refactor for touchpad

With PointerChoreographer enabled, touchpads work similar to mice,
using MousePointerController of the associated display.
For some gestures like scroll or multi-finger swipes,
TouchpadInputMapper sets fake finger coordinates and
PointerChoreographer combines cursor position with them.

Test: atest inputflinger_tests
Bug: 293587049
Change-Id: I0f6588c79004284df98d99351ea3c3e64b636a74
parent a0a24d7c
Loading
Loading
Loading
Loading
+57 −11
Original line number Diff line number Diff line
@@ -31,6 +31,11 @@ bool isFromMouse(const NotifyMotionArgs& args) {
            args.pointerProperties[0].toolType == ToolType::MOUSE;
}

bool isFromTouchpad(const NotifyMotionArgs& args) {
    return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
            args.pointerProperties[0].toolType == ToolType::FINGER;
}

bool isHoverAction(int32_t action) {
    return action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
            action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT;
@@ -83,6 +88,8 @@ NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& arg

    if (isFromMouse(args)) {
        return processMouseEventLocked(args);
    } else if (isFromTouchpad(args)) {
        return processTouchpadEventLocked(args);
    } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
        processStylusHoverEventLocked(args);
    } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
@@ -97,30 +104,54 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio
                   << args.dump();
    }

    const int32_t displayId = getTargetMouseDisplayLocked(args.displayId);
    auto [displayId, pc] = getDisplayIdAndMouseControllerLocked(args.displayId);

    // Get the mouse pointer controller for the display, or create one if it doesn't exist.
    auto [it, emplaced] =
            mMousePointersByDisplay.try_emplace(displayId,
                                                getMouseControllerConstructor(displayId));
    if (emplaced) {
        notifyPointerDisplayIdChangedLocked();
    const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
    const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
    pc.move(deltaX, deltaY);
    pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);

    const auto [x, y] = pc.getPosition();
    NotifyMotionArgs newArgs(args);
    newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
    newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
    newArgs.xCursorPosition = x;
    newArgs.yCursorPosition = y;
    newArgs.displayId = displayId;
    return newArgs;
}

    PointerControllerInterface& pc = *it->second;
NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
    auto [displayId, pc] = getDisplayIdAndMouseControllerLocked(args.displayId);

    NotifyMotionArgs newArgs(args);
    newArgs.displayId = displayId;
    if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) {
        // This is a movement of the mouse pointer.
        const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
        const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
        pc.move(deltaX, deltaY);
        pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);

        const auto [x, y] = pc.getPosition();
    NotifyMotionArgs newArgs(args);
        newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
        newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
        newArgs.xCursorPosition = x;
        newArgs.yCursorPosition = y;
    newArgs.displayId = displayId;
    } else {
        // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
        pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);

        const auto [x, y] = pc.getPosition();
        for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
            newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
                                                  args.pointerCoords[i].getX() + x);
            newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
                                                  args.pointerCoords[i].getY() + y);
        }
        newArgs.xCursorPosition = x;
        newArgs.yCursorPosition = y;
    }
    return newArgs;
}

@@ -270,6 +301,21 @@ int32_t PointerChoreographer::getTargetMouseDisplayLocked(int32_t associatedDisp
    return associatedDisplayId == ADISPLAY_ID_NONE ? mDefaultMouseDisplayId : associatedDisplayId;
}

std::pair<int32_t, PointerControllerInterface&>
PointerChoreographer::getDisplayIdAndMouseControllerLocked(int32_t associatedDisplayId) {
    const int32_t displayId = getTargetMouseDisplayLocked(associatedDisplayId);

    // Get the mouse pointer controller for the display, or create one if it doesn't exist.
    auto [it, emplaced] =
            mMousePointersByDisplay.try_emplace(displayId,
                                                getMouseControllerConstructor(displayId));
    if (emplaced) {
        notifyPointerDisplayIdChangedLocked();
    }

    return {displayId, *it->second};
}

InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) {
    auto it = std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
                           [deviceId](const auto& info) { return info.getId() == deviceId; });
+3 −0
Original line number Diff line number Diff line
@@ -95,10 +95,13 @@ private:
    void notifyPointerDisplayIdChangedLocked() REQUIRES(mLock);
    const DisplayViewport* findViewportByIdLocked(int32_t displayId) const REQUIRES(mLock);
    int32_t getTargetMouseDisplayLocked(int32_t associatedDisplayId) const REQUIRES(mLock);
    std::pair<int32_t, PointerControllerInterface&> getDisplayIdAndMouseControllerLocked(
            int32_t associatedDisplayId) REQUIRES(mLock);
    InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(mLock);

    NotifyMotionArgs processMotion(const NotifyMotionArgs& args);
    NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    NotifyMotionArgs processTouchpadEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    void processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    void processStylusHoverEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    void processDeviceReset(const NotifyDeviceResetArgs& args);
+2 −4
Original line number Diff line number Diff line
@@ -527,10 +527,8 @@ void CursorInputMapper::configureOnChangeDisplayInfo(const InputReaderConfigurat
        if (mEnablePointerChoreographer) {
            // Always use DISPLAY_ID_NONE for mouse events.
            // PointerChoreographer will make it target the correct the displayId later.
            const auto pointerViewport =
                    getContext()->getPolicy()->getPointerViewportForAssociatedDisplay();
            mDisplayId = pointerViewport ? std::make_optional(ADISPLAY_ID_NONE) : std::nullopt;
            resolvedViewport = pointerViewport;
            resolvedViewport = getContext()->getPolicy()->getPointerViewportForAssociatedDisplay();
            mDisplayId = resolvedViewport ? std::make_optional(ADISPLAY_ID_NONE) : std::nullopt;
        } else {
            mDisplayId = mPointerController->getDisplayId();
            if (auto v = config.getDisplayViewportById(*mDisplayId); v) {
+44 −18
Original line number Diff line number Diff line
@@ -246,7 +246,8 @@ TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext,
        mStateConverter(deviceContext, mMotionAccumulator),
        mGestureConverter(*getContext(), deviceContext, getDeviceId()),
        mCapturedEventConverter(*getContext(), deviceContext, mMotionAccumulator, getDeviceId()),
        mMetricsId(metricsIdFromInputDeviceIdentifier(deviceContext.getDeviceIdentifier())) {
        mMetricsId(metricsIdFromInputDeviceIdentifier(deviceContext.getDeviceIdentifier())),
        mEnablePointerChoreographer(input_flags::enable_pointer_choreographer()) {
    RawAbsoluteAxisInfo slotAxisInfo;
    deviceContext.getAbsoluteAxisInfo(ABS_MT_SLOT, &slotAxisInfo);
    if (!slotAxisInfo.valid || slotAxisInfo.maxValue <= 0) {
@@ -331,31 +332,56 @@ std::list<NotifyArgs> TouchpadInputMapper::reconfigure(nsecs_t when,

    if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) {
        mDisplayId = ADISPLAY_ID_NONE;
        if (auto viewport = mDeviceContext.getAssociatedViewport(); viewport) {
        std::optional<DisplayViewport> resolvedViewport;
        std::optional<FloatRect> boundsInLogicalDisplay;
        if (auto assocViewport = mDeviceContext.getAssociatedViewport(); assocViewport) {
            // This InputDevice is associated with a viewport.
            // Only generate events for the associated display.
            mDisplayId = assocViewport->displayId;
            resolvedViewport = *assocViewport;
            if (!mEnablePointerChoreographer) {
                const bool mismatchedPointerDisplay =
                    (viewport->displayId != mPointerController->getDisplayId());
                        (assocViewport->displayId != mPointerController->getDisplayId());
                if (mismatchedPointerDisplay) {
                    ALOGW("Touchpad \"%s\" associated viewport display does not match pointer "
                          "controller",
                          mDeviceContext.getName().c_str());
                    mDisplayId.reset();
                }
            }
            mDisplayId = mismatchedPointerDisplay ? std::nullopt
                                                  : std::make_optional(viewport->displayId);
        } else {
            // The InputDevice is not associated with a viewport, but it controls the mouse pointer.
            if (mEnablePointerChoreographer) {
                // Always use DISPLAY_ID_NONE for touchpad events.
                // PointerChoreographer will make it target the correct the displayId later.
                resolvedViewport =
                        getContext()->getPolicy()->getPointerViewportForAssociatedDisplay();
                mDisplayId = resolvedViewport ? std::make_optional(ADISPLAY_ID_NONE) : std::nullopt;
            } else {
                mDisplayId = mPointerController->getDisplayId();
                if (auto v = config.getDisplayViewportById(*mDisplayId); v) {
                    resolvedViewport = *v;
                }

        ui::Rotation orientation = ui::ROTATION_0;
        if (mDisplayId.has_value()) {
            if (auto viewport = config.getDisplayViewportById(*mDisplayId); viewport) {
                orientation = getInverseRotation(viewport->orientation);
                if (auto bounds = mPointerController->getBounds(); bounds) {
                    boundsInLogicalDisplay = *bounds;
                }
            }
        }

        mGestureConverter.setDisplayId(mDisplayId);
        mGestureConverter.setOrientation(orientation);
        mGestureConverter.setOrientation(resolvedViewport
                                                 ? getInverseRotation(resolvedViewport->orientation)
                                                 : ui::ROTATION_0);

        if (!boundsInLogicalDisplay) {
            boundsInLogicalDisplay = resolvedViewport
                    ? FloatRect{static_cast<float>(resolvedViewport->logicalLeft),
                                static_cast<float>(resolvedViewport->logicalTop),
                                static_cast<float>(resolvedViewport->logicalRight - 1),
                                static_cast<float>(resolvedViewport->logicalBottom - 1)}
                    : FloatRect{0, 0, 0, 0};
        }
        mGestureConverter.setBoundsInLogicalDisplay(*boundsInLogicalDisplay);
    }
    if (!changes.any() || changes.test(InputReaderConfiguration::Change::TOUCHPAD_SETTINGS)) {
        mPropertyProvider.getProperty("Use Custom Touchpad Pointer Accel Curve")
+2 −0
Original line number Diff line number Diff line
@@ -107,6 +107,8 @@ private:
    // Tracking IDs for touches that have at some point been reported as palms by the touchpad.
    std::set<int32_t> mPalmTrackingIds;

    const bool mEnablePointerChoreographer;

    // The display that events generated by this mapper should target. This can be set to
    // ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e.
    // std::nullopt), all events will be ignored.
Loading