import json import copy from pathlib import Path from typing import Callable DEFAULT_CONFIG = { "active_profile": "pc1_dp", "profiles": [ { "id": "pc1_dp", "name": "PC1 \u2014 DP", "hotkey": "ctrl+alt+1", "monitor_inputs": [ {"monitor_index": 0, "vcp_value": 15}, {"monitor_index": 1, "vcp_value": 15} ] }, { "id": "pc2_hdmi", "name": "PC2 \u2014 HDMI", "hotkey": "ctrl+alt+2", "monitor_inputs": [ {"monitor_index": 0, "vcp_value": 17}, {"monitor_index": 1, "vcp_value": 17} ] } ], "device_triggers": [ { "name": "HP 975 keyboard", "bt_device_id": "VID&0203F0_PID&6343", "on_connect": "pc1_dp", "on_disconnect": "pc2_hdmi", "enabled": True }, { "name": "MX Anywhere 2S", "bt_device_id": "VID&02046D_PID&B01A", "on_connect": "pc1_dp", "on_disconnect": "pc2_hdmi", "enabled": True } ], "general": { "autostart": True, "minimize_to_tray": True, "debounce_ms": 500 } } class ConfigManager: def __init__(self, config_path=None): if config_path is None: config_path = Path(__file__).parent / "config.json" self.config_path = Path(config_path) self._config: dict = {} self._callbacks: list[Callable] = [] self.load() def load(self) -> None: if self.config_path.exists(): try: with open(self.config_path, "r", encoding="utf-8") as f: self._config = json.load(f) except (json.JSONDecodeError, OSError): self._config = copy.deepcopy(DEFAULT_CONFIG) else: self._config = copy.deepcopy(DEFAULT_CONFIG) self.save() def save(self) -> None: self.config_path.parent.mkdir(parents=True, exist_ok=True) with open(self.config_path, "w", encoding="utf-8") as f: json.dump(self._config, f, indent=2, ensure_ascii=False) def get(self) -> dict: return self._config def update(self, new_config: dict) -> None: self._config = new_config self.save() for cb in self._callbacks: cb(self._config) def on_change(self, callback: Callable) -> None: self._callbacks.append(callback) def get_profile(self, profile_id: str) -> dict | None: for p in self._config.get("profiles", []): if p["id"] == profile_id: return p return None def get_active_profile_id(self) -> str: return self._config.get("active_profile", "pc1_dp") def set_active_profile(self, profile_id: str) -> None: self._config["active_profile"] = profile_id self.save()