From ed8aabd1dc5a88652a076631c2d46886ca60c031 Mon Sep 17 00:00:00 2001 From: aiongg <67543387+aiongg@users.noreply.github.com> Date: Mon, 26 Oct 2026 00:18:17 -0400 Subject: [PATCH] Shortcut edits wait for the Keyboard Shortcuts dialog; the menu bar owns a user's Paste in Place chord (#1854) --- crates/ui-egui/src/menus.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index af72d080e..a32d26e30 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -1806,6 +1806,11 @@ fn run_ui_inner(app: &mut DesignApp, id: &str, p: &Value) -> Option>()}), ) } + // The open Keyboard Shortcuts dialog edits the keys itself, and its Cancel puts back the + // ones it started with, which would undo a change made here. + "window.setShortcut" | "window.resetShortcuts" | "window.importShortcuts" if app.shortcut_dialog.is_some() => { + Err("close the Keyboard Shortcuts dialog first".into()) + } "window.setShortcut" => { let Some(id) = p.get("id").and_then(Value::as_str) else { return Some(Err("missing id".into())) }; let mut cmd = crate::keys::command_ref(id, p.get("params").unwrap_or(&Value::Null)); @@ -3228,6 +3233,15 @@ pub fn paste_chord_command(app: &DesignApp, modifiers: egui::Modifiers) -> Optio let platform = app.keymap.platform(); let held = craft_keymap::Mods::from_egui(&modifiers, platform); let pressed = craft_keymap::Chord::new(held, craft_keymap::Key::V); + // A shortcut the user set is the menu bar's key equivalent once the bar carries it. + let on_bar = app + .native_shortcuts + .get(id) + .and_then(|sc| craft_keymap::Binding::parse(sc).ok()) + .is_some_and(|b| !b.trigger.double && b.trigger.chord.effective(platform) == pressed); + if app.native_menu && on_bar { + return None; + } let bound = app.keymap.bindings(&craft_keymap::CommandRef::new(id)).iter().any(|b| !b.trigger.double && b.trigger.chord.effective(platform) == pressed); bound.then_some(id) @@ -3806,6 +3820,28 @@ mod tests { app.keymap.catalog().iter().filter_map(|b| crate::keys::shortcut(&app.keymap, &b.command).map(|s| (b.command.key(), s))).collect() } + #[test] + #[cfg(not(target_arch = "wasm32"))] + fn shortcut_edits_wait_for_the_dialog_and_the_menu_bar_owns_its_paste_chord() { + let mut app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default()); + crate::shortcuts_dialog::open(&mut app, None); + for (id, p) in [ + ("window.setShortcut", json!({"id": "app.palette", "shortcut": "F2"})), + ("window.resetShortcuts", json!({})), + ("window.importShortcuts", json!({"text": ""})), + ] { + assert!(run_ui(&mut app, id, &p).unwrap().is_err(), "{id} while the dialog is open"); + } + crate::shortcuts_dialog::close(&mut app, false).unwrap(); + // A chord of the user's: the default one is the bar's from the start. + run_ui(&mut app, "window.setShortcut", &json!({"id": "edit.pasteInPlace", "shortcut": "Cmd+Alt+V", "steal": true})).unwrap().unwrap(); + let held = egui::Modifiers::COMMAND | egui::Modifiers::ALT; + app.native_menu = true; + assert_eq!(paste_chord_command(&app, held), Some("edit.pasteInPlace"), "before the bar carries it"); + app.native_shortcuts.insert("edit.pasteInPlace".into(), "Cmd+Alt+V".into()); + assert_eq!(paste_chord_command(&app, held), None, "the bar's key equivalent runs it, once"); + } + #[test] fn custom_shortcuts_override_defaults() { let mut app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());