← Commit history

0.9.316: Tour remote: FIFO press queue (no press lost), poll-drained presses recorded, presses on progress

John Lauer ·207ef205ff ·1mo ago ·parent 80a3105
3 files changed +26−11
BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.9.315\ No newline at end of file+0.9.316\ No newline at end of file
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "kicad",   "displayName": "KiCad EDA",-  "version": "0.9.315",+  "version": "0.9.316",   "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+24−9
@@ -1080,13 +1080,20 @@ def _stop_narration() -> None: # interrupted mid-verb) and while paused; exit also silences narration and # clears the caption. _CTL_TOAST_ID = "kicad-demo-ctl"-_CTRL: dict = {"cmd": None, "seq": 0}+_CTRL: dict = {"cmd": None, "seq": 0, "queue": []}   # queue: FIFO of presses not yet honoured _CTRL_LOCK = _threading.Lock()   def set_demo_control(cmd: str) -> None:+    """Queue a transport command. FIFO (measured on ConfRoomROG 2026-09-04: a+    single slot lost a 'next' when 'back' arrived during the same beat's+    un-interruptible window open). 'exit' jumps the queue."""     with _CTRL_LOCK:-        _CTRL["cmd"] = cmd+        if cmd == "exit":+            _CTRL["queue"] = ["exit"]+        elif len(_CTRL["queue"]) < 8:+            _CTRL["queue"].append(cmd)+        _CTRL["cmd"] = _CTRL["queue"][0] if _CTRL["queue"] else None   def _post_transport(body: str, paused: bool = False) -> None:@@ -1299,13 +1306,21 @@ def _panel_poll() -> str | None:             _apply_mute(bool(d["muted"]), "panel-poll")         events = [e for e in (d.get("events") or []) if str((e or {}).get("at")) not in _PANEL_SEEN]         mapping = {"back": "prev", "play": "play", "pause": "pause", "next": "next", "stop": "exit"}-        for ev in reversed(events):+        for ev in events:             b = str((ev or {}).get("button") or "").lower()+            _PANEL_SEEN.add(str((ev or {}).get("at")))+            with _JOB_LOCK:+                _JOB.setdefault("presses", []).append({"button": b, "at": (ev or {}).get("at"), "via": "poll",+                                                       "beat": _JOB.get("beatIndex"), "step": _JOB.get("step")})             if b in ("mute", "unmute"):                 _apply_mute(b == "mute", "panel-poll")                 continue             if b in mapping:-                return mapping[b]+                set_demo_control(mapping[b])+        with _CTRL_LOCK:+            if _CTRL["queue"]:+                cmd = _CTRL["queue"].pop(0); _CTRL["cmd"] = _CTRL["queue"][0] if _CTRL["queue"] else None+                return cmd         if d.get("state") == "paused":             return "pause-held"     except Exception:  # pylint: disable=broad-except@@ -1347,8 +1362,8 @@ def _panel_hide() -> None: def _drain_ctrl() -> str | None:     """One pending control command, from the verb channel or a toast click."""     with _CTRL_LOCK:-        cmd = _CTRL["cmd"]-        _CTRL["cmd"] = None+        cmd = _CTRL["queue"].pop(0) if _CTRL["queue"] else None+        _CTRL["cmd"] = _CTRL["queue"][0] if _CTRL["queue"] else None     if cmd:         return cmd     pc = _panel_poll()@@ -1503,7 +1518,7 @@ def _run_demo_background(kicad_info: dict) -> None:         # the mute from THIS call's args and swallow whatever the panel queued.         _NARR["muted"] = bool(_JOB.get("mutedRequested"))         with _CTRL_LOCK:-            _CTRL["cmd"] = None            # a control queued against the previous tour must not steer this one+            _CTRL["cmd"] = None; _CTRL["queue"] = []   # a control queued against the previous tour must not steer this one         _drain_stale_presses()         _restore_bounds("leftovers")            # a crashed earlier tour never leaves windows moved         _close_stale_tour_windows()@@ -1637,7 +1652,7 @@ def _run_demo_background(kicad_info: dict) -> None:                     break                 if cmd:                     with _CTRL_LOCK:      # keep it for the between-beat check-                        _CTRL["cmd"] = cmd+                        _CTRL["queue"].insert(0, cmd); _CTRL["cmd"] = cmd                     break                 _t.sleep(0.5)             if exited:@@ -1733,7 +1748,7 @@ def handle_demo(kicad_info: dict, args: dict) -> dict:         out = {"success": True, **{k: snap.get(k) for k in                ("done", "step", "stepLabel", "beatIndex", "beatCount",                 "percent", "elapsedSec", "estimatedSec", "error",-                "panel", "muted", "muteSource", "lastPress", "paused", "stopping", "verified", "captions", "windowsRestored")}}+                "panel", "muted", "muteSource", "lastPress", "presses", "paused", "stopping", "verified", "captions", "windowsRestored")}}         # 0.9.199 (wiki issue #39, John): `active` used to be a BOOLEAN here and         # an ARRAY in kicad_progress - the same key, two types, from one bridge.         # A renderer written as `if (resp.active)` then treats a finished job as