feat: full implementation - switcher, device watcher, hotkeys, tray, settings UI
This commit is contained in:
44
config/config.json
Normal file
44
config/config.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"active_profile": "pc1_dp",
|
||||
"profiles": [
|
||||
{
|
||||
"id": "pc1_dp",
|
||||
"name": "PC1 — DP",
|
||||
"hotkey": "ctrl+alt+1",
|
||||
"monitor_inputs": [
|
||||
{"monitor_index": 0, "vcp_value": 15},
|
||||
{"monitor_index": 1, "vcp_value": 15}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "pc2_hdmi",
|
||||
"name": "PC2 — 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
|
||||
}
|
||||
}
|
||||
100
config/config_manager.py
Normal file
100
config/config_manager.py
Normal file
@@ -0,0 +1,100 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user