import serial import serial.tools.list_ports import win32gui import win32con import win32com.client import time import sys # --- Config --- COM_PORT = "COM3" # change to your Arduino's COM port BAUD_RATE = 9600 TRIGGER_WORD = "DETECTED" COOLDOWN_SEC = 1.5 # minimum seconds between switches IGNORE_TITLES = {"", "Program Manager", "Windows Input Experience"} def list_ports(): ports = serial.tools.list_ports.comports() if not ports: print("No serial ports found.") else: print("Available ports:") for p in ports: print(f" {p.device} — {p.description}") def get_windows(): """Return list of (hwnd, title) for all visible, non-minimized top-level windows.""" results = [] def callback(hwnd, _): if not win32gui.IsWindowVisible(hwnd): return title = win32gui.GetWindowText(hwnd) if title and title not in IGNORE_TITLES: results.append((hwnd, title)) win32gui.EnumWindows(callback, None) return results def force_focus(hwnd): """Bring window to foreground, bypassing Windows focus-steal protection.""" shell = win32com.client.Dispatch("WScript.Shell") shell.SendKeys('%') # simulate Alt — tricks Windows into allowing focus change if win32gui.IsIconic(hwnd): win32gui.ShowWindow(hwnd, win32con.SW_RESTORE) win32gui.SetForegroundWindow(hwnd) class WindowSwitcher: def __init__(self): self.index = 0 self.last_switch = 0 def switch(self): now = time.time() if now - self.last_switch < COOLDOWN_SEC: return windows = get_windows() if not windows: print("No windows found.") return self.index = (self.index + 1) % len(windows) hwnd, title = windows[self.index] try: force_focus(hwnd) print(f"[{time.strftime('%H:%M:%S')}] → {title}") self.last_switch = now except Exception as e: print(f"Could not switch to '{title}': {e}") def main(): if "--list-ports" in sys.argv: list_ports() return if "--test" in sys.argv: # Test window switching without Arduino print("Test mode — switching window in 2 seconds...") time.sleep(2) WindowSwitcher().switch() return print(f"Connecting to {COM_PORT} at {BAUD_RATE} baud...") print("Press Ctrl+C to stop.\n") switcher = WindowSwitcher() try: ser = serial.Serial(COM_PORT, BAUD_RATE, timeout=1) print(f"Connected. Waiting for '{TRIGGER_WORD}' signal...\n") while True: line = ser.readline().decode("utf-8", errors="ignore").strip() if line == TRIGGER_WORD: switcher.switch() except serial.SerialException as e: print(f"Serial error: {e}") print("\nAvailable ports:") list_ports() except KeyboardInterrupt: print("\nStopped.") if __name__ == "__main__": main()