Input devices configure on per-display basis (1/2)
A InputDevice may be associated with a specific display.
This would provide a function to check if an input device can dispatch
input events to the specific display.
If the device has no associated, the events can dispatch to any display.
Bug: 116767202
Test: atest -a libinput_tests inputflinger_tests
Change-Id: I05a1c8db191ef1e6c4182f902a7a3b51e420740d
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 64070e3..f84aa34 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -805,6 +805,30 @@
return false;
}
+bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) {
+ AutoMutex _l(mLock);
+
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex < 0) {
+ ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId);
+ return false;
+ }
+
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplay();
+ // No associated display. By default, can dispatch to all displays.
+ if (!associatedDisplayId) {
+ return true;
+ }
+
+ if (*associatedDisplayId == ADISPLAY_ID_NONE) {
+ ALOGW("Device has associated, but no associated display id.");
+ return true;
+ }
+
+ return *associatedDisplayId == displayId;
+}
+
void InputReader::dump(std::string& dump) {
AutoMutex _l(mLock);
@@ -1275,6 +1299,18 @@
mContext->getListener()->notifyDeviceReset(&args);
}
+std::optional<int32_t> InputDevice::getAssociatedDisplay() {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay();
+ if (associatedDisplayId) {
+ return associatedDisplayId;
+ }
+ }
+
+ return std::nullopt;
+}
// --- CursorButtonAccumulator ---
@@ -2647,7 +2683,7 @@
}
// Update the PointerController if viewports changed.
- if (mParameters.hasAssociatedDisplay) {
+ if (mParameters.mode == Parameters::MODE_POINTER) {
getPolicy()->obtainPointerController(getDeviceId());
}
bumpGeneration();
@@ -2919,6 +2955,19 @@
}
}
+std::optional<int32_t> CursorInputMapper::getAssociatedDisplay() {
+ if (mParameters.hasAssociatedDisplay) {
+ if (mParameters.mode == Parameters::MODE_POINTER) {
+ return std::make_optional(mPointerController->getDisplayId());
+ } else {
+ // If the device is orientationAware and not a mouse,
+ // it expects to dispatch events to any display
+ return std::make_optional(ADISPLAY_ID_NONE);
+ }
+ }
+ return std::nullopt;
+}
+
// --- RotaryEncoderInputMapper ---
RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) :
@@ -6511,9 +6560,7 @@
ALOG_ASSERT(false);
}
}
- const int32_t displayId = mPointerController != nullptr ?
- mPointerController->getDisplayId() : mViewport.displayId;
-
+ const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
@@ -6830,6 +6877,16 @@
return true;
}
+std::optional<int32_t> TouchInputMapper::getAssociatedDisplay() {
+ if (mParameters.hasAssociatedDisplay) {
+ if (mDeviceMode == DEVICE_MODE_POINTER) {
+ return std::make_optional(mPointerController->getDisplayId());
+ } else {
+ return std::make_optional(mViewport.displayId);
+ }
+ }
+ return std::nullopt;
+}
// --- SingleTouchInputMapper ---
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index aaffce2..fed55ac 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -146,6 +146,7 @@
ssize_t repeat, int32_t token);
virtual void cancelVibrate(int32_t deviceId, int32_t token);
+ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId);
protected:
// These members are protected so they can be instrumented by test cases.
virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
@@ -320,6 +321,7 @@
return value;
}
+ std::optional<int32_t> getAssociatedDisplay();
private:
InputReaderContext* mContext;
int32_t mId;
@@ -778,7 +780,9 @@
virtual void updateExternalStylusState(const StylusState& state);
virtual void fadePointer();
-
+ virtual std::optional<int32_t> getAssociatedDisplay() {
+ return std::nullopt;
+ }
protected:
InputDevice* mDevice;
InputReaderContext* mContext;
@@ -932,6 +936,7 @@
virtual void fadePointer();
+ virtual std::optional<int32_t> getAssociatedDisplay();
private:
// Amount that trackball needs to move in order to generate a key event.
static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6;
@@ -1025,7 +1030,7 @@
virtual void cancelTouch(nsecs_t when);
virtual void timeoutExpired(nsecs_t when);
virtual void updateExternalStylusState(const StylusState& state);
-
+ virtual std::optional<int32_t> getAssociatedDisplay();
protected:
CursorButtonAccumulator mCursorButtonAccumulator;
CursorScrollAccumulator mCursorScrollAccumulator;
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index fe1c50b..c411ec0 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -100,6 +100,9 @@
virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
ssize_t repeat, int32_t token) = 0;
virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
+
+ /* Return true if the device can send input events to the specified display. */
+ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
};
/* Reads raw events from the event hub and processes them, endlessly. */
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 0b86555..84c5ad6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -841,6 +841,7 @@
bool mResetWasCalled;
bool mProcessWasCalled;
+ std::optional<DisplayViewport> mViewport;
public:
FakeInputMapper(InputDevice* device, uint32_t sources) :
InputMapper(device),
@@ -909,8 +910,14 @@
}
}
- virtual void configure(nsecs_t, const InputReaderConfiguration*, uint32_t) {
+ virtual void configure(nsecs_t, const InputReaderConfiguration* config, uint32_t changes) {
mConfigureWasCalled = true;
+
+ // Find the associated viewport if exist.
+ const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort();
+ if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+ mViewport = config->getDisplayViewportByPort(*displayPort);
+ }
}
virtual void reset(nsecs_t) {
@@ -957,6 +964,13 @@
virtual void fadePointer() {
}
+
+ virtual std::optional<int32_t> getAssociatedDisplay() {
+ if (mViewport) {
+ return std::make_optional(mViewport->displayId);
+ }
+ return std::nullopt;
+ }
};
@@ -984,9 +998,10 @@
}
InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const std::string& name,
- uint32_t classes) {
+ uint32_t classes, const std::string& location = "") {
InputDeviceIdentifier identifier;
identifier.name = name;
+ identifier.location = location;
int32_t generation = deviceId + 1;
return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier,
classes);
@@ -1286,7 +1301,7 @@
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0, "fake", deviceClass);
+ InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
@@ -1470,7 +1485,7 @@
TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0, "fake", deviceClass);
+ InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
@@ -1500,6 +1515,36 @@
prevSequenceNum = resetArgs.sequenceNum;
}
+TEST_F(InputReaderTest, Device_CanDispatchToDisplay) {
+ constexpr int32_t deviceId = 1;
+ constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ const char* DEVICE_LOCATION = "USB1";
+ InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass,
+ DEVICE_LOCATION);
+ FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_TOUCHSCREEN);
+ device->addMapper(mapper);
+ mReader->setNextDevice(device);
+ addDevice(deviceId, "fake", deviceClass, nullptr);
+
+ const uint8_t hdmi1 = 1;
+
+ // Associated touch screen with second display.
+ mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
+
+ // Add default and second display.
+ mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, "local:0", NO_PORT, ViewportType::VIEWPORT_INTERNAL);
+ mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, "local:1", hdmi1, ViewportType::VIEWPORT_EXTERNAL);
+ mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ mReader->loopOnce();
+
+ // Check device.
+ ASSERT_EQ(deviceId, device->getId());
+ ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, DISPLAY_ID));
+ ASSERT_TRUE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID));
+}
+
// --- InputDeviceTest ---