app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Reference implementation of the KiCad bridge: multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.
← Commit history
0.9.317: Tour remote: dashboard presses recorded, acked with a caption, and honoured at the next gesture like panel presses
3 files changed
+27−11
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.316+0.9.317
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.316",+ "version": "0.9.317", "description": "Reverse bridge for KiCad \u2014 board/schematic introspection, lint via kicad-cli, plugin install, multi-instance probe, in-process DRC.", "homepage": "https://wiki.adom.inc/adom/adom-bridge", "author": "Adom Inc.",
handlers/demo.py+25−9@@ -608,6 +608,7 @@ def _run_step(kicad_info: dict, step: str, prep: dict) -> dict: # A web front-end wants a real progress bar (percent + ETA), not a spinner, and # the bridge is the only party that knows its own timings. One job at a time. import json+import time as _time import sys as _sys import threading as _threading @@ -1718,24 +1719,39 @@ def handle_demo(kicad_info: dict, args: dict) -> dict: # Transport (John, 2026-08-24): the dashboard and the ab toast both land # here. Applied by the job thread between beats. if args.get("control"):+ # The dashboard's buttons land here; ab's panel lands in on_panel_event.+ # Same record, same ack caption, same FIFO (John's laptop run+ # 2026-09-04: dashboard presses were recorded nowhere and acked+ # nowhere, so the run looked like "prev/next don't work"). cmd = str(args["control"]).strip().lower()- if cmd in ("mute", "unmute"):- _NARR["muted"] = (cmd == "mute")- if _NARR["muted"]:- _stop_narration()- return {"success": True, "control": cmd, "muted": _NARR["muted"]}- if cmd not in ("play", "pause", "next", "prev", "exit"):+ if cmd not in ("play", "pause", "next", "prev", "exit", "mute", "unmute"): return {"success": False, "error": f"unknown control '{cmd}'", "_hint": "Controls: play, pause, next, prev, exit, mute, unmute."}+ if cmd in ("mute", "unmute"):+ _apply_mute(cmd == "mute", "dashboard")+ if _job_snapshot().get("active"):+ _caption_ack("Remote: muted" if cmd == "mute" else "Remote: narration back on")+ return {"success": True, "control": cmd, "muted": _NARR["muted"]} if not _job_snapshot().get("active"): return {"success": False, "error": "no demo job is running", "_hint": "Start one with kicad_demo {\"all\":true,\"background\":true}."}+ with _JOB_LOCK:+ _JOB.setdefault("presses", []).append({"button": cmd, "at": int(_time.time()), "via": "dashboard",+ "beat": _JOB.get("beatIndex"), "step": _JOB.get("step")})+ _caption_ack({"play": "Remote: playing", "pause": "Remote: pausing", "next": "Remote: next",+ "prev": "Remote: back", "exit": "Remote: stopping the tour"}[cmd])+ if cmd in ("pause", "exit", "next", "prev"):+ _stop_narration()+ if cmd == "exit":+ _EXIT["now"] = True+ _caption_clear()+ _job_update(stopping=True, stepLabel="Closing the demo tour") set_demo_control(cmd)+ _job_update(lastPress={"button": cmd, "at": int(_time.time()), "via": "dashboard"}) return {"success": True, "control": cmd,- "_hint": ("Applied between beats - a beat that is mid-open finishes "- "first. 'exit' stops the tour, silences narration and "- "clears the caption.")}+ "_hint": ("Honoured at the running beat's next gesture (a window mid-open finishes first). "+ "'exit' stops the tour, silences narration and clears the caption.")} # ---- progress poll (cheap, no side effects) ---- if args.get("layoutProbe"):