Fix toggleCapsLock failed for multiple EventHub devices
If a physical device includes multiple EventHub devices for different
funcions, it would also create multiple InputMappers to process raw
events. And it may contain multiple KeyboardInputMapper.
When 'toggleCapsLock' called, we have to check if device has the meta
state key such as CAPS_LOCK or NUMS_LOCK, then we should just update the
the first InputMapper that own the meta state key to prevent other
InputMapper update the global state multiple times.
Bug: 195405545
Test: atest inputflinger_tests
Test: shortcut key META-ALT
Change-Id: I9d09e13d1de416370b8570b6621db5c4bf1ba8eb
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 68d5e7c..0f0ad0a 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1209,6 +1209,15 @@
return false;
}
+bool EventHub::hasKeyCode(int32_t deviceId, int32_t keyCode) const {
+ std::scoped_lock _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device != nullptr) {
+ return device->hasKeycodeLocked(keyCode);
+ }
+ return false;
+}
+
bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 1e9ec54..36344b5 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -559,7 +559,13 @@
}
void InputDevice::updateMetaState(int32_t keyCode) {
- for_each_mapper([keyCode](InputMapper& mapper) { mapper.updateMetaState(keyCode); });
+ first_in_mappers<bool>([keyCode](InputMapper& mapper) {
+ if (sourcesMatchMask(mapper.getSources(), AINPUT_SOURCE_KEYBOARD) &&
+ mapper.updateMetaState(keyCode)) {
+ return std::make_optional(true);
+ }
+ return std::optional<bool>();
+ });
}
void InputDevice::bumpGeneration() {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 10c04f6..e71a9e9 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -555,6 +555,7 @@
}
if (device->isIgnored()) {
+ ALOGW("Ignoring toggleCapsLock for ignored deviceId %" PRId32 ".", deviceId);
return;
}
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 3c3f88e..7a00bac 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -312,6 +312,7 @@
uint8_t* outFlags) const = 0;
virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0;
+ virtual bool hasKeyCode(int32_t deviceId, int32_t keyCode) const = 0;
/* LED related functions expect Android LED constants, not scan codes or HID usages */
virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
@@ -489,6 +490,7 @@
std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override final;
bool hasScanCode(int32_t deviceId, int32_t scanCode) const override final;
+ bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override final;
bool hasLed(int32_t deviceId, int32_t led) const override final;
void setLedState(int32_t deviceId, int32_t led, bool on) override final;
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index f32472d..518aaa0 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -323,6 +323,7 @@
inline bool hasScanCode(int32_t scanCode) const {
return mEventHub->hasScanCode(mId, scanCode);
}
+ inline bool hasKeyCode(int32_t keyCode) const { return mEventHub->hasKeyCode(mId, keyCode); }
inline bool hasLed(int32_t led) const { return mEventHub->hasLed(mId, led); }
inline void setLedState(int32_t led, bool on) { return mEventHub->setLedState(mId, led, on); }
inline void getVirtualKeyDefinitions(std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index df1acd4..b9aef54 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -84,7 +84,9 @@
return 0;
}
-void InputMapper::updateMetaState(int32_t keyCode) {}
+bool InputMapper::updateMetaState(int32_t keyCode) {
+ return false;
+}
void InputMapper::updateExternalStylusState(const StylusState& state) {}
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 15cff1c..d9adc0f 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -83,7 +83,11 @@
virtual std::optional<int32_t> getLightPlayerId(int32_t lightId) { return std::nullopt; }
virtual int32_t getMetaState();
- virtual void updateMetaState(int32_t keyCode);
+ /**
+ * Process the meta key and update the global meta state when changed.
+ * Return true if the meta key could be handled by the InputMapper.
+ */
+ virtual bool updateMetaState(int32_t keyCode);
virtual void updateExternalStylusState(const StylusState& state);
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 104d087..52af38d 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -384,8 +384,13 @@
return mMetaState;
}
-void KeyboardInputMapper::updateMetaState(int32_t keyCode) {
+bool KeyboardInputMapper::updateMetaState(int32_t keyCode) {
+ if (!android::isMetaKey(keyCode) || !getDeviceContext().hasKeyCode(keyCode)) {
+ return false;
+ }
+
updateMetaStateIfNeeded(keyCode, false);
+ return true;
}
bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) {
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index ca41712..fc92320 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -40,7 +40,7 @@
const int32_t* keyCodes, uint8_t* outFlags) override;
virtual int32_t getMetaState() override;
- virtual void updateMetaState(int32_t keyCode) override;
+ virtual bool updateMetaState(int32_t keyCode) override;
virtual std::optional<int32_t> getAssociatedDisplayId() override;
virtual void updateLedState(bool reset);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 43f14bd..3280e24 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -870,6 +870,24 @@
return false;
}
+ bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override {
+ Device* device = getDevice(deviceId);
+ if (!device) {
+ return false;
+ }
+ for (size_t i = 0; i < device->keysByScanCode.size(); i++) {
+ if (keyCode == device->keysByScanCode.valueAt(i).keyCode) {
+ return true;
+ }
+ }
+ for (size_t j = 0; j < device->keysByUsageCode.size(); j++) {
+ if (keyCode == device->keysByUsageCode.valueAt(j).keyCode) {
+ return true;
+ }
+ }
+ return false;
+ }
+
bool hasLed(int32_t deviceId, int32_t led) const override {
Device* device = getDevice(deviceId);
return device && device->leds.indexOfKey(led) >= 0;
@@ -3729,6 +3747,25 @@
mapper2.getMetaState());
}
+TEST_F(KeyboardInputMapperTest, Process_toggleCapsLockState) {
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+ // Suppose we have two mappers. (DPAD + KEYBOARD)
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_DPAD,
+ AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ // Initialize metastate to AMETA_NUM_LOCK_ON.
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
+ mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+
+ mReader->toggleCapsLockState(DEVICE_ID);
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
+}
+
// --- KeyboardInputMapperTest_ExternalDevice ---
class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {