Skip to content

Commit 76b1f62

Browse files
Vaibhav DevmurariAndroid (Google) Code Review
authored andcommitted
Merge "Fix: Sticky keys filter should ignore incomplete key events" into main
2 parents d0ddacc + b7269da commit 76b1f62

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)