Fix led meta state can't be cleared by another keyboard
Currently, the led meta state of CapsLock, NumLock and ScrollLock would
be stored in to a global state. If we connected with multiple keyboards,
and some keyboard changed the led state, others should clear their local
led state frist then update it by the global state so we could clear the
state per device properly.
Bug: 194465459
Test: atest inputflinger_tests
Change-Id: I5965cf951a5ebcadc69541b9a036fb38fd428d30
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 8ba501c..bda7755 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -3999,6 +3999,78 @@
ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
}
+TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleInMultiDevices) {
+ // keyboard 1.
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+ 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);
+
+ KeyboardInputMapper& mapper1 =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+
+ // keyboard 2.
+ const std::string USB2 = "USB2";
+ const std::string DEVICE_NAME2 = "KEYBOARD2";
+ constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
+ constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
+ std::shared_ptr<InputDevice> device2 =
+ newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
+ ftl::Flags<InputDeviceClass>(0));
+ mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+ mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/);
+ mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+ KeyboardInputMapper& mapper2 =
+ device2->addMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
+ device2->reset(ARBITRARY_TIME);
+
+ // Initial metastate is AMETA_NUM_LOCK_ON, turn it off.
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper2.getMetaState());
+
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+ // Toggle caps lock on and off.
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper2.getMetaState());
+
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+ // Toggle scroll lock on and off.
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper2.getMetaState());
+
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+}
+
// --- KeyboardInputMapperTest_ExternalDevice ---
class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {