lesavka: preserve quick modifier chords
This commit is contained in:
parent
20cb355aa0
commit
a3e84c5c15
@ -473,15 +473,32 @@ impl InputAggregator {
|
||||
|
||||
fn process_keyboard_updates(&mut self) {
|
||||
for index in 0..self.keyboards.len() {
|
||||
let mut keyboard_shadow: HashSet<KeyCode> = self.keyboards[index]
|
||||
.pressed_keys_snapshot()
|
||||
.into_iter()
|
||||
.collect();
|
||||
let other_pressed: HashSet<KeyCode> = self
|
||||
.keyboards
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(other_index, _)| *other_index != index)
|
||||
.flat_map(|(_, keyboard)| keyboard.pressed_keys_snapshot())
|
||||
.collect();
|
||||
let updates = {
|
||||
let keyboard = &mut self.keyboards[index];
|
||||
keyboard.drain_key_updates()
|
||||
};
|
||||
for update in updates {
|
||||
update_shadow_pressed_keys(&mut keyboard_shadow, update.code, update.value);
|
||||
if update.swallowed || !self.keyboard_capture_enabled() {
|
||||
continue;
|
||||
}
|
||||
let report = self.build_combined_keyboard_report();
|
||||
let report = build_keyboard_report(
|
||||
other_pressed
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(keyboard_shadow.iter().copied()),
|
||||
);
|
||||
if report == self.last_keyboard_report {
|
||||
continue;
|
||||
}
|
||||
@ -497,16 +514,6 @@ impl InputAggregator {
|
||||
.any(KeyboardAggregator::sending_enabled)
|
||||
}
|
||||
|
||||
fn build_combined_keyboard_report(&self) -> [u8; 8] {
|
||||
let mut pressed = HashSet::new();
|
||||
for keyboard in &self.keyboards {
|
||||
for key in keyboard.pressed_keys_snapshot() {
|
||||
pressed.insert(key);
|
||||
}
|
||||
}
|
||||
build_keyboard_report(pressed.into_iter())
|
||||
}
|
||||
|
||||
fn quick_toggle_active(&mut self) -> bool {
|
||||
self.quick_toggle_key.is_some_and(|key| {
|
||||
self.keyboards
|
||||
@ -696,6 +703,14 @@ fn should_ignore_keyboard_device(dev: &Device) -> bool {
|
||||
|| name.contains("codex-persistent-kbd")
|
||||
}
|
||||
|
||||
fn update_shadow_pressed_keys(pressed_keys: &mut HashSet<KeyCode>, code: KeyCode, value: i32) {
|
||||
if value == 0 {
|
||||
pressed_keys.remove(&code);
|
||||
} else if value > 0 {
|
||||
pressed_keys.insert(code);
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the quick-toggle key from env, defaulting to Pause/Break.
|
||||
fn quick_toggle_key_from_env() -> Option<KeyCode> {
|
||||
match std::env::var("LESAVKA_INPUT_TOGGLE_KEY") {
|
||||
|
||||
@ -153,6 +153,48 @@ mod inputs_contract_extra {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn process_keyboard_updates_keeps_quick_shift_chord_when_full_tap_lands_in_one_poll_cycle() {
|
||||
let Some((mut vdev, dev)) = build_keyboard_pair_with_keys(
|
||||
"lesavka-input-shift-batch",
|
||||
&[evdev::KeyCode::KEY_LEFTSHIFT, evdev::KeyCode::KEY_A],
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let (kbd_tx, mut rx) = tokio::sync::broadcast::channel(32);
|
||||
let (mou_tx, _) = tokio::sync::broadcast::channel(16);
|
||||
let keyboard = KeyboardAggregator::new(dev, false, kbd_tx.clone(), None);
|
||||
|
||||
let mut agg = InputAggregator::new(false, kbd_tx, mou_tx, None);
|
||||
agg.keyboards.push(keyboard);
|
||||
|
||||
vdev.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, evdev::KeyCode::KEY_LEFTSHIFT.0, 1),
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, evdev::KeyCode::KEY_A.0, 1),
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, evdev::KeyCode::KEY_A.0, 0),
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, evdev::KeyCode::KEY_LEFTSHIFT.0, 0),
|
||||
])
|
||||
.expect("emit quick shifted tap");
|
||||
thread::sleep(std::time::Duration::from_millis(25));
|
||||
|
||||
temp_env::with_var("LESAVKA_LIVE_MODIFIER_DELAY_MS", Some("0"), || {
|
||||
agg.process_keyboard_updates();
|
||||
});
|
||||
|
||||
let reports: Vec<Vec<u8>> =
|
||||
std::iter::from_fn(|| rx.try_recv().ok().map(|pkt| pkt.data)).collect();
|
||||
assert!(
|
||||
reports.contains(&vec![0x02, 0, 0x04, 0, 0, 0, 0, 0]),
|
||||
"expected shifted A report from one-batch chord, got {reports:?}"
|
||||
);
|
||||
assert!(
|
||||
reports.contains(&vec![0; 8]),
|
||||
"expected final empty report after one-batch chord, got {reports:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn process_keyboard_updates_keeps_overlapping_plain_keys_from_sticking_across_keyboards() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user