Skip processing repeat EV_KEY events for keyboards
Key repeat is handled by Android internally so we should not use the
kernel level key repeat.
Android attempts to disable key repeat by sending a EVIOCSREP ioctl
call, however this does not work on all keyboards (namely any that use
the atkbd driver) as [0, 0] are considered invalid configuration values
for the driver.
This functions in a similar way to the original intention in that it
will discard all kernel level repeat EV_KEY events to allow the system
level key-repeat to function correctly.
Bug: b/374209729
Test: Manually with offending device
Flag: EXEMPT bugfix
Change-Id: I5219edcddfc2fdb420e5c3ef7ecc9b5c557e5c6a
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 567a3e2..852ed08 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -241,11 +241,16 @@
mHidUsageAccumulator.process(rawEvent);
switch (rawEvent.type) {
case EV_KEY: {
- int32_t scanCode = rawEvent.code;
+ // Skip processing repeated keys (value == 2) since auto repeat is handled by Android
+ // internally.
+ if (rawEvent.value == 2) {
+ break;
+ }
+ const int32_t scanCode = rawEvent.code;
if (isSupportedScanCode(scanCode)) {
- out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0,
- scanCode, mHidUsageAccumulator.consumeCurrentHidUsage());
+ out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0, scanCode,
+ mHidUsageAccumulator.consumeCurrentHidUsage());
}
break;
}
diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
index 88c25d3..bcc6062 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -20,16 +20,19 @@
#include "InputMapperTest.h"
#include "InterfaceMocks.h"
+#include "TestEventMatchers.h"
#define TAG "KeyboardInputMapper_test"
namespace android {
using testing::_;
+using testing::AllOf;
using testing::Args;
using testing::DoAll;
using testing::Return;
using testing::SetArgPointee;
+using testing::VariantWith;
/**
* Unit tests for KeyboardInputMapper.
@@ -86,4 +89,24 @@
}
}
+TEST_F(KeyboardInputMapperUnitTest, RepeatEventsDiscarded) {
+ std::list<NotifyArgs> args;
+ args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 1);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 2);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 0);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN),
+ WithKeyCode(AKEYCODE_0),
+ WithScanCode(KEY_0))),
+ VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
+ WithKeyCode(AKEYCODE_0),
+ WithScanCode(KEY_0)))));
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index 6fa3365..f58d8fd 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -540,6 +540,34 @@
return WithKeyCodeMatcher(keyCode);
}
+/// Scan code
+class WithScanCodeMatcher {
+public:
+ using is_gtest_matcher = void;
+ explicit WithScanCodeMatcher(int32_t scanCode) : mScanCode(scanCode) {}
+
+ bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const {
+ return mScanCode == args.scanCode;
+ }
+
+ bool MatchAndExplain(const KeyEvent& event, std::ostream*) const {
+ return mScanCode == event.getKeyCode();
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "with scan code " << KeyEvent::getLabel(mScanCode);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const { *os << "wrong scan code"; }
+
+private:
+ const int32_t mScanCode;
+};
+
+inline WithScanCodeMatcher WithScanCode(int32_t scanCode) {
+ return WithScanCodeMatcher(scanCode);
+}
+
/// EventId
class WithEventIdMatcher {
public: