Skip to content

Commit b7269da

Browse files
author
Vaibhav Devmurari
committed
Fix: Sticky keys filter should ignore incomplete key events
When sticky keys filter is enabled while some keys are pressed down on the keyboard, the key up on those keys should not affect the sticky state. Bug: 381239751 Test: atest --host libinputflinger_rs_test Flag: EXEMPT bugfix Change-Id: I3142883f33e9783b7ca09c3291f75b4008f6a13f
1 parent 9a3ad9b commit b7269da

1 file changed

Lines changed: 68 additions & 1 deletion

File tree

services/inputflinger/rust/sticky_keys_filter.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub struct StickyKeysFilter {
4747
next: Box<dyn Filter + Send + Sync>,
4848
listener: ModifierStateListener,
4949
data: Data,
50+
down_key_map: HashMap<i32, HashSet<i32>>,
5051
}
5152

5253
#[derive(Default)]
@@ -69,15 +70,34 @@ impl StickyKeysFilter {
6970
next: Box<dyn Filter + Send + Sync>,
7071
listener: ModifierStateListener,
7172
) -> StickyKeysFilter {
72-
Self { next, listener, data: Default::default() }
73+
Self { next, listener, data: Default::default(), down_key_map: HashMap::new() }
7374
}
7475
}
7576

7677
impl Filter for StickyKeysFilter {
7778
fn notify_key(&mut self, event: &KeyEvent) {
79+
let down = event.action == KeyEventAction::DOWN;
7880
let up = event.action == KeyEventAction::UP;
7981
let mut modifier_state = self.data.modifier_state;
8082
let mut locked_modifier_state = self.data.locked_modifier_state;
83+
if down {
84+
let down_keys = self.down_key_map.entry(event.deviceId).or_default();
85+
down_keys.insert(event.keyCode);
86+
} else {
87+
if !self.down_key_map.contains_key(&event.deviceId) {
88+
self.next.notify_key(event);
89+
return;
90+
}
91+
let down_keys = self.down_key_map.get_mut(&event.deviceId).unwrap();
92+
if !down_keys.contains(&event.keyCode) {
93+
self.next.notify_key(event);
94+
return;
95+
}
96+
down_keys.remove(&event.keyCode);
97+
if down_keys.is_empty() {
98+
self.down_key_map.remove(&event.deviceId);
99+
}
100+
}
81101
if !is_ephemeral_modifier_key(event.keyCode) {
82102
// If non-ephemeral modifier key (i.e. non-modifier keys + toggle modifier keys like
83103
// CAPS_LOCK, NUM_LOCK etc.), don't block key and pass in the sticky modifier state with
@@ -130,6 +150,7 @@ impl Filter for StickyKeysFilter {
130150
self.data.locked_modifier_state = ModifierState::None;
131151
self.listener.modifier_state_changed(ModifierState::None, ModifierState::None);
132152
}
153+
self.down_key_map.retain(|key, _| device_infos.iter().any(|x| *key == x.deviceId));
133154
self.next.notify_devices_changed(device_infos);
134155
}
135156

@@ -166,6 +187,7 @@ impl Filter for StickyKeysFilter {
166187
result += &format!("\tmodifier_state = {:?}\n", self.data.modifier_state);
167188
result += &format!("\tlocked_modifier_state = {:?}\n", self.data.locked_modifier_state);
168189
result += &format!("\tcontributing_devices = {:?}\n", self.data.contributing_devices);
190+
result += &format!("\tdown_key_map = {:?}\n", self.down_key_map);
169191
self.next.dump(dump_str + &result)
170192
}
171193
}
@@ -321,6 +343,31 @@ mod tests {
321343
}
322344
}
323345

346+
#[test]
347+
fn test_notify_key_passes_ephemeral_modifier_keys_if_only_key_up_occurs() {
348+
let test_filter = TestFilter::new();
349+
let test_callbacks = TestCallbacks::new();
350+
let mut sticky_keys_filter = setup_filter(
351+
Box::new(test_filter.clone()),
352+
Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks.clone())))),
353+
);
354+
let key_codes = &[
355+
KEYCODE_ALT_LEFT,
356+
KEYCODE_ALT_RIGHT,
357+
KEYCODE_CTRL_LEFT,
358+
KEYCODE_CTRL_RIGHT,
359+
KEYCODE_SHIFT_LEFT,
360+
KEYCODE_SHIFT_RIGHT,
361+
KEYCODE_META_LEFT,
362+
KEYCODE_META_RIGHT,
363+
];
364+
for key_code in key_codes.iter() {
365+
let event = KeyEvent { keyCode: *key_code, ..BASE_KEY_UP };
366+
sticky_keys_filter.notify_key(&event);
367+
assert_eq!(test_filter.last_event().unwrap(), event);
368+
}
369+
}
370+
324371
#[test]
325372
fn test_notify_key_passes_non_ephemeral_modifier_keys() {
326373
let test_filter = TestFilter::new();
@@ -436,6 +483,26 @@ mod tests {
436483
assert_eq!(test_callbacks.get_last_locked_modifier_state(), ModifierState::None);
437484
}
438485

486+
#[test]
487+
fn test_modifier_state_unchanged_on_non_modifier_key_up_without_down() {
488+
let test_filter = TestFilter::new();
489+
let test_callbacks = TestCallbacks::new();
490+
let mut sticky_keys_filter = setup_filter(
491+
Box::new(test_filter.clone()),
492+
Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks.clone())))),
493+
);
494+
sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_DOWN });
495+
sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_UP });
496+
497+
sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEY_A, ..BASE_KEY_UP });
498+
499+
assert_eq!(
500+
test_callbacks.get_last_modifier_state(),
501+
ModifierState::CtrlLeftOn | ModifierState::CtrlOn
502+
);
503+
assert_eq!(test_callbacks.get_last_locked_modifier_state(), ModifierState::None);
504+
}
505+
439506
#[test]
440507
fn test_locked_modifier_state_not_cleared_on_non_modifier_key_press() {
441508
let test_filter = TestFilter::new();

0 commit comments

Comments
 (0)