113 lines
3.0 KiB
Python
113 lines
3.0 KiB
Python
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()
|