From f261f630f67639910403d8d7e75724c4ab8f2318 Mon Sep 17 00:00:00 2001 From: Owen McGirr Date: Mon, 27 Jul 2026 15:09:24 +0100 Subject: [PATCH 1/5] Add PC Switch Control profiles and output engine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add validated atomic profile persistence with immutable built-in Grid 3 and keyboard profiles - Add mapped desktop and Grid output sessions with state reconciliation and deterministic cleanup - Add an accessible eight-slot profile manager and focused engine tests 🤖 Auto-generated --- src/SwitchifyPc.App/App.xaml.cs | 23 +- src/SwitchifyPc.App/SettingsWindow.xaml | 14 + src/SwitchifyPc.App/SettingsWindow.xaml.cs | 6 +- .../SwitchControlProfileWindow.xaml | 102 ++++++ .../SwitchControlProfileWindow.xaml.cs | 217 +++++++++++++ .../SwitchControl/SwitchControlProfile.cs | 139 ++++++++ .../SwitchControlProfileStore.cs | 167 ++++++++++ .../SwitchControlSessionManager.cs | 305 ++++++++++++++++++ .../SwitchControl/SwitchOutputSessions.cs | 238 ++++++++++++++ .../SwitchControlProfileTests.cs | 103 ++++++ .../SwitchControlSessionManagerTests.cs | 94 ++++++ .../SwitchOutputSessionTests.cs | 120 +++++++ .../Input/WindowsInputMapper.cs | 6 + 13 files changed, 1532 insertions(+), 2 deletions(-) create mode 100644 src/SwitchifyPc.App/SwitchControlProfileWindow.xaml create mode 100644 src/SwitchifyPc.App/SwitchControlProfileWindow.xaml.cs create mode 100644 src/SwitchifyPc.Core/SwitchControl/SwitchControlProfile.cs create mode 100644 src/SwitchifyPc.Core/SwitchControl/SwitchControlProfileStore.cs create mode 100644 src/SwitchifyPc.Core/SwitchControl/SwitchControlSessionManager.cs create mode 100644 src/SwitchifyPc.Core/SwitchControl/SwitchOutputSessions.cs create mode 100644 src/SwitchifyPc.Tests/SwitchControlProfileTests.cs create mode 100644 src/SwitchifyPc.Tests/SwitchControlSessionManagerTests.cs create mode 100644 src/SwitchifyPc.Tests/SwitchOutputSessionTests.cs diff --git a/src/SwitchifyPc.App/App.xaml.cs b/src/SwitchifyPc.App/App.xaml.cs index 80c292a..5dd7331 100644 --- a/src/SwitchifyPc.App/App.xaml.cs +++ b/src/SwitchifyPc.App/App.xaml.cs @@ -9,6 +9,7 @@ using SwitchifyPc.Core.Input; using SwitchifyPc.Core.Pairing; using SwitchifyPc.Core.Settings; +using SwitchifyPc.Core.SwitchControl; using SwitchifyPc.Core.AppLifecycle; using SwitchifyPc.Core.Diagnostics; using SwitchifyPc.Core.Startup; @@ -36,6 +37,7 @@ public partial class App : System.Windows.Application private WindowsExistingInstanceSignal? existingInstanceSignal; private NativeTrayIcon? trayIcon; private SettingsWindow? settingsWindow; + private SwitchControlProfileWindow? switchControlProfileWindow; private SetupGuideWindow? setupGuideWindow; private MainWindowViewModel mainWindowViewModel = new(); private SetupGuideViewModel setupGuideViewModel = new(); @@ -45,6 +47,7 @@ public partial class App : System.Windows.Application private WindowsBluetoothGattServer? bluetoothServer; private BluetoothRemoteFrameProcessor? bluetoothFrameProcessor; private DesktopCommandExecutor? commandExecutor; + private JsonSwitchControlProfileStore? switchControlProfileStore; private MouseRepeatController? mouseRepeatController; private WindowsCursorOverlayNotifier? cursorOverlay; private WindowsModifierKeyOverlayNotifier? modifierOverlay; @@ -154,6 +157,7 @@ protected override void OnExit(ExitEventArgs e) themeManager?.Dispose(); themeManager = null; commandExecutor = null; + switchControlProfileStore = null; bluetoothFrameProcessor = null; bluetoothStatusTracker = null; pairingApprovalManager = null; @@ -164,6 +168,7 @@ protected override void OnExit(ExitEventArgs e) trayIcon?.Dispose(); trayIcon = null; settingsWindow = null; + switchControlProfileWindow = null; setupGuideWindow = null; telemetryReporter?.Dispose(); telemetryReporter = null; @@ -273,7 +278,7 @@ private SetupGuideWindow CreateSetupGuideWindow() private SettingsWindow CreateSettingsWindow() { - SettingsWindow window = new(CreateSettingsController()); + SettingsWindow window = new(CreateSettingsController(), ShowSwitchControlProfiles); window.Closing += (_, eventArgs) => { if (isQuitting) return; @@ -284,6 +289,22 @@ private SettingsWindow CreateSettingsWindow() return window; } + private void ShowSwitchControlProfiles() + { + switchControlProfileStore ??= new JsonSwitchControlProfileStore( + Path.Combine(UserDataDirectory(), "switch-control-profiles.json")); + if (switchControlProfileWindow is null) + { + switchControlProfileWindow = new SwitchControlProfileWindow( + switchControlProfileStore, + () => null); + switchControlProfileWindow.Closed += (_, _) => switchControlProfileWindow = null; + } + switchControlProfileWindow.Owner = settingsWindow; + switchControlProfileWindow.Show(); + switchControlProfileWindow.Activate(); + } + private static void CenterWindow(Window window) { window.Left = SystemParameters.WorkArea.Left + (SystemParameters.WorkArea.Width - window.Width) / 2; diff --git a/src/SwitchifyPc.App/SettingsWindow.xaml b/src/SwitchifyPc.App/SettingsWindow.xaml index 7b99159..78751cc 100644 --- a/src/SwitchifyPc.App/SettingsWindow.xaml +++ b/src/SwitchifyPc.App/SettingsWindow.xaml @@ -368,6 +368,20 @@ + + + + +