← Commit history

1.0.11: 1.0.11: kicad_menu_items lists a window's menu bar (path, id, accelerator), so menu commands are chosen from what the build actually has; exact-label matching from 1.0.10

John Lauer ·3328e86bc9 ·1mo ago ·parent b8b8ed2
3 files changed +33−4
rust/Cargo.lock+3−3
@@ -244,7 +244,7 @@ dependencies = [  [[package]] name = "kicad-bridge"-version = "1.0.10"+version = "1.0.11" dependencies = [  "kicad-core",  "kicad-platform",@@ -255,7 +255,7 @@ dependencies = [  [[package]] name = "kicad-core"-version = "1.0.10"+version = "1.0.11" dependencies = [  "kicad-ipc-rs",  "kicad-platform",@@ -281,7 +281,7 @@ dependencies = [  [[package]] name = "kicad-platform"-version = "1.0.10"+version = "1.0.11" dependencies = [  "serde",  "serde_json",
rust/Cargo.toml+1−1
@@ -3,7 +3,7 @@ resolver = "2" members = ["crates/*"]  [workspace.package]-version = "1.0.10"+version = "1.0.11" edition = "2021" license = "MIT" publish = false
rust/crates/kicad-bridge/src/verbs_windows.rs+29
@@ -96,6 +96,16 @@ pub static VERBS: &[Verb] = &[         related: &["kicad_install_footprint", "kicad_close_footprint_editor", "kicad_screenshot_all"],         pitfalls: &["the footprint must be in an installed fp-lib-table library (install_footprint first)", "allowCursorClick (the SendInput launcher click) is not in the native build: the background menu and UIA rungs are the only ones"],     },+    Verb {+        name: "kicad_menu_items",+        summary: "List a KiCad window's menu bar items (path, id, accelerator), optionally filtered by a substring: what kicad_send_key {menu} and kicad_3d_view can fire.",+        mechanism: Mechanism::Window, risk: "read", timeout_sec: 30,+        input: "{\"hwnd\"?: 123, \"contains\"?: \"zoom\"}",+        example: "kicad_menu_items {\"hwnd\":123456,\"contains\":\"zoom\"}",+        hint: "Read-only, background. The last path element is the label a menu command matches (exact label first, then substring).",+        related: &["kicad_send_key", "kicad_3d_view", "kicad_window_info"],+        pitfalls: &["menus differ between KiCad versions and editors; list before you assume a label"],+    },     Verb {         name: "kicad_3d_view",         summary: "Drive the 3D Viewer without the mouse: zoom, rotate, view orientation, flip, or a scripted tour; menu commands posted to the viewer in the background.",@@ -292,6 +302,7 @@ pub fn dispatch(state: &mut State, command: &str, args: &Value) -> Option<Value>         "kicad_open_footprint_editor" => open_footprint_editor(state, args),         "kicad_open_3d_viewer" => open_3d_viewer(args),         "kicad_3d_view" => view_3d(args),+        "kicad_menu_items" => menu_items(args),         "kicad_open_editors" => open_editors(),         "kicad_close" => close_kicad(state, args),         "kicad_close_symbol_editor" => close_kind(WindowKind::SymbolEditor, "Symbol Editor"),@@ -1875,6 +1886,24 @@ fn open_3d_from(frame: u64, label: &str, pathways: &mut Vec<String>) -> Result<O   /// `kicad_3d_view`: the 3D Viewer's View-menu commands by name, repeated with pauses, or a tour.++/// `kicad_menu_items`: the native menu bar of a KiCad window, read-only.+pub(crate) fn menu_items(args: &Value) -> Value {+    let hwnd = match arg_any_u64(args, &["hwnd"]).or_else(|| foreground_kicad_hwnd()) {+        Some(h) => h,+        None => return fail("no_window", "No KiCad window found.", "kicad_window_info lists the windows; pass hwnd."),+    };+    let needle = arg_str(args, "contains").map(|s| s.to_lowercase()).unwrap_or_default();+    match native().menu_tree(hwnd) {+        Ok(items) => {+            let list: Vec<Value> = items.iter().filter(|it| needle.is_empty() || it.path.iter().any(|p| p.replace('&', "").to_lowercase().contains(&needle))).map(|it| json!({"path": it.path.iter().map(|p| p.replace('&', "")).collect::<Vec<_>>(), "id": it.id, "accel": it.accel})).collect();+            json!({"success": true, "hwnd": hwnd, "title": title_of(hwnd), "count": list.len(), "items": list})+        }+        Err(e) if is_not_impl(&e) => unsupported("native menu walk (menu_tree)"),+        Err(e) => fail("menu_walk_failed", &e, "Retry once the window is idle."),+    }+}+ pub(crate) fn view_3d(args: &Value) -> Value {     const ACTIONS: &[(&str, &str)] = &[         ("zoom_in", "Zoom In"), ("zoom_out", "Zoom Out"), ("fit", "Zoom to Fit"),