Refactor KVM switch logic to enforce input source based on auxiliary monitor presence and update related documentation and tests

This commit is contained in:
Lago
2026-03-27 16:05:20 +01:00
parent 3f7c5a0677
commit dc3b67d00a
4 changed files with 111 additions and 42 deletions
+13 -30
View File
@@ -80,7 +80,6 @@ class KvmSwitcherService:
self._samsung_session_attempted = False
self._samsung_session_successful = False
self._samsung_session_attempt_count = 0
self._last_trigger_input_code: int | None = None
self._state_lock = Lock()
self._stop_event = Event()
self._thread: Thread | None = None
@@ -124,7 +123,7 @@ class KvmSwitcherService:
scan=scan,
errors=errors,
)
self._update_samsung_session(scan.samsung_present, trigger_input_code)
self._update_samsung_session(scan.samsung_present)
ddm_slot = self.ddm_backend.resolve_alienware_slot(force=False)
supports_monitor_targeting = bool(
@@ -140,8 +139,8 @@ class KvmSwitcherService:
blocking_errors = [error for error in errors if _is_blocking_error(error)]
trigger_target_port = self._port_name_for_input_code(trigger_input_code)
desired_port = self._resolve_desired_port(config, trigger_input_code)
trigger_matches_device_port = desired_port is not None
desired_port = self._resolve_desired_port(config)
trigger_matches_device_port = scan.samsung_present
last_switch_result = "idle"
with self._state_lock:
last_switch_at = self._status.last_switch_at
@@ -159,8 +158,9 @@ class KvmSwitcherService:
desired_codes = self._port_input_codes(desired_port)
if scan.alienware_input_code is not None and scan.alienware_input_code in desired_codes:
last_switch_result = "noop"
self._samsung_session_attempted = True
self._samsung_session_attempted = False
self._samsung_session_successful = True
self._samsung_session_attempt_count = 0
else:
last_switch_result, last_switch_at, scan, errors = self._attempt_switch_sequence(
config=config,
@@ -170,12 +170,10 @@ class KvmSwitcherService:
last_switch_at=last_switch_at,
errors=errors,
)
elif trigger_matches_device_port and self._samsung_session_successful:
elif scan.samsung_present and self._samsung_session_successful:
last_switch_result = "waiting_for_disconnect"
elif trigger_matches_device_port and self._samsung_session_attempt_count >= 3:
elif scan.samsung_present and self._samsung_session_attempt_count >= 3:
last_switch_result = "max_attempts_waiting_for_disconnect"
elif scan.samsung_present:
last_switch_result = "waiting_for_trigger_match"
status = ServiceStatus(
config=config,
@@ -217,14 +215,8 @@ class KvmSwitcherService:
@staticmethod
def _resolve_desired_port(
config: AppConfig,
trigger_input: int | None,
) -> str | None:
if trigger_input is None:
return None
desired_codes = KvmSwitcherService._port_input_codes(config.device_port)
if trigger_input in desired_codes:
return config.device_port
return None
return config.device_port
@staticmethod
def _port_input_codes(port_name: str) -> set[int]:
@@ -243,13 +235,12 @@ class KvmSwitcherService:
return port_name
return None
def _update_samsung_session(self, samsung_present: bool, trigger_input_code: int | None) -> None:
def _update_samsung_session(self, samsung_present: bool) -> None:
if not samsung_present:
self._samsung_session_active = False
self._samsung_session_attempted = False
self._samsung_session_successful = False
self._samsung_session_attempt_count = 0
self._last_trigger_input_code = None
return
if not self._samsung_session_active:
@@ -257,14 +248,6 @@ class KvmSwitcherService:
self._samsung_session_attempted = False
self._samsung_session_successful = False
self._samsung_session_attempt_count = 0
self._last_trigger_input_code = trigger_input_code
return
if trigger_input_code != self._last_trigger_input_code:
self._samsung_session_attempted = False
self._samsung_session_successful = False
self._samsung_session_attempt_count = 0
self._last_trigger_input_code = trigger_input_code
def _attempt_switch_sequence(
self,
@@ -295,28 +278,28 @@ class KvmSwitcherService:
verify_scan = self.monitor_backend.scan()
scan = verify_scan
errors.extend(verify_scan.errors)
verify_trigger_input, _, _ = self._resolve_trigger_state(
self._resolve_trigger_state(
config=config,
scan=verify_scan,
errors=errors,
)
self._update_samsung_session(verify_scan.samsung_present, verify_trigger_input)
self._update_samsung_session(verify_scan.samsung_present)
if not verify_scan.samsung_present:
return "waiting_for_reconnect", last_switch_at, scan, errors
desired_codes = self._port_input_codes(desired_port)
if verify_trigger_input not in desired_codes:
return "waiting_for_trigger_match", last_switch_at, scan, errors
if verify_scan.alienware_input_code is None:
errors.append(
"Alienware input could not be read after switch; assuming success because switch command completed."
)
self._samsung_session_successful = True
self._samsung_session_attempt_count = 0
return "switched_unverified", last_switch_at, scan, errors
if verify_scan.alienware_input_code in desired_codes:
self._samsung_session_successful = True
self._samsung_session_attempt_count = 0
return last_result, last_switch_at, scan, errors
return "max_attempts_waiting_for_disconnect", last_switch_at, scan, errors