Shortcuts: a text with no key press of its own leaves the next keystroke's press to that keystroke's text

A text-only event right before a desktop keystroke in the same frame ([text, key, text]) took the key press as the press after it, which left the keystroke's own text with no key. A text now takes the press after it only when every later text in the same run of alternating texts and presses has a press after it too, as in the web build's [text, key] order; otherwise the press goes to the text after it.
This commit is contained in:
dotCooCoo
2026-10-31 18:44:50 +07:00
committed by bflatastic
parent 8579aa07e3
commit 0127739597
2 changed files with 22 additions and 2 deletions
+17 -2
View File
@@ -848,9 +848,24 @@ fn latin(text: &str, physical: Option<Key>) -> String {
/// For each event, the index of the key press that typed it when it is text: the press right
/// before it (egui-winit) unless an earlier text took that press, or else the press right after it
/// (eframe's web build with no text field focused). Each press types at most one text.
/// (eframe's web build with no text field focused). Each press types at most one text. A text
/// takes the press after it only when every later text in the same run of alternating texts and
/// presses has a press after it too; otherwise the text after that press takes it as the press
/// before it, and this text has none.
fn typing_presses(events: &[egui::Event]) -> Vec<Option<usize>> {
let is_press = |k: usize| matches!(events.get(k), Some(egui::Event::Key { pressed: true, .. }));
let is_text = |k: usize| matches!(events.get(k), Some(egui::Event::Text(_)));
// Whether the run of alternating texts and presses that starts with the text at `j` ends
// with a press.
let ends_with_press = |mut j: usize| loop {
if !is_press(j + 1) {
break false;
}
if !is_text(j + 2) {
break true;
}
j += 2;
};
let mut taken = None;
events
.iter()
@@ -860,7 +875,7 @@ fn typing_presses(events: &[egui::Event]) -> Vec<Option<usize>> {
return None;
}
let before = j.checked_sub(1).filter(|&k| is_press(k) && taken != Some(k));
let by = before.or_else(|| Some(j + 1).filter(|&k| is_press(k)));
let by = before.or_else(|| ends_with_press(j).then_some(j + 1));
taken = by.or(taken);
by
})
+5
View File
@@ -1486,6 +1486,11 @@ fn one_key_shortcuts_use_the_key_of_the_same_keystroke_in_either_order() {
app.select_tool("pen");
frame(&mut app, vec![press(Key::P), text("з"), press(Key::V), text("м")]);
assert_eq!(app.session.tool_id(), "selection", "key before its text");
// A text with no key press of its own right before a desktop keystroke leaves that press to
// the keystroke's text.
assert_eq!(typing_presses(&[text("p"), press(Key::V), text("м")]), [None, None, Some(1)]);
frame(&mut app, vec![text("p"), press(Key::V), text("м")]);
assert_eq!(app.session.tool_id(), "selection", "the text after the key uses it");
let names = |events: &[egui::Event]| -> Vec<String> {
shortcut_presses(events, Modifiers::NONE).into_iter().filter_map(|(n, _)| n.into_iter().next()).collect()
};