app
Adom Desktop - 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.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
"""Handler for fix_keyboard command.
Windows: releases stuck modifier keys (Alt, Ctrl, Shift, Win) and unlocks
the foreground window lock — recovery for when keybd_event/SendKeys leaves
keys held at the OS level after KiCad UI automation.
macOS: no-op. Stuck modifier keys aren't a problem on macOS because we don't
use SendKeys-style automation against KiCad windows (UI scripting requires
Accessibility permission, which we don't request).
"""
import ctypes
import ctypes.wintypes
import sys
IS_WINDOWS = sys.platform == "win32"
if IS_WINDOWS:
user32 = ctypes.windll.user32
else:
user32 = None
# Key-up flag
KEYEVENTF_KEYUP = 0x0002
# Virtual key codes for all modifier keys
_MODIFIER_KEYS = [
0x12, # VK_MENU (Alt generic)
0xA4, # VK_LMENU (Left Alt)
0xA5, # VK_RMENU (Right Alt)
0x11, # VK_CONTROL (Ctrl generic)
0xA2, # VK_LCONTROL (Left Ctrl)
0xA3, # VK_RCONTROL (Right Ctrl)
0x10, # VK_SHIFT (Shift generic)
0xA0, # VK_LSHIFT (Left Shift)
0xA1, # VK_RSHIFT (Right Shift)
0x5B, # VK_LWIN (Left Win)
0x5C, # VK_RWIN (Right Win)
]
# SystemParametersInfo constants
SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001
SPIF_UPDATEINIFILE = 0x01
SPIF_SENDCHANGE = 0x02
def _get_stuck_keys() -> list[str]:
"""Check which modifier keys are currently pressed/stuck."""
stuck = []
names = {
0x12: "Alt", 0x11: "Ctrl", 0x10: "Shift", 0x5B: "LWin", 0x5C: "RWin",
}
for vk, name in names.items():
state = user32.GetAsyncKeyState(vk)
if state & 0x8000:
stuck.append(name)
return stuck
def handle_fix_keyboard(kicad_info: dict, args: dict) -> dict:
"""Release all stuck modifier keys and unlock foreground window focus.
Windows-only recovery for keybd_event/SendKeys leaving modifiers stuck.
On macOS this returns a no-op success since we don't have the same problem.
"""
if not IS_WINDOWS:
return {
"success": True,
"output": "fix_keyboard is a Windows-only recovery command (no-op on this platform).",
}
# 1. Check which keys are stuck before fix
stuck_before = _get_stuck_keys()
# 2. Release all modifier keys (10 rounds for reliability)
for _ in range(10):
for vk in _MODIFIER_KEYS:
user32.keybd_event(vk, 0, KEYEVENTF_KEYUP, 0)
# 3. Unlock foreground window lock (LSFW_UNLOCK = 2)
user32.LockSetForegroundWindow(2)
# 4. Reset foreground lock timeout to 0 (allow any app to take foreground)
user32.SystemParametersInfoW(
SPI_SETFOREGROUNDLOCKTIMEOUT, 0, None,
SPIF_UPDATEINIFILE | SPIF_SENDCHANGE,
)
# 5. Verify
stuck_after = _get_stuck_keys()
if stuck_before:
detail = f"Stuck keys detected: {', '.join(stuck_before)}. "
else:
detail = "No stuck keys detected via GetAsyncKeyState. "
if stuck_after:
detail += f"WARNING: Keys still stuck after fix: {', '.join(stuck_after)}. "
detail += "User may need to sign out and back in."
return {
"success": True,
"output": detail + " Modifier keys released, foreground lock cleared.",
}
else:
detail += "All modifier keys released successfully."
return {
"success": True,
"output": detail + " Foreground lock cleared.",
}