CapturedTouchpadEventConverter: report relative axes
In the old touchpad stack, when a touchpad was captured we'd report
AXIS_RELATIVE_(X|Y) values for each finger, as offsets from the location
it had in the previous frame. When I implemented captured mode in the
new stack I didn't realize this, so the new stack introduced in Android
U doesn't report them. This causes problems for games that capture the
mouse pointer and use the relative axes for camera movement.
This is attempt 2; the original CL [0] had a unit test that was flaky
due to it accidentally making assertions about uninitialized memory. The
changes since that CL are to TwoFingers_motionReportedCorrectly in
CapturedTouchpadEventConverter_test.cpp (to change the last
WithPointerRelativeMotion call to WithRelativeMotion) and
TestEventMatchers.h (to use a class for WithPointerRelativeMotion and to
check for out-of-range pointer indexes).
[0]: Change ID I8a1caa4c9315dd41bc712fd9467146bb608cf6f3
Bug: 330522990
Bug: 365166534
Test: check the axis values using a test app
Test: $ atest inputflinger_tests:CapturedTouchpadEventConverterTest
Flag: com.android.input.flags.include_relative_axis_values_for_captured_touchpads
Change-Id: If6828f95e3aa359af479a708f95fbb5e31e5bc9a
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
index c8e7790..dd46bbc 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
@@ -20,14 +20,19 @@
#include <sstream>
#include <android-base/stringprintf.h>
+#include <com_android_input_flags.h>
#include <input/PrintTools.h>
#include <linux/input-event-codes.h>
#include <log/log_main.h>
+namespace input_flags = com::android::input::flags;
+
namespace android {
namespace {
+static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
+
int32_t actionWithIndex(int32_t action, int32_t index) {
return action | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
}
@@ -43,6 +48,12 @@
return i;
}
+void addRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
+ RawAbsoluteAxisInfo& evdevAxis) {
+ deviceInfo.addMotionRange(androidAxis, SOURCE, evdevAxis.minValue, evdevAxis.maxValue,
+ evdevAxis.flat, evdevAxis.fuzz, evdevAxis.resolution);
+}
+
} // namespace
CapturedTouchpadEventConverter::CapturedTouchpadEventConverter(
@@ -108,8 +119,15 @@
}
void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const {
- tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
- tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
+ if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
+ tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X,
+ AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X);
+ tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y,
+ AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y);
+ } else {
+ tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
+ tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
+ }
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR);
@@ -135,8 +153,23 @@
int32_t evdevAxis) const {
std::optional<RawAbsoluteAxisInfo> info = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
if (info) {
- deviceInfo.addMotionRange(androidAxis, SOURCE, info->minValue, info->maxValue, info->flat,
- info->fuzz, info->resolution);
+ addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *info);
+ }
+}
+
+void CapturedTouchpadEventConverter::tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo,
+ int32_t androidAxis,
+ int32_t androidRelativeAxis,
+ int32_t evdevAxis) const {
+ std::optional<RawAbsoluteAxisInfo> axisInfo = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
+ if (axisInfo) {
+ addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *axisInfo);
+
+ // The largest movement we could possibly report on a relative axis is from the minimum to
+ // the maximum (or vice versa) of the absolute axis.
+ float range = axisInfo->maxValue - axisInfo->minValue;
+ deviceInfo.addMotionRange(androidRelativeAxis, SOURCE, -range, range, axisInfo->flat,
+ axisInfo->fuzz, axisInfo->resolution);
}
}
@@ -163,7 +196,7 @@
std::list<NotifyArgs> out;
std::vector<PointerCoords> coords;
std::vector<PointerProperties> properties;
- std::map<size_t, size_t> coordsIndexForSlotNumber;
+ std::map<size_t /*slotNumber*/, size_t /*coordsIndex*/> coordsIndexForSlotNumber;
// For all the touches that were already down, send a MOVE event with their updated coordinates.
// A convention of the MotionEvent API is that pointer coordinates in UP events match the
@@ -175,11 +208,19 @@
// to stay perfectly still between frames, and if it does the worst that can happen is
// an extra MOVE event, so it's not worth the overhead of checking for changes.
coordsIndexForSlotNumber[slotNumber] = coords.size();
- coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
+ coords.push_back(makePointerCoordsForSlot(slotNumber));
properties.push_back({.id = pointerId, .toolType = ToolType::FINGER});
}
out.push_back(
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties));
+ if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
+ // For any further events we send from this sync, the pointers won't have moved relative
+ // to the positions we just reported in this MOVE event, so zero out the relative axes.
+ for (PointerCoords& pointer : coords) {
+ pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
+ pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
+ }
+ }
}
std::vector<size_t> upSlots, downSlots;
@@ -234,6 +275,9 @@
/*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0));
freePointerIdForSlot(slotNumber);
+ if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
+ mPreviousCoordsForSlotNumber.erase(slotNumber);
+ }
coords.erase(coords.begin() + indexToRemove);
properties.erase(properties.begin() + indexToRemove);
// Now that we've removed some coords and properties, we might have to update the slot
@@ -254,7 +298,7 @@
: actionWithIndex(AMOTION_EVENT_ACTION_POINTER_DOWN, coordsIndex);
coordsIndexForSlotNumber[slotNumber] = coordsIndex;
- coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
+ coords.push_back(makePointerCoordsForSlot(slotNumber));
properties.push_back(
{.id = allocatePointerIdToSlot(slotNumber), .toolType = ToolType::FINGER});
@@ -286,12 +330,22 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION, mDownTime, /*videoFrames=*/{});
}
-PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(
- const MultiTouchMotionAccumulator::Slot& slot) const {
+PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(size_t slotNumber) {
+ const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(slotNumber);
PointerCoords coords;
coords.clear();
coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX());
coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY());
+ if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
+ if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber);
+ it != mPreviousCoordsForSlotNumber.end()) {
+ auto [oldX, oldY] = it->second;
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY);
+ }
+ mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY());
+ }
+
coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor());
coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor());
coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, slot.getToolMajor());
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
index 9b6df7a..d6c0708 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
@@ -21,6 +21,7 @@
#include <map>
#include <set>
#include <string>
+#include <utility>
#include <vector>
#include <android/input.h>
@@ -49,12 +50,14 @@
private:
void tryAddRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
int32_t evdevAxis) const;
+ void tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, int32_t androidAxis,
+ int32_t androidRelativeAxis, int32_t evdevAxis) const;
[[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
[[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
const std::vector<PointerCoords>& coords,
const std::vector<PointerProperties>& properties,
int32_t actionButton = 0, int32_t flags = 0);
- PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const;
+ PointerCoords makePointerCoordsForSlot(size_t slotNumber);
int32_t allocatePointerIdToSlot(size_t slotNumber);
void freePointerIdForSlot(size_t slotNumber);
@@ -76,8 +79,7 @@
std::bitset<MAX_POINTER_ID + 1> mPointerIdsInUse;
std::map<size_t, int32_t> mPointerIdForSlotNumber;
-
- static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
+ std::map<size_t, std::pair<float, float>> mPreviousCoordsForSlotNumber;
};
} // namespace android