diff options
| -rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 55 | ||||
| -rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.h | 4 | ||||
| -rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 27 |
3 files changed, 50 insertions, 36 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7f68d1b8b1..3fd1c8aa27 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -506,12 +506,6 @@ bool isConnectionResponsive(const Connection& connection) { return true; } -vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { - const vec2 transformedXy = transform.transform(x, y); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - // Returns true if the event type passed as argument represents a user activity. bool isUserActivityEvent(const EventEntry& eventEntry) { switch (eventEntry.type) { @@ -4214,10 +4208,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, - motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*injectedEntry); + pointerProperties, samplePointerCoords, 0, 0); + transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { sampleEventTimes += 1; @@ -4236,9 +4228,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*nextInjectedEntry); + samplePointerCoords, 0, 0); + transformMotionEntryForInjectionLocked(*nextInjectedEntry, + motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); } break; @@ -4402,35 +4394,28 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, } } -void InputDispatcher::transformMotionEntryForInjectionLocked(MotionEntry& entry) const { - const bool isRelativeMouseEvent = isFromSource(entry.source, AINPUT_SOURCE_MOUSE_RELATIVE); - if (!isRelativeMouseEvent && !isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) { - return; - } - +void InputDispatcher::transformMotionEntryForInjectionLocked( + MotionEntry& entry, const ui::Transform& injectedTransform) const { // Input injection works in the logical display coordinate space, but the input pipeline works // display space, so we need to transform the injected events accordingly. const auto it = mDisplayInfos.find(entry.displayId); if (it == mDisplayInfos.end()) return; - const auto& transformToDisplay = it->second.transform.inverse(); + const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform; for (uint32_t i = 0; i < entry.pointerCount; i++) { PointerCoords& pc = entry.pointerCoords[i]; - const auto xy = isRelativeMouseEvent - ? transformWithoutTranslation(transformToDisplay, pc.getX(), pc.getY()) - : transformToDisplay.transform(pc.getXYValue()); - pc.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); - - // Axes with relative values never represent points on a screen, so they should never have - // translation applied. If a device does not report relative values, these values are always - // 0, and will remain unaffected by the following operation. - const auto rel = - transformWithoutTranslation(transformToDisplay, - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, rel.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, rel.y); + // Make a copy of the injected coords. We cannot change them in place because some of them + // are interdependent (for example, X coordinate might depend on the Y coordinate). + PointerCoords injectedCoords = entry.pointerCoords[i]; + + BitSet64 bits(injectedCoords.bits); + while (!bits.isEmpty()) { + const auto axis = static_cast<int32_t>(bits.clearFirstMarkedBit()); + const float value = + MotionEvent::calculateTransformedAxisValue(axis, entry.source, + transformToDisplay, injectedCoords); + pc.setAxisValue(axis, value); + } } } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 8a551cfca1..6f05670943 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -280,7 +280,9 @@ private: bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResult(EventEntry& entry, android::os::InputEventInjectionResult injectionResult); - void transformMotionEntryForInjectionLocked(MotionEntry&) const REQUIRES(mLock); + void transformMotionEntryForInjectionLocked(MotionEntry&, + const ui::Transform& injectedTransform) const + REQUIRES(mLock); std::condition_variable mInjectionSyncFinished; void incrementPendingForegroundDispatches(EventEntry& entry); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 515a01e137..eaea4e26c4 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2079,6 +2079,33 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) { secondWindow->assertNoEvents(); } +// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed +// event should be treated as being in the logical display space. +TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; + ui::Transform injectedEventTransform; + injectedEventTransform.set(matrix); + const vec2 expectedPoint{75, 55}; // The injected point in the logical display space. + const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint); + + MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(untransformedPoint.x) + .y(untransformedPoint.y)) + .build(); + event.transform(matrix); + + injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT); + + firstWindow->consumeMotionDown(); + secondWindow->assertNoEvents(); +} + TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); |