Shortcuts: an Escape that cancels a Tools or ruler move runs no Escape command

A command bound to plain Escape no longer runs when that Escape
cancels a floating Tools panel move or a ruler-origin drag, nor on the
key repeats while Escape stays held. The next separate Escape press
runs it as before. A test binds Select None to Escape and holds Escape
through both cancels.
This commit is contained in:
dotCooCoo
2026-11-04 20:51:00 +07:00
committed by bflatastic
parent 49616e0a16
commit db6a0d786e
2 changed files with 26 additions and 1 deletions
+3 -1
View File
@@ -350,10 +350,12 @@ pub fn handle(app: &mut VectorcraftApp, ctx: &egui::Context) {
let row_key = |chord: &craft_keymap::Chord| {
rows_keys && chord.is_plain() && !chord.mods.shift && matches!(chord.key, craft_keymap::Key::Delete | craft_keymap::Key::Backspace)
};
// An Escape that ended a ruler-origin drag or floating Tools move runs no command bound to it.
let gesture_escape = |chord: &craft_keymap::Chord| escape_ended_gesture && chord.is_plain() && chord.key == craft_keymap::Key::Escape;
let hits = dispatch(app, ctx, |hit| {
let chord = &hit.trigger.chord;
let shifted_punctuation = chord.mods.shift && chord.key.name().chars().all(|c| !c.is_alphanumeric());
!(chord.is_plain() && types_text(chord.key) && !shifted_punctuation || row_key(chord))
!(chord.is_plain() && types_text(chord.key) && !shifted_punctuation || row_key(chord) || gesture_escape(chord))
});
let ran = !hits.is_empty();
for c in hits {
+23
View File
@@ -465,6 +465,29 @@ fn held_escape_that_cancels_ruler_origin_drag_keeps_the_tool() {
}
}
#[test]
fn held_escape_that_cancels_a_move_skips_a_command_bound_to_escape() {
for ruler in [false, true] {
let ctx = egui::Context::default();
let mut app = in_screen_mode(&ctx, 0);
app.run("shortcuts.set", json!({"id": "select.none", "shortcut": "Escape", "force": true})).unwrap();
let selected = app.session.active().unwrap().selection.objects.clone();
assert!(!selected.is_empty());
let to = if ruler { begin_ruler_origin_drag(&mut app, &ctx) } else { begin_tools_move(&mut app, &ctx).1 };
frame(&mut app, &ctx, escape_event(true, false));
assert_eq!(app.session.active().unwrap().selection.objects, selected, "the cancelling Escape runs no command (ruler: {ruler})");
for _ in 0..3 {
frame(&mut app, &ctx, escape_event(true, true));
}
release_drag(&mut app, &ctx, to);
frame(&mut app, &ctx, escape_event(true, true));
assert_eq!(app.session.active().unwrap().selection.objects, selected, "held Escape runs no command (ruler: {ruler})");
frame(&mut app, &ctx, escape_event(false, false));
frame(&mut app, &ctx, escape());
assert!(app.session.active().unwrap().selection.objects.is_empty(), "the next Escape runs the command (ruler: {ruler})");
}
}
#[test]
fn a_popup_takes_escape_before_full_screen_exits() {
let ctx = egui::Context::default();