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

Commit 34bda038 authored by Xin Li's avatar Xin Li
Browse files

Merge 2024-06 Release (ab/AP2A.240605.024) to aosp-main-future

Bug: 343100748
Merged-In: Ie57b7112bcaa2306b2b5171707822c46bc9f2c52
Change-Id: I5d17bf549178ccc20ecb51a15094b26126fb0d1b
parents 8e0660dc 8b1d65e8
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -37,6 +37,13 @@

namespace aidl::android::os {

#if defined(__ANDROID_VENDOR__)
#define AT_LEAST_V_OR_202404 constexpr(__ANDROID_VENDOR_API__ >= 202404)
#else
// TODO(b/322384429) switch this to __ANDROID_API_V__ when V is finalized
#define AT_LEAST_V_OR_202404 (__builtin_available(android __ANDROID_API_FUTURE__, *))
#endif

/**
 * Wrapper class that enables interop with AIDL NDK generation
 * Takes ownership of the APersistableBundle* given to it in reset() and will automatically
+188 −81
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
namespace android {

namespace {

bool isFromMouse(const NotifyMotionArgs& args) {
    return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
            args.pointerProperties[0].toolType == ToolType::MOUSE;
@@ -36,6 +37,11 @@ bool isFromTouchpad(const NotifyMotionArgs& args) {
            args.pointerProperties[0].toolType == ToolType::FINGER;
}

bool isFromDrawingTablet(const NotifyMotionArgs& args) {
    return isFromSource(args.source, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS) &&
            isStylusToolType(args.pointerProperties[0].toolType);
}

bool isHoverAction(int32_t action) {
    return action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
            action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT;
@@ -44,13 +50,42 @@ bool isHoverAction(int32_t action) {
bool isStylusHoverEvent(const NotifyMotionArgs& args) {
    return isStylusEvent(args.source, args.pointerProperties) && isHoverAction(args.action);
}

bool isMouseOrTouchpad(uint32_t sources) {
    // Check if this is a mouse or touchpad, but not a drawing tablet.
    return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) ||
            (isFromSource(sources, AINPUT_SOURCE_MOUSE) &&
             !isFromSource(sources, AINPUT_SOURCE_STYLUS));
}

inline void notifyPointerDisplayChange(std::optional<std::tuple<int32_t, FloatPoint>> change,
                                       PointerChoreographerPolicyInterface& policy) {
    if (!change) {
        return;
    }
    const auto& [displayId, cursorPosition] = *change;
    policy.notifyPointerDisplayIdChanged(displayId, cursorPosition);
}

void setIconForController(const std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle>& icon,
                          PointerControllerInterface& controller) {
    if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
        if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
            LOG(FATAL) << "SpriteIcon should not be null";
        }
        controller.setCustomPointerIcon(*std::get<std::unique_ptr<SpriteIcon>>(icon));
    } else {
        controller.updatePointerIcon(std::get<PointerIconStyle>(icon));
    }
}

} // namespace

// --- PointerChoreographer ---

PointerChoreographer::PointerChoreographer(InputListenerInterface& listener,
                                           PointerChoreographerPolicyInterface& policy)
      : mTouchControllerConstructor([this]() REQUIRES(mLock) {
      : mTouchControllerConstructor([this]() {
            return mPolicy.createPointerController(
                    PointerControllerInterface::ControllerType::TOUCH);
        }),
@@ -62,10 +97,16 @@ PointerChoreographer::PointerChoreographer(InputListenerInterface& listener,
        mStylusPointerIconEnabled(false) {}

void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
    PointerDisplayChange pointerDisplayChange;

    { // acquire lock
        std::scoped_lock _l(mLock);

        mInputDeviceInfos = args.inputDeviceInfos;
    updatePointerControllersLocked();
        pointerDisplayChange = updatePointerControllersLocked();
    } // release lock

    notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
    mNextListener.notify(args);
}

@@ -90,6 +131,8 @@ NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& arg
        return processMouseEventLocked(args);
    } else if (isFromTouchpad(args)) {
        return processTouchpadEventLocked(args);
    } else if (isFromDrawingTablet(args)) {
        processDrawingTabletEventLocked(args);
    } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
        processStylusHoverEventLocked(args);
    } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
@@ -104,7 +147,7 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio
                   << args.dump();
    }

    auto [displayId, pc] = getDisplayIdAndMouseControllerLocked(args.displayId);
    auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);

    const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
    const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
@@ -124,7 +167,7 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio
}

NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
    auto [displayId, pc] = getDisplayIdAndMouseControllerLocked(args.displayId);
    auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);

    NotifyMotionArgs newArgs(args);
    newArgs.displayId = displayId;
@@ -161,6 +204,36 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo
    return newArgs;
}

void PointerChoreographer::processDrawingTabletEventLocked(const android::NotifyMotionArgs& args) {
    if (args.displayId == ADISPLAY_ID_NONE) {
        return;
    }

    if (args.getPointerCount() != 1) {
        LOG(WARNING) << "Only drawing tablet events with a single pointer are currently supported: "
                     << args.dump();
    }

    // Use a mouse pointer controller for drawing tablets, or create one if it doesn't exist.
    auto [it, _] = mDrawingTabletPointersByDevice.try_emplace(args.deviceId,
                                                              getMouseControllerConstructor(
                                                                      args.displayId));

    PointerControllerInterface& pc = *it->second;

    const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
    const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
    pc.setPosition(x, y);
    if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
        // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
        //   immediately by a DOWN event.
        pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
        pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
    } else if (canUnfadeOnDisplay(args.displayId)) {
        pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
    }
}

/**
 * When screen is touched, fade the mouse pointer on that display. We only call fade for
 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
@@ -227,6 +300,8 @@ void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs&
    const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
    pc.setPosition(x, y);
    if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
        // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
        //   immediately by a DOWN event.
        pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
        pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
    } else if (canUnfadeOnDisplay(args.displayId)) {
@@ -256,6 +331,7 @@ void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args)
    std::scoped_lock _l(mLock);
    mTouchPointersByDevice.erase(args.deviceId);
    mStylusPointersByDevice.erase(args.deviceId);
    mDrawingTabletPointersByDevice.erase(args.deviceId);
}

void PointerChoreographer::notifyPointerCaptureChanged(
@@ -292,6 +368,11 @@ void PointerChoreographer::dump(std::string& dump) {
        std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT);
        dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
    }
    dump += INDENT "DrawingTabletControllers:\n";
    for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
        std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT);
        dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
    }
    dump += "\n";
}

@@ -308,17 +389,13 @@ int32_t PointerChoreographer::getTargetMouseDisplayLocked(int32_t associatedDisp
    return associatedDisplayId == ADISPLAY_ID_NONE ? mDefaultMouseDisplayId : associatedDisplayId;
}

std::pair<int32_t, PointerControllerInterface&>
PointerChoreographer::getDisplayIdAndMouseControllerLocked(int32_t associatedDisplayId) {
std::pair<int32_t, PointerControllerInterface&> PointerChoreographer::ensureMouseControllerLocked(
        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();
    }
    auto it = mMousePointersByDisplay.find(displayId);
    LOG_ALWAYS_FATAL_IF(it == mMousePointersByDisplay.end(),
                        "There is no mouse controller created for display %d", displayId);

    return {displayId, *it->second};
}
@@ -333,17 +410,17 @@ bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) {
    return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
}

void PointerChoreographer::updatePointerControllersLocked() {
PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerControllersLocked() {
    std::set<int32_t /*displayId*/> mouseDisplaysToKeep;
    std::set<DeviceId> touchDevicesToKeep;
    std::set<DeviceId> stylusDevicesToKeep;
    std::set<DeviceId> drawingTabletDevicesToKeep;

    // Mark the displayIds or deviceIds of PointerControllers currently needed, and create
    // new PointerControllers if necessary.
    for (const auto& info : mInputDeviceInfos) {
        const uint32_t sources = info.getSources();
        if (isFromSource(sources, AINPUT_SOURCE_MOUSE) ||
            isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE)) {
        if (isMouseOrTouchpad(sources)) {
            const int32_t displayId = getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
            mouseDisplaysToKeep.insert(displayId);
            // For mice, show the cursor immediately when the device is first connected or
@@ -364,6 +441,10 @@ void PointerChoreographer::updatePointerControllersLocked() {
            info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) {
            stylusDevicesToKeep.insert(info.getId());
        }
        if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE) &&
            info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) {
            drawingTabletDevicesToKeep.insert(info.getId());
        }
    }

    // Remove PointerControllers no longer needed.
@@ -376,17 +457,21 @@ void PointerChoreographer::updatePointerControllersLocked() {
    std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) {
        return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end();
    });
    std::erase_if(mDrawingTabletPointersByDevice, [&drawingTabletDevicesToKeep](const auto& pair) {
        return drawingTabletDevicesToKeep.find(pair.first) == drawingTabletDevicesToKeep.end();
    });
    std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(mLock) {
        return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
                            [id](const auto& info) { return info.getId() == id; }) ==
                mInputDeviceInfos.end();
    });

    // Notify the policy if there's a change on the pointer display ID.
    notifyPointerDisplayIdChangedLocked();
    // Check if we need to notify the policy if there's a change on the pointer display ID.
    return calculatePointerDisplayChangeToNotify();
}

void PointerChoreographer::notifyPointerDisplayIdChangedLocked() {
PointerChoreographer::PointerDisplayChange
PointerChoreographer::calculatePointerDisplayChangeToNotify() {
    int32_t displayIdToNotify = ADISPLAY_ID_NONE;
    FloatPoint cursorPosition = {0, 0};
    if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
@@ -398,22 +483,30 @@ void PointerChoreographer::notifyPointerDisplayIdChangedLocked() {
        displayIdToNotify = pointerController->getDisplayId();
        cursorPosition = pointerController->getPosition();
    }

    if (mNotifiedPointerDisplayId == displayIdToNotify) {
        return;
        return {};
    }
    mPolicy.notifyPointerDisplayIdChanged(displayIdToNotify, cursorPosition);
    mNotifiedPointerDisplayId = displayIdToNotify;
    return {{displayIdToNotify, cursorPosition}};
}

void PointerChoreographer::setDefaultMouseDisplayId(int32_t displayId) {
    PointerDisplayChange pointerDisplayChange;

    { // acquire lock
        std::scoped_lock _l(mLock);

        mDefaultMouseDisplayId = displayId;
    updatePointerControllersLocked();
        pointerDisplayChange = updatePointerControllersLocked();
    } // release lock

    notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
}

void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
    PointerDisplayChange pointerDisplayChange;

    { // acquire lock
        std::scoped_lock _l(mLock);
        for (const auto& viewport : viewports) {
            const int32_t displayId = viewport.displayId;
@@ -427,9 +520,18 @@ void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport
                    stylusPointerController->setDisplayViewport(viewport);
                }
            }
            for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
                const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
                if (info && info->getAssociatedDisplayId() == displayId) {
                    drawingTabletController->setDisplayViewport(viewport);
                }
            }
        }
        mViewports = viewports;
    notifyPointerDisplayIdChangedLocked();
        pointerDisplayChange = calculatePointerDisplayChangeToNotify();
    } // release lock

    notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
}

std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
@@ -453,21 +555,33 @@ FloatPoint PointerChoreographer::getMouseCursorPosition(int32_t displayId) {
}

void PointerChoreographer::setShowTouchesEnabled(bool enabled) {
    PointerDisplayChange pointerDisplayChange;

    { // acquire lock
        std::scoped_lock _l(mLock);
        if (mShowTouchesEnabled == enabled) {
            return;
        }
        mShowTouchesEnabled = enabled;
    updatePointerControllersLocked();
        pointerDisplayChange = updatePointerControllersLocked();
    } // release lock

    notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
}

void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) {
    PointerDisplayChange pointerDisplayChange;

    { // acquire lock
        std::scoped_lock _l(mLock);
        if (mStylusPointerIconEnabled == enabled) {
            return;
        }
        mStylusPointerIconEnabled = enabled;
    updatePointerControllersLocked();
        pointerDisplayChange = updatePointerControllersLocked();
    } // release lock

    notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
}

bool PointerChoreographer::setPointerIcon(
@@ -485,42 +599,35 @@ bool PointerChoreographer::setPointerIcon(
        return false;
    }
    const uint32_t sources = info->getSources();
    const auto stylusPointerIt = mStylusPointersByDevice.find(deviceId);

    if (isFromSource(sources, AINPUT_SOURCE_STYLUS) &&
        stylusPointerIt != mStylusPointersByDevice.end()) {
        if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
            if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
                LOG(FATAL) << "SpriteIcon should not be null";
    if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE)) {
        auto it = mDrawingTabletPointersByDevice.find(deviceId);
        if (it != mDrawingTabletPointersByDevice.end()) {
            setIconForController(icon, *it->second);
            return true;
        }
            stylusPointerIt->second->setCustomPointerIcon(
                    *std::get<std::unique_ptr<SpriteIcon>>(icon));
        } else {
            stylusPointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
    }
    } else if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
        if (const auto mousePointerIt = mMousePointersByDisplay.find(displayId);
            mousePointerIt != mMousePointersByDisplay.end()) {
            if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
                if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
                    LOG(FATAL) << "SpriteIcon should not be null";
    if (isFromSource(sources, AINPUT_SOURCE_STYLUS)) {
        auto it = mStylusPointersByDevice.find(deviceId);
        if (it != mStylusPointersByDevice.end()) {
            setIconForController(icon, *it->second);
            return true;
        }
                mousePointerIt->second->setCustomPointerIcon(
                        *std::get<std::unique_ptr<SpriteIcon>>(icon));
            } else {
                mousePointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
    }
    if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
        auto it = mMousePointersByDisplay.find(displayId);
        if (it != mMousePointersByDisplay.end()) {
            setIconForController(icon, *it->second);
            return true;
        } else {
            LOG(WARNING) << "No mouse pointer controller found for display " << displayId
                         << ", device " << deviceId << ".";
            return false;
        }
    } else {
        LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device "
                     << deviceId << ".";
        return false;
    }
    return true;
    LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device " << deviceId
                 << ".";
    return false;
}

void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) {
+8 −3
Original line number Diff line number Diff line
@@ -109,11 +109,13 @@ public:
    void dump(std::string& dump) override;

private:
    void updatePointerControllersLocked() REQUIRES(mLock);
    void notifyPointerDisplayIdChangedLocked() REQUIRES(mLock);
    using PointerDisplayChange =
            std::optional<std::tuple<int32_t /*displayId*/, FloatPoint /*cursorPosition*/>>;
    [[nodiscard]] PointerDisplayChange updatePointerControllersLocked() REQUIRES(mLock);
    [[nodiscard]] PointerDisplayChange calculatePointerDisplayChangeToNotify() 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(
    std::pair<int32_t /*displayId*/, PointerControllerInterface&> ensureMouseControllerLocked(
            int32_t associatedDisplayId) REQUIRES(mLock);
    InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(mLock);
    bool canUnfadeOnDisplay(int32_t displayId) REQUIRES(mLock);
@@ -121,6 +123,7 @@ private:
    NotifyMotionArgs processMotion(const NotifyMotionArgs& args);
    NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    NotifyMotionArgs processTouchpadEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    void processDrawingTabletEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    void processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    void processStylusHoverEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
    void processDeviceReset(const NotifyDeviceResetArgs& args);
@@ -142,6 +145,8 @@ private:
            GUARDED_BY(mLock);
    std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mStylusPointersByDevice
            GUARDED_BY(mLock);
    std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mDrawingTabletPointersByDevice
            GUARDED_BY(mLock);

    int32_t mDefaultMouseDisplayId GUARDED_BY(mLock);
    int32_t mNotifiedPointerDisplayId GUARDED_BY(mLock);
+6 −0
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@ namespace android {
 *
 * This is the interface that PointerChoreographer uses to talk to Window Manager and other
 * system components.
 *
 * NOTE: In general, the PointerChoreographer must not interact with the policy while
 * holding any locks.
 */
class PointerChoreographerPolicyInterface {
public:
@@ -37,6 +40,9 @@ public:
     * for and runnable on the host, the PointerController implementation must be in a separate
     * library, libinputservice, that has the additional dependencies. The PointerController
     * will be mocked when testing PointerChoreographer.
     *
     * Since this is a factory method used to work around dependencies, it will not interact with
     * other input components and may be called with the PointerChoreographer lock held.
     */
    virtual std::shared_ptr<PointerControllerInterface> createPointerController(
            PointerControllerInterface::ControllerType type) = 0;
+1 −6
Original line number Diff line number Diff line
@@ -509,13 +509,8 @@ std::vector<std::unique_ptr<InputMapper>> InputDevice::createMappers(
    // Touchscreens and touchpad devices.
    static const bool ENABLE_TOUCHPAD_GESTURES_LIBRARY =
            sysprop::InputProperties::enable_touchpad_gestures_library().value_or(true);
    // TODO(b/272518665): Fix the new touchpad stack for Sony DualShock 4 (5c4, 9cc) touchpads, or
    // at least load this setting from the IDC file.
    const InputDeviceIdentifier identifier = contextPtr.getDeviceIdentifier();
    const bool isSonyDualShock4Touchpad = identifier.vendor == 0x054c &&
            (identifier.product == 0x05c4 || identifier.product == 0x09cc);
    if (ENABLE_TOUCHPAD_GESTURES_LIBRARY && classes.test(InputDeviceClass::TOUCHPAD) &&
        classes.test(InputDeviceClass::TOUCH_MT) && !isSonyDualShock4Touchpad) {
        classes.test(InputDeviceClass::TOUCH_MT)) {
        mappers.push_back(createInputMapper<TouchpadInputMapper>(contextPtr, readerConfig));
    } else if (classes.test(InputDeviceClass::TOUCH_MT)) {
        mappers.push_back(createInputMapper<MultiTouchInputMapper>(contextPtr, readerConfig));
Loading