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.342: First-run wizard deadlock: time-boxed dialog clicks and bounded sweeps (#83)
3 files changed
+19−3
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.341+0.9.342
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.341",+ "version": "0.9.342", "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/close_windows.py+17−1@@ -436,7 +436,17 @@ if IS_WINDOWS: for tier in _DISMISS_BUTTON_TIERS: btn = _find_button(tier) if btn:- user32.SendMessageW(btn, BM_CLICK, 0, 0)+ # NEVER a plain SendMessage here (#83, winvm 2026-09-07): clicking the+ # first-run wizard's Cancel opens its "Are you sure?" Confirmation+ # MODALLY inside the button handler, so a synchronous BM_CLICK does+ # not return until that box is answered, and the only thing that+ # would answer it is this sweep, which is blocked. That deadlock held+ # kicad_open_schematic past ab's 130 s budget. Time-boxed send: the+ # click is delivered, we get control back, the next pass answers the+ # follow-up dialog.+ SMTO_ABORTIFHUNG = 0x0002+ res = ctypes.wintypes.DWORD(0)+ user32.SendMessageTimeoutW(btn, BM_CLICK, 0, 0, SMTO_ABORTIFHUNG, 1500, ctypes.byref(res)) return "clicked-button" # No recognized button — Escape closes most wizards/dialogs cleanly. user32.PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0)@@ -517,7 +527,10 @@ if IS_WINDOWS: # only the first time we see a given hwnd so we don't shoot the same box # repeatedly. Stop as soon as a pass dismisses nothing new. shot_hwnds: set = set()+ _deadline = time.time() + 25.0 # a sweep is never allowed to eat the verb's budget for _pass in range(5):+ if time.time() > _deadline:+ break remaining = [] acted = False for w in _win_scan_kicad_dialogs(kicad_info):@@ -912,7 +925,10 @@ def auto_sweep_dialogs(kicad_info: dict, screenshot: bool = True, dialogs = [] had_error = False seen = set()+ _deadline = time.time() + 25.0 # bounded: ab's budget is 130 s and the verb already spent some for _pass in range(4):+ if time.time() > _deadline:+ break acted = False for w in _win_scan_kicad_dialogs(kicad_info): if not w.get("isDialog"):