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

Commit 44981070 authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Cherrypicker Worker
Browse files

InputReader: Use shared keyboard source for all key events

When multiple EventHub devices are merged into a single InputDevice,
it's possible that there are more than one KeyboardInputMappers created
for the device. In this case, each mapper could be configured with a
different source. This can lead to situations where a device generates
key events that have different sources, depending on the mapper from
which it originated.

To make sure all key events use a consistent source for each
InputDevice, use the shared keyboard source when generating events from
a KeyboardInputMapper.

Bug: 354270482
Test: atest inputflinger_tests
Flag: EXEMPT bugfix
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:38636652797f16d84f8b5672be4d7d95d8b31947)
Merged-In: I586424b5e8d31d17cbe635d9f91a889aee906d40
Change-Id: I586424b5e8d31d17cbe635d9f91a889aee906d40
parent 9cfc94c8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -299,6 +299,7 @@ public:
    inline ftl::Flags<InputDeviceClass> getDeviceClasses() const {
        return mEventHub->getDeviceClasses(mId);
    }
    inline uint32_t getDeviceSources() const { return mDevice.getSources(); }
    inline InputDeviceIdentifier getDeviceIdentifier() const {
        return mEventHub->getDeviceIdentifier(mId);
    }
+20 −10
Original line number Diff line number Diff line
@@ -98,10 +98,10 @@ static bool isMediaKey(int32_t keyCode) {
KeyboardInputMapper::KeyboardInputMapper(InputDeviceContext& deviceContext,
                                         const InputReaderConfiguration& readerConfig,
                                         uint32_t source)
      : InputMapper(deviceContext, readerConfig), mSource(source) {}
      : InputMapper(deviceContext, readerConfig), mMapperSource(source) {}

uint32_t KeyboardInputMapper::getSources() const {
    return mSource;
    return mMapperSource;
}

ui::Rotation KeyboardInputMapper::getOrientation() {
@@ -351,8 +351,8 @@ std::list<NotifyArgs> KeyboardInputMapper::processKey(nsecs_t when, nsecs_t read
        policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
    }

    out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, deviceId, mSource,
                                   getDisplayId(), policyFlags,
    out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, deviceId,
                                   getEventSource(), getDisplayId(), policyFlags,
                                   down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, flags,
                                   keyCode, scanCode, keyMetaState, downTime));
    return out;
@@ -478,10 +478,10 @@ std::list<NotifyArgs> KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) {
    std::list<NotifyArgs> out;
    size_t n = mKeyDowns.size();
    for (size_t i = 0; i < n; i++) {
        out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when,
                                       systemTime(SYSTEM_TIME_MONOTONIC), getDeviceId(), mSource,
                                       getDisplayId(), /*policyFlags=*/0, AKEY_EVENT_ACTION_UP,
                                       mKeyDowns[i].flags | AKEY_EVENT_FLAG_CANCELED,
        out.emplace_back(
                NotifyKeyArgs(getContext()->getNextId(), when, systemTime(SYSTEM_TIME_MONOTONIC),
                              getDeviceId(), getEventSource(), getDisplayId(), /*policyFlags=*/0,
                              AKEY_EVENT_ACTION_UP, mKeyDowns[i].flags | AKEY_EVENT_FLAG_CANCELED,
                              mKeyDowns[i].keyCode, mKeyDowns[i].scanCode, AMETA_NONE,
                              mKeyDowns[i].downTime));
    }
@@ -501,4 +501,14 @@ void KeyboardInputMapper::onKeyDownProcessed(nsecs_t downTime) {
    }
}

uint32_t KeyboardInputMapper::getEventSource() const {
    // For all input events generated by this mapper, use the source that's shared across all
    // KeyboardInputMappers for this device in case there are more than one.
    static constexpr auto ALL_KEYBOARD_SOURCES =
            AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD;
    const auto deviceSources = getDeviceContext().getDeviceSources();
    LOG_ALWAYS_FATAL_IF((deviceSources & mMapperSource) != mMapperSource);
    return deviceSources & ALL_KEYBOARD_SOURCES;
}

} // namespace android
+5 −1
Original line number Diff line number Diff line
@@ -60,7 +60,10 @@ private:
        int32_t flags{};
    };

    uint32_t mSource{};
    // The keyboard source for this mapper. Events generated should use the source shared
    // by all KeyboardInputMappers for this input device.
    uint32_t mMapperSource{};

    std::optional<KeyboardLayoutInfo> mKeyboardLayoutInfo;

    std::vector<KeyDown> mKeyDowns{}; // keys that are down
@@ -106,6 +109,7 @@ private:
    std::optional<DisplayViewport> findViewport(const InputReaderConfiguration& readerConfig);
    [[nodiscard]] std::list<NotifyArgs> cancelAllDownKeys(nsecs_t when);
    void onKeyDownProcessed(nsecs_t downTime);
    uint32_t getEventSource() const;
};

} // namespace android
+5 −4
Original line number Diff line number Diff line
@@ -121,11 +121,12 @@ protected:
    T& constructAndAddMapper(Args... args) {
        // ensure a device entry exists for this eventHubId
        mDevice->addEmptyEventHubDevice(EVENTHUB_ID);
        // configure the empty device
        configureDevice(/*changes=*/{});

        return mDevice->constructAndAddMapper<T>(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(),
                                                 args...);
        auto& mapper =
                mDevice->constructAndAddMapper<T>(EVENTHUB_ID,
                                                  mFakePolicy->getReaderConfiguration(), args...);
        configureDevice(/*changes=*/{});
        return mapper;
    }

    void setDisplayInfoAndReconfigure(ui::LogicalDisplayId displayId, int32_t width, int32_t height,
+45 −0
Original line number Diff line number Diff line
@@ -4179,6 +4179,51 @@ TEST_F(KeyboardInputMapperTest, Process_GesureEventToSetFlagKeepTouchMode) {
    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_KEEP_TOUCH_MODE, args.flags);
}

/**
 * When there is more than one KeyboardInputMapper for an InputDevice, each mapper should produce
 * events that use the shared keyboard source across all mappers. This is to ensure that each
 * input device generates key events in a consistent manner, regardless of which mapper produces
 * the event.
 */
TEST_F(KeyboardInputMapperTest, UsesSharedKeyboardSource) {
    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);

    // Add a mapper with SOURCE_KEYBOARD
    KeyboardInputMapper& keyboardMapper =
            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);

    process(keyboardMapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
    ASSERT_NO_FATAL_FAILURE(
            mFakeListener->assertNotifyKeyWasCalled(WithSource(AINPUT_SOURCE_KEYBOARD)));
    process(keyboardMapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
    ASSERT_NO_FATAL_FAILURE(
            mFakeListener->assertNotifyKeyWasCalled(WithSource(AINPUT_SOURCE_KEYBOARD)));

    // Add a mapper with SOURCE_DPAD
    KeyboardInputMapper& dpadMapper =
            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_DPAD);
    for (auto* mapper : {&keyboardMapper, &dpadMapper}) {
        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD)));
        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD)));
    }

    // Add a mapper with SOURCE_GAMEPAD
    KeyboardInputMapper& gamepadMapper =
            constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_GAMEPAD);
    for (auto* mapper : {&keyboardMapper, &dpadMapper, &gamepadMapper}) {
        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD)));
        process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
                WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD)));
    }
}

// --- KeyboardInputMapperTest_ExternalAlphabeticDevice ---

class KeyboardInputMapperTest_ExternalAlphabeticDevice : public InputMapperTest {
Loading