From 5f11fe46c801882d0e8251b9829d0ee859c4029f Mon Sep 17 00:00:00 2001 From: Lesueur Benjamin Date: Wed, 9 Oct 2024 10:50:38 +0200 Subject: [PATCH] Implement support for Rog Ally X (#362) * Initial commit * add oem118 failsafe * todo: check PnPDevice PID/VID to deploy the appropriate inf * use vendorID and productID to pull the appropriate XInput driver - Generic XInput: xusb22.inf - Custom XInput (Rog Ally X): oem118.inf * Fixed an issue causing a crash on empty profile.TDPOverrideValues * Revert "Fixed an issue causing a crash on empty profile.TDPOverrideValues" This reverts commit 5fa36ec0c594c5f817ba80e35329ff72217b6c29. * improve controller drivers store logic * remove SuspendedControllers * improve DeviceManager fail-safe drivers restoration * add rog_ally_x illustration, thanks to @romracer * oups * improve memory management * improve virtual controller disposal on suspend * Fixed an issue affecting Alt Gr key locking LControl * Fixed an issue causing a crash when failing to retrieve deviceInfo for OneXPlayerX1 * Fix an issue preventing HC to load properly on X1Mini, which doesn't seams to have a serial chip * update libraries * remove splashscreen loading text * on popular demand, improve UI navigation when desktop layout is enabled inputs sent to UI are now post layout management * improve gamepad navigation on combobox. Handle disabled ComboBoxItem * prevent disabled comboBoxItem from being selected * clear hidDevices array on device Close() * build 0.21.6.1 * update ROGAllyX default power profiles * code cleanup * make PerformanceGuids public --- HandheldCompanion.iss | 2 +- .../Controllers/IController.xaml.cs | 2 +- .../Controllers/NeptuneController.cs | 4 +- .../Controllers/RumbleConverter.cs | 8 +- HandheldCompanion/Controls/ProcessEx.cs | 1 + HandheldCompanion/Devices/ASUS/ROGAlly.cs | 9 +- HandheldCompanion/Devices/ASUS/ROGAllyX.cs | 33 +++++ HandheldCompanion/Devices/IDevice.cs | 50 +------ HandheldCompanion/Devices/Lenovo/LegionGo.cs | 8 +- HandheldCompanion/Devices/MSI/ClawA1M.cs | 6 +- .../Devices/Minisforum/MinisforumV3.cs | 7 +- .../Devices/OneXPlayer/OneXPlayerX1.cs | 32 +++-- .../Devices/OneXPlayer/OneXPlayerX1Intel.cs | 6 +- .../Devices/OneXPlayer/OneXPlayerX1Mini.cs | 2 + HandheldCompanion/HandheldCompanion.csproj | 20 +-- .../Managers/ControllerManager.cs | 135 +++++++++++++----- HandheldCompanion/Managers/DeviceManager.cs | 10 +- HandheldCompanion/Managers/InputsManager.cs | 6 + .../Managers/PerformanceManager.cs | 4 +- HandheldCompanion/Managers/ProcessManager.cs | 4 +- HandheldCompanion/Managers/VirtualManager.cs | 24 +--- .../Properties/Settings.Designer.cs | 29 +--- .../Properties/Settings.settings | 6 - .../DeviceImages/device_rog_ally_x.png | Bin 0 -> 11850 bytes HandheldCompanion/UI/UIGamepad.cs | 43 ++++-- HandheldCompanion/Utils/DeviceUtils.cs | 14 +- .../QuickPages/QuickProfilesPage.xaml.cs | 2 +- HandheldCompanion/Views/SplashScreen.xaml | 23 ++- .../Views/Windows/MainWindow.xaml.cs | 22 +-- 29 files changed, 269 insertions(+), 243 deletions(-) create mode 100644 HandheldCompanion/Devices/ASUS/ROGAllyX.cs create mode 100644 HandheldCompanion/Resources/DeviceImages/device_rog_ally_x.png diff --git a/HandheldCompanion.iss b/HandheldCompanion.iss index c4a2f7826..82349543c 100644 --- a/HandheldCompanion.iss +++ b/HandheldCompanion.iss @@ -26,7 +26,7 @@ #define InstallerVersion '0.2' #define MyAppSetupName 'Handheld Companion' #define MyBuildId 'HandheldCompanion' -#define MyAppVersion '0.21.6.0' +#define MyAppVersion '0.21.6.1' #define MyAppPublisher 'BenjaminLSR' #define MyAppCopyright 'Copyright @ BenjaminLSR' #define MyAppURL 'https://github.com/Valkirie/HandheldCompanion' diff --git a/HandheldCompanion/Controllers/IController.xaml.cs b/HandheldCompanion/Controllers/IController.xaml.cs index c6fb395ea..f4683422c 100644 --- a/HandheldCompanion/Controllers/IController.xaml.cs +++ b/HandheldCompanion/Controllers/IController.xaml.cs @@ -90,7 +90,7 @@ public partial class IController : UserControl private Thread workingThread; private bool workingThreadRunning; - protected object hidlock = new(); + protected object hidLock = new(); public virtual bool IsReady => true; public virtual bool IsWireless => false; diff --git a/HandheldCompanion/Controllers/NeptuneController.cs b/HandheldCompanion/Controllers/NeptuneController.cs index b92469a09..c58672cf9 100644 --- a/HandheldCompanion/Controllers/NeptuneController.cs +++ b/HandheldCompanion/Controllers/NeptuneController.cs @@ -289,7 +289,7 @@ private void Close() public override void Hide(bool powerCycle = true) { - lock (hidlock) + lock (hidLock) { Close(); base.Hide(powerCycle); @@ -305,7 +305,7 @@ public override void Unhide(bool powerCycle = true) if (IsExclusiveMode) return; - lock (hidlock) + lock (hidLock) { Close(); base.Unhide(powerCycle); diff --git a/HandheldCompanion/Controllers/RumbleConverter.cs b/HandheldCompanion/Controllers/RumbleConverter.cs index a9b0d0319..62658c656 100644 --- a/HandheldCompanion/Controllers/RumbleConverter.cs +++ b/HandheldCompanion/Controllers/RumbleConverter.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace HandheldCompanion.Controllers +namespace HandheldCompanion.Controllers { // Function to map the Xbox rumble value to Nintendo Switch HD Rumble public class RumbleConverter diff --git a/HandheldCompanion/Controls/ProcessEx.cs b/HandheldCompanion/Controls/ProcessEx.cs index 166d0f992..921107803 100644 --- a/HandheldCompanion/Controls/ProcessEx.cs +++ b/HandheldCompanion/Controls/ProcessEx.cs @@ -377,6 +377,7 @@ public void Dispose() Process?.Dispose(); MainThread?.Dispose(); ChildrenProcessIds.Dispose(); + ProcessWindows.Clear(); GC.SuppressFinalize(this); //now, the finalizer won't be called } diff --git a/HandheldCompanion/Devices/ASUS/ROGAlly.cs b/HandheldCompanion/Devices/ASUS/ROGAlly.cs index a220b463e..38f4a3fb7 100644 --- a/HandheldCompanion/Devices/ASUS/ROGAlly.cs +++ b/HandheldCompanion/Devices/ASUS/ROGAlly.cs @@ -129,7 +129,7 @@ public ROGAlly() OEMPowerMode = (int)AsusMode.Silent, OSPowerMode = OSPowerMode.BetterBattery, CPUBoostLevel = CPUBoostLevel.Disabled, - Guid = new("961cc777-2547-4f9d-8174-7d86181b8a7a"), + Guid = BetterBatteryGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 10.0d, 10.0d, 10.0d } }); @@ -140,7 +140,7 @@ public ROGAlly() DeviceDefault = true, OEMPowerMode = (int)AsusMode.Performance, OSPowerMode = OSPowerMode.BetterPerformance, - Guid = new("3af9B8d9-7c97-431d-ad78-34a8bfea439f"), + Guid = BetterPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 15.0d, 15.0d, 15.0d } }); @@ -151,7 +151,7 @@ public ROGAlly() DeviceDefault = true, OEMPowerMode = (int)AsusMode.Turbo, OSPowerMode = OSPowerMode.BestPerformance, - Guid = new("ded574b5-45a0-4f42-8737-46345c09c238"), + Guid = BestPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 25.0d, 25.0d, 25.0d } }); @@ -367,6 +367,8 @@ public override void Close() } } + hidDevices.Clear(); + base.Close(); } @@ -709,7 +711,6 @@ public void SendHidControlWrite(byte[] data) if (device.IsConnected) device.WriteFeatureData(data); } - } public void SetBatteryChargeLimit(int chargeLimit) diff --git a/HandheldCompanion/Devices/ASUS/ROGAllyX.cs b/HandheldCompanion/Devices/ASUS/ROGAllyX.cs new file mode 100644 index 000000000..7331c8e8c --- /dev/null +++ b/HandheldCompanion/Devices/ASUS/ROGAllyX.cs @@ -0,0 +1,33 @@ +using HandheldCompanion.Misc; +using System.Linq; +using System.Numerics; + +namespace HandheldCompanion.Devices; + +public class ROGAllyX : ROGAlly +{ + public ROGAllyX() + { + // device specific settings + ProductIllustration = "device_rog_ally_x"; + + // used to monitor OEM specific inputs + _pid = 0x1B4C; + + // overwrite ROGAlly default gyrometer axis settings + GyrometerAxis = new Vector3(1.0f, 1.0f, -1.0f); + + // overwrite ROGAlly default power profiles + PowerProfile powerProfile = DevicePowerProfiles.FirstOrDefault(profile => profile.Guid == BetterBatteryGuid); + if (powerProfile != null) + powerProfile.TDPOverrideValues = new[] { 13.0d, 13.0d, 13.0d }; + + powerProfile = DevicePowerProfiles.FirstOrDefault(profile => profile.Guid == BetterPerformanceGuid); + if (powerProfile != null) + powerProfile.TDPOverrideValues = new[] { 17.0d, 17.0d, 17.0d }; + + powerProfile = DevicePowerProfiles.FirstOrDefault(profile => profile.Guid == BestPerformanceGuid); + if (powerProfile != null) + powerProfile.TDPOverrideValues = new[] { 25.0d, 25.0d, 25.0d }; + } +} \ No newline at end of file diff --git a/HandheldCompanion/Devices/IDevice.cs b/HandheldCompanion/Devices/IDevice.cs index b58b86283..82681834e 100644 --- a/HandheldCompanion/Devices/IDevice.cs +++ b/HandheldCompanion/Devices/IDevice.cs @@ -12,7 +12,6 @@ using Sentry; using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.Linq; using System.Numerics; using System.Windows.Media; @@ -66,6 +65,10 @@ public abstract class IDevice public delegate void KeyReleasedEventHandler(ButtonFlags button); public delegate void PowerStatusChangedEventHandler(IDevice device); + public static readonly Guid BetterBatteryGuid = new Guid("961cc777-2547-4f9d-8174-7d86181b8a7a"); + public static readonly Guid BetterPerformanceGuid = new Guid("3af9B8d9-7c97-431d-ad78-34a8bfea439f"); + public static readonly Guid BestPerformanceGuid = new Guid("ded574b5-45a0-4f42-8737-46345c09c238"); + protected static OpenLibSys openLibSys; protected object updateLock = new(); @@ -479,6 +482,9 @@ public static IDevice GetCurrent() case "RC71L": device = new ROGAlly(); break; + case "RC72LA": + device = new ROGAllyX(); + break; } } break; @@ -865,48 +871,6 @@ public bool HasKey() return false; } - protected void ResumeDevices() - { - List successes = []; - - StringCollection deviceInstanceIds = SettingsManager.GetStringCollection("SuspendedDevices"); - - if (deviceInstanceIds is null) - deviceInstanceIds = []; - - foreach (string InstanceId in deviceInstanceIds) - { - if (PnPUtil.EnableDevice(InstanceId)) - successes.Add(InstanceId); - } - - foreach (string InstanceId in successes) - deviceInstanceIds.Remove(InstanceId); - - SettingsManager.SetProperty("SuspendedDevices", deviceInstanceIds); - } - - protected bool SuspendDevice(string InterfaceId) - { - PnPDevice pnPDevice = PnPDevice.GetDeviceByInterfaceId(InterfaceId); - if (pnPDevice is not null) - { - StringCollection deviceInstanceIds = SettingsManager.GetStringCollection("SuspendedDevices"); - - if (deviceInstanceIds is null) - deviceInstanceIds = []; - - if (!deviceInstanceIds.Contains(pnPDevice.InstanceId)) - deviceInstanceIds.Add(pnPDevice.InstanceId); - - SettingsManager.SetProperty("SuspendedDevices", deviceInstanceIds); - - return PnPUtil.DisableDevice(pnPDevice.InstanceId); - } - - return false; - } - public static IEnumerable GetHidDevices(int vendorId, int deviceId, int minFeatures = 1) { HidDevice[] HidDeviceList = HidDevices.Enumerate(vendorId, new int[] { deviceId }).ToArray(); diff --git a/HandheldCompanion/Devices/Lenovo/LegionGo.cs b/HandheldCompanion/Devices/Lenovo/LegionGo.cs index 955f7780b..abef4e090 100644 --- a/HandheldCompanion/Devices/Lenovo/LegionGo.cs +++ b/HandheldCompanion/Devices/Lenovo/LegionGo.cs @@ -245,7 +245,7 @@ public LegionGo() OSPowerMode = OSPowerMode.BetterBattery, CPUBoostLevel = CPUBoostLevel.Disabled, OEMPowerMode = (int)LegionMode.Quiet, - Guid = new("961cc777-2547-4f9d-8174-7d86181b8a7a"), + Guid = BetterBatteryGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 8.0d, 8.0d, 8.0d } }); @@ -257,7 +257,7 @@ public LegionGo() DeviceDefault = true, OSPowerMode = OSPowerMode.BetterPerformance, OEMPowerMode = (int)LegionMode.Balanced, - Guid = new("3af9B8d9-7c97-431d-ad78-34a8bfea439f"), + Guid = BetterPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 15.0d, 15.0d, 15.0d } }); @@ -269,7 +269,7 @@ public LegionGo() DeviceDefault = true, OSPowerMode = OSPowerMode.BestPerformance, OEMPowerMode = (int)LegionMode.Performance, - Guid = new("ded574b5-45a0-4f42-8737-46345c09c238"), + Guid = BestPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 20.0d, 20.0d, 20.0d } }); @@ -381,6 +381,8 @@ public override void Close() device.CloseDevice(); } + hidDevices.Clear(); + // Reset the fan speed to default before device shutdown/restart SetFanFullSpeedAsync(false); diff --git a/HandheldCompanion/Devices/MSI/ClawA1M.cs b/HandheldCompanion/Devices/MSI/ClawA1M.cs index f1c145db0..b17d51c7c 100644 --- a/HandheldCompanion/Devices/MSI/ClawA1M.cs +++ b/HandheldCompanion/Devices/MSI/ClawA1M.cs @@ -115,7 +115,7 @@ public ClawA1M() DeviceDefault = true, OSPowerMode = OSPowerMode.BetterBattery, CPUBoostLevel = CPUBoostLevel.Disabled, - Guid = new("961cc777-2547-4f9d-8174-7d86181b8a7a"), + Guid = BetterBatteryGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 20.0d, 20.0d, 20.0d } }); @@ -125,7 +125,7 @@ public ClawA1M() Default = true, DeviceDefault = true, OSPowerMode = OSPowerMode.BetterPerformance, - Guid = new("3af9B8d9-7c97-431d-ad78-34a8bfea439f"), + Guid = BetterPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 30.0d, 30.0d, 30.0d } }); @@ -135,7 +135,7 @@ public ClawA1M() Default = true, DeviceDefault = true, OSPowerMode = OSPowerMode.BestPerformance, - Guid = new("ded574b5-45a0-4f42-8737-46345c09c238"), + Guid = BestPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 35.0d, 35.0d, 35.0d } }); diff --git a/HandheldCompanion/Devices/Minisforum/MinisforumV3.cs b/HandheldCompanion/Devices/Minisforum/MinisforumV3.cs index 18baf305d..1e1d6ce2e 100644 --- a/HandheldCompanion/Devices/Minisforum/MinisforumV3.cs +++ b/HandheldCompanion/Devices/Minisforum/MinisforumV3.cs @@ -1,5 +1,4 @@ using HandheldCompanion.Managers; -using HandheldCompanion.Misc; using System.Collections.Generic; using System.Numerics; using System.Runtime.InteropServices; @@ -63,7 +62,7 @@ public MinisforumV3() OSPowerMode = OSPowerMode.BetterBattery, OEMPowerMode = (int)MinisForumMode.Quiet, CPUBoostLevel = CPUBoostLevel.Disabled, - Guid = new("961cc777-2547-4f9d-8174-7d86181b8a7a"), + Guid = BetterBatteryGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 15.0d, 15.0d, 15.0d } }); @@ -74,7 +73,7 @@ public MinisforumV3() DeviceDefault = true, OSPowerMode = OSPowerMode.BetterPerformance, OEMPowerMode = (int)MinisForumMode.Balanced, - Guid = new("3af9B8d9-7c97-431d-ad78-34a8bfea439f"), + Guid = BetterPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 22.0d, 22.0d, 22.0d } }); @@ -85,7 +84,7 @@ public MinisforumV3() DeviceDefault = true, OSPowerMode = OSPowerMode.BestPerformance, OEMPowerMode = (int)MinisForumMode.Performance, - Guid = new("ded574b5-45a0-4f42-8737-46345c09c238"), + Guid = BestPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 28.0d, 28.0d, 28.0d } }); diff --git a/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1.cs b/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1.cs index 8818be810..7c1b19f50 100644 --- a/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1.cs +++ b/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1.cs @@ -129,23 +129,27 @@ public override bool Open() if (EnableSerialPort) { - var devices = GetSerialDevices(); + List devices = GetSerialDevices(); USBDeviceInfo deviceInfo = devices.FirstOrDefault(a => a.Name.Contains(SerialPortDeviceName)); - - var SerialPortName = Regex.Match(deviceInfo.Name, "COM\\d+").Value; - - // Add the serial port name to be excluded for other instances - SerialUSBIMU.SerialPortNamesInUse.Add(SerialPortName); - - // Initialize and open the serial port if it has not been initialized yet - if (_serialPort is null) + if (deviceInfo is null) { - _serialPort = new SerialPort(SerialPortName, SerialPortBaudRate, SerialPortParity, SerialPortDataBits, - SerialPortStopBits); - _serialPort.Open(); - - LogManager.LogInformation("Enabled Serial Port Control: {0}", _serialPort.PortName); + LogManager.LogInformation("Failed to retrieve serial device with name: {0}", SerialPortDeviceName); + } + else + { + // Add the serial port name to be excluded for other instances + string SerialPortName = Regex.Match(deviceInfo.Name, "COM\\d+").Value; + SerialUSBIMU.SerialPortNamesInUse.Add(SerialPortName); + + // Initialize and open the serial port if it has not been initialized yet + if (_serialPort is null) + { + _serialPort = new SerialPort(SerialPortName, SerialPortBaudRate, SerialPortParity, SerialPortDataBits, SerialPortStopBits); + _serialPort.Open(); + + LogManager.LogInformation("Enabled Serial Port Control: {0}", _serialPort.PortName); + } } } diff --git a/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1Intel.cs b/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1Intel.cs index 87b816c5d..1b993e36d 100644 --- a/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1Intel.cs +++ b/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1Intel.cs @@ -20,7 +20,7 @@ public OneXPlayerX1Intel() DeviceDefault = true, OSPowerMode = OSPowerMode.BetterBattery, CPUBoostLevel = CPUBoostLevel.Disabled, - Guid = new("961cc777-2547-4f9d-8174-7d86181b8a7a"), + Guid = BetterBatteryGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 15.0d, 15.0d, 15.0d } }); @@ -32,7 +32,7 @@ public OneXPlayerX1Intel() DeviceDefault = true, OSPowerMode = OSPowerMode.BetterPerformance, CPUBoostLevel = CPUBoostLevel.Enabled, - Guid = new("3af9B8d9-7c97-431d-ad78-34a8bfea439f"), + Guid = BetterPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 30.0d, 30.0d, 30.0d } }); @@ -44,7 +44,7 @@ public OneXPlayerX1Intel() DeviceDefault = true, OSPowerMode = OSPowerMode.BestPerformance, CPUBoostLevel = CPUBoostLevel.Enabled, - Guid = new("ded574b5-45a0-4f42-8737-46345c09c238"), + Guid = BestPerformanceGuid, TDPOverrideEnabled = true, TDPOverrideValues = new[] { 35.0d, 35.0d, 64.0d }, EPPOverrideEnabled = true, diff --git a/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1Mini.cs b/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1Mini.cs index 61dd57882..8d8bf86ea 100644 --- a/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1Mini.cs +++ b/HandheldCompanion/Devices/OneXPlayer/OneXPlayerX1Mini.cs @@ -9,5 +9,7 @@ public OneXPlayerX1Mini() cTDP = new double[] { 15, 30 }; GfxClock = new double[] { 100, 2700 }; CpuClock = 5100; + + EnableSerialPort = false; } } diff --git a/HandheldCompanion/HandheldCompanion.csproj b/HandheldCompanion/HandheldCompanion.csproj index 5c432154c..3ab4ad427 100644 --- a/HandheldCompanion/HandheldCompanion.csproj +++ b/HandheldCompanion/HandheldCompanion.csproj @@ -1,4 +1,4 @@ - + WinExe @@ -12,7 +12,7 @@ HandheldCompanion.App $(SolutionDir)bin\$(Configuration) Resources\icon.ico - 0.21.6.0 + 0.21.6.1 app.manifest AnyCPU;x64;x86 true @@ -81,6 +81,7 @@ + @@ -179,6 +180,7 @@ + @@ -201,7 +203,7 @@ - + @@ -210,17 +212,17 @@ - - + + - - - + + + - + diff --git a/HandheldCompanion/Managers/ControllerManager.cs b/HandheldCompanion/Managers/ControllerManager.cs index 4251e1d32..5c478f57a 100644 --- a/HandheldCompanion/Managers/ControllerManager.cs +++ b/HandheldCompanion/Managers/ControllerManager.cs @@ -10,12 +10,13 @@ using Nefarius.Utilities.DeviceManagement.Drivers; using Nefarius.Utilities.DeviceManagement.Extensions; using Nefarius.Utilities.DeviceManagement.PnP; +using Newtonsoft.Json; using SharpDX.DirectInput; using SharpDX.XInput; using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Collections.Specialized; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -79,6 +80,9 @@ static ControllerManager() public static Task Start() { + // get driver store + DriversStore = DeserializeDriverStore(); + // Flushing possible JoyShocks... JslDisconnectAndDisposeAll(); @@ -91,8 +95,10 @@ public static Task Start() SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; + /* UIGamepad.GotFocus += GamepadFocusManager_GotFocus; UIGamepad.LostFocus += GamepadFocusManager_LostFocus; + */ ProcessManager.ForegroundChanged += ProcessManager_ForegroundChanged; @@ -167,6 +173,7 @@ private enum FocusedWindow Quicktools } + /* private static void GamepadFocusManager_LostFocus(string Name) { switch (Name) @@ -200,6 +207,7 @@ private static void GamepadFocusManager_GotFocus(string Name) // check applicable scenarios CheckControllerScenario(); } + */ private static void ProcessManager_ForegroundChanged(ProcessEx? processEx, ProcessEx? backgroundEx) { @@ -273,10 +281,11 @@ private static void ScenarioTimer_Elapsed(object? sender, ElapsedEventArgs e) } } + /* // either main window or quicktools are focused - // set flag if (focusedWindows != FocusedWindow.None) ControllerMuted = true; + */ } private static void CheckControllerScenario() @@ -717,9 +726,7 @@ private static void watchdogThreadLoop(object? obj) if (ControllerManagementAttempts == ControllerManagementMaxAttempts) { // resume all physical controllers - StringCollection deviceInstanceIds = SettingsManager.GetStringCollection("SuspendedControllers"); - if (deviceInstanceIds is not null && deviceInstanceIds.Count != 0) - ResumeControllers(); + ResumeControllers(); UpdateStatus(ControllerManagerStatus.Failed); ControllerManagementAttempts = 0; @@ -760,9 +767,7 @@ private static void watchdogThreadLoop(object? obj) VirtualManager.Resume(false); // resume all physical controllers - StringCollection deviceInstanceIds = SettingsManager.GetStringCollection("SuspendedControllers"); - if (deviceInstanceIds is not null && deviceInstanceIds.Count != 0) - ResumeControllers(); + ResumeControllers(); // suspend and resume virtual controller VirtualManager.Suspend(false); @@ -777,9 +782,7 @@ private static void watchdogThreadLoop(object? obj) else { // resume all physical controllers - StringCollection deviceInstanceIds = SettingsManager.GetStringCollection("SuspendedControllers"); - if (deviceInstanceIds is not null && deviceInstanceIds.Count != 0) - ResumeControllers(); + ResumeControllers(); // give us one extra loop to make sure we're good if (managerStatus != ControllerManagerStatus.Succeeded) @@ -1014,14 +1017,11 @@ public static void SetTargetController(string baseContainerDeviceInstanceId, boo } } + public static string DriversPath = Path.Combine(MainWindow.SettingsPath, "drivers.json"); + public static Dictionary DriversStore = []; + public static bool SuspendController(string baseContainerDeviceInstanceId) { - // PnPUtil.StartPnPUtil(@"/delete-driver C:\Windows\INF\xusb22.inf /uninstall /force"); - StringCollection deviceInstanceIds = SettingsManager.GetStringCollection("SuspendedControllers"); - - if (deviceInstanceIds is null) - deviceInstanceIds = []; - try { PnPDevice pnPDevice = PnPDevice.GetDeviceByInstanceId(baseContainerDeviceInstanceId); @@ -1038,16 +1038,15 @@ public static bool SuspendController(string baseContainerDeviceInstanceId) switch (enumerator) { case "USB": - if (pnPDriver is not null) + if (!string.IsNullOrEmpty(pnPDriver?.InfPath)) { + // store driver to collection + AddOrUpdateDriverStore(baseContainerDeviceInstanceId, pnPDriver.InfPath); + pnPDevice.InstallNullDriver(out bool rebootRequired); usbPnPDevice.CyclePort(); } - if (!deviceInstanceIds.Contains(baseContainerDeviceInstanceId)) - deviceInstanceIds.Add(baseContainerDeviceInstanceId); - - SettingsManager.SetProperty("SuspendedControllers", deviceInstanceIds); PowerCyclers[baseContainerDeviceInstanceId] = true; return true; } @@ -1059,20 +1058,16 @@ public static bool SuspendController(string baseContainerDeviceInstanceId) public static bool ResumeControllers() { - // PnPUtil.StartPnPUtil(@"/add-driver C:\Windows\INF\xusb22.inf /install"); - StringCollection deviceInstanceIds = SettingsManager.GetStringCollection("SuspendedControllers"); - - if (deviceInstanceIds is null || deviceInstanceIds.Count == 0) - return true; - - foreach (string baseContainerDeviceInstanceId in deviceInstanceIds) + // loop through controllers + foreach (string baseContainerDeviceInstanceId in DriversStore.Keys) { try { PnPDevice pnPDevice = PnPDevice.GetDeviceByInstanceId(baseContainerDeviceInstanceId); UsbPnPDevice usbPnPDevice = pnPDevice.ToUsbPnPDevice(); - DriverMeta pnPDriver = null; + // get current driver + DriverMeta pnPDriver = null; try { pnPDriver = pnPDevice.GetCurrentDriver(); @@ -1083,18 +1078,21 @@ public static bool ResumeControllers() switch (enumerator) { case "USB": - if (pnPDriver is null || pnPDriver.InfPath != "xusb22.inf") { - pnPDevice.RemoveAndSetup(); - pnPDevice.InstallCustomDriver("xusb22.inf", out bool rebootRequired); - } + // todo: check PnPDevice PID/VID to deploy the appropriate inf + string InfPath = GetDriverFromDriverStore(baseContainerDeviceInstanceId); + if (pnPDriver?.InfPath != InfPath && !string.IsNullOrEmpty(InfPath)) + { + pnPDevice.RemoveAndSetup(); + pnPDevice.InstallCustomDriver(InfPath, out bool rebootRequired); + } - if (deviceInstanceIds.Contains(baseContainerDeviceInstanceId)) - deviceInstanceIds.Remove(baseContainerDeviceInstanceId); + // remove device from store + RemoveFromDriverStore(baseContainerDeviceInstanceId); - SettingsManager.SetProperty("SuspendedControllers", deviceInstanceIds); - PowerCyclers.TryRemove(baseContainerDeviceInstanceId, out _); - return true; + PowerCyclers.TryRemove(baseContainerDeviceInstanceId, out _); + return true; + } } } catch { } @@ -1103,6 +1101,53 @@ public static bool ResumeControllers() return false; } + private static void SerializeDriverStore() + { + string json = JsonConvert.SerializeObject(DriversStore, Formatting.Indented); + File.WriteAllText(DriversPath, json); + } + + private static Dictionary DeserializeDriverStore() + { + if (!File.Exists(DriversPath)) + return []; + + string json = File.ReadAllText(DriversPath); + return JsonConvert.DeserializeObject>(json); + } + + private static string GetDriverFromDriverStore(string path) + { + if (DriversStore.TryGetValue(path, out string driver)) + return driver; + + return "xusb22.inf"; + } + + private static void AddOrUpdateDriverStore(string path, string calibration) + { + // upcase + path = path.ToUpper(); + + // update array + DriversStore[path] = calibration; + + // serialize store + SerializeDriverStore(); + } + + private static void RemoveFromDriverStore(string path) + { + // upcase + path = path.ToUpper(); + + // update array + DriversStore.Remove(path); + + // serialize store + SerializeDriverStore(); + } + public static IController GetTargetController() { return targetController; @@ -1172,6 +1217,7 @@ private static void UpdateInputs(ControllerState controllerState, GamepadMotion { // compute layout controllerState = LayoutManager.MapController(controllerState); + InputsUpdated2?.Invoke(controllerState); } VirtualManager.UpdateInputs(controllerState, gamepadMotion); @@ -1213,9 +1259,20 @@ internal static IController GetEmulatedController() public static event ControllerSelectedEventHandler ControllerSelected; public delegate void ControllerSelectedEventHandler(IController Controller); + /// + /// Controller state has changed, before layout manager + /// + /// The updated controller state. public static event InputsUpdatedEventHandler InputsUpdated; public delegate void InputsUpdatedEventHandler(ControllerState Inputs); + /// + /// Controller state has changed, after layout manager + /// + /// The updated controller state. + public static event InputsUpdated2EventHandler InputsUpdated2; + public delegate void InputsUpdated2EventHandler(ControllerState Inputs); + public static event StatusChangedEventHandler StatusChanged; public delegate void StatusChangedEventHandler(ControllerManagerStatus status, int attempts); diff --git a/HandheldCompanion/Managers/DeviceManager.cs b/HandheldCompanion/Managers/DeviceManager.cs index 6d15ab843..34b0414e4 100644 --- a/HandheldCompanion/Managers/DeviceManager.cs +++ b/HandheldCompanion/Managers/DeviceManager.cs @@ -78,8 +78,9 @@ static DeviceManager() public static void Start() { - // fail-safe - PnPUtil.StartPnPUtil(@"/add-driver C:\Windows\INF\xusb22.inf /install"); + // fail-safe: restore drivers from incomplete controller suspend/resume process (if any) + foreach (string InfPath in ControllerManager.DriversStore.Values) + PnPUtil.StartPnPUtil($@"/add-driver C:\Windows\INF\{InfPath} /install"); UsbDeviceListener.StartListen(DeviceInterfaceIds.UsbDevice); UsbDeviceListener.DeviceArrived += UsbDevice_DeviceArrived; @@ -122,8 +123,9 @@ public static void Stop() HidDeviceListener.DeviceArrived -= HidDevice_DeviceArrived; HidDeviceListener.DeviceRemoved -= HidDevice_DeviceRemoved; - // fail-safe - PnPUtil.StartPnPUtil(@"/add-driver C:\Windows\INF\xusb22.inf /install"); + // fail-safe: restore drivers from incomplete controller suspend/resume process (if any) + foreach (string InfPath in ControllerManager.DriversStore.Values) + PnPUtil.StartPnPUtil($@"/add-driver C:\Windows\INF\{InfPath} /install"); LogManager.LogInformation("{0} has stopped", "DeviceManager"); } diff --git a/HandheldCompanion/Managers/InputsManager.cs b/HandheldCompanion/Managers/InputsManager.cs index 0462e3aa4..b72e5adbd 100644 --- a/HandheldCompanion/Managers/InputsManager.cs +++ b/HandheldCompanion/Managers/InputsManager.cs @@ -442,7 +442,13 @@ private static void M_GlobalHook_KeyEvent(object? sender, KeyEventArgs e) switch (args.KeyValue) { case 165: + // KeyboardSimulator.KeyUp((VirtualKeyCode)KeyCode.RMenu); + KeyboardSimulator.KeyUp((VirtualKeyCode)KeyCode.LMenu); KeyboardSimulator.KeyUp((VirtualKeyCode)KeyCode.LControl); + KeyboardSimulator.KeyUp((VirtualKeyCode)KeyCode.RControl); + KeyboardSimulator.KeyUp((VirtualKeyCode)KeyCode.Alt); + KeyboardSimulator.KeyUp((VirtualKeyCode)KeyCode.LAlt); + // KeyboardSimulator.KeyUp((VirtualKeyCode)KeyCode.RAlt); break; } } diff --git a/HandheldCompanion/Managers/PerformanceManager.cs b/HandheldCompanion/Managers/PerformanceManager.cs index ac83597fe..b9aaf243b 100644 --- a/HandheldCompanion/Managers/PerformanceManager.cs +++ b/HandheldCompanion/Managers/PerformanceManager.cs @@ -17,7 +17,7 @@ public static class OSPowerMode /// /// Better Battery mode. /// - public static Guid BetterBattery = new("961cc777-2547-4f9d-8174-7d86181b8a7a"); + public static Guid BetterBattery = IDevice.BetterBatteryGuid; /// /// Better Performance mode. @@ -28,7 +28,7 @@ public static class OSPowerMode /// /// Best Performance mode. /// - public static Guid BestPerformance = new("ded574b5-45a0-4f42-8737-46345c09c238"); + public static Guid BestPerformance = IDevice.BestPerformanceGuid; } public enum CPUBoostLevel diff --git a/HandheldCompanion/Managers/ProcessManager.cs b/HandheldCompanion/Managers/ProcessManager.cs index c8b619a22..38f24147c 100644 --- a/HandheldCompanion/Managers/ProcessManager.cs +++ b/HandheldCompanion/Managers/ProcessManager.cs @@ -306,10 +306,8 @@ private static void ProcessHalted(object? sender, EventArgs e) ForegroundChanged?.Invoke(null, foregroundProcess); } - bool success = Processes.TryRemove(new KeyValuePair(processId, processEx)); - // raise event - if (success) + if (Processes.TryRemove(processId, out _)) { ProcessStopped?.Invoke(processEx); diff --git a/HandheldCompanion/Managers/VirtualManager.cs b/HandheldCompanion/Managers/VirtualManager.cs index 417c2ed6d..4f383b3a1 100644 --- a/HandheldCompanion/Managers/VirtualManager.cs +++ b/HandheldCompanion/Managers/VirtualManager.cs @@ -111,24 +111,19 @@ public static void Resume(bool OS) // update DSU status SetDSUStatus(SettingsManager.GetBoolean("DSUEnabled")); } - - // set controller mode - SetControllerMode(HIDmode); } + + // set controller mode + SetControllerMode(HIDmode); } public static void Suspend(bool OS) { + // dispose virtual controller + SetControllerMode(HIDmode.NoController); + lock (threadLock) { - // dispose virtual controller - if (vTarget is not null) - { - vTarget.Disconnect(); - vTarget.Dispose(); - vTarget = null; - } - if (OS) { // dispose ViGEm drivers @@ -247,12 +242,7 @@ public static void SetControllerMode(HIDmode mode) { default: case HIDmode.NoController: - if (vTarget is not null) - { - vTarget.Disconnect(); - vTarget.Dispose(); - vTarget = null; - } + // controller was disposed already above break; case HIDmode.DualShock4Controller: diff --git a/HandheldCompanion/Properties/Settings.Designer.cs b/HandheldCompanion/Properties/Settings.Designer.cs index ecfe53096..ce0a6666b 100644 --- a/HandheldCompanion/Properties/Settings.Designer.cs +++ b/HandheldCompanion/Properties/Settings.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -7,15 +7,16 @@ // the code is regenerated. // //------------------------------------------------------------------------------ + using System.Configuration; -namespace HandheldCompanion.Properties -{ +namespace HandheldCompanion.Properties { [SettingsProvider(typeof(CustomSettingsProvider))] internal sealed partial class Settings : ApplicationSettingsBase { + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings Default { @@ -732,17 +733,6 @@ public bool ControllerManagement { } } - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public global::System.Collections.Specialized.StringCollection SuspendedControllers { - get { - return ((global::System.Collections.Specialized.StringCollection)(this["SuspendedControllers"])); - } - set { - this["SuspendedControllers"] = value; - } - } - [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] @@ -935,17 +925,6 @@ public int LEDPresetIndex { } } - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public global::System.Collections.Specialized.StringCollection SuspendedDevices { - get { - return ((global::System.Collections.Specialized.StringCollection)(this["SuspendedDevices"])); - } - set { - this["SuspendedDevices"] = value; - } - } - [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] diff --git a/HandheldCompanion/Properties/Settings.settings b/HandheldCompanion/Properties/Settings.settings index 73fbc98ec..9228258d2 100644 --- a/HandheldCompanion/Properties/Settings.settings +++ b/HandheldCompanion/Properties/Settings.settings @@ -179,9 +179,6 @@ True - - - False @@ -230,9 +227,6 @@ 0 - - - False diff --git a/HandheldCompanion/Resources/DeviceImages/device_rog_ally_x.png b/HandheldCompanion/Resources/DeviceImages/device_rog_ally_x.png new file mode 100644 index 0000000000000000000000000000000000000000..91cf3ce9a526ac68ed83bf279839fca3a1f3fd4f GIT binary patch literal 11850 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 Ef;M)tasU7T literal 0 HcmV?d00001 diff --git a/HandheldCompanion/UI/UIGamepad.cs b/HandheldCompanion/UI/UIGamepad.cs index adfdf1630..1abc9e622 100644 --- a/HandheldCompanion/UI/UIGamepad.cs +++ b/HandheldCompanion/UI/UIGamepad.cs @@ -96,7 +96,7 @@ public UIGamepad(GamepadWindow gamepadWindow, Frame contentFrame) tooltipTimer = new Timer(2000) { AutoReset = false }; tooltipTimer.Elapsed += TooltipTimer_Elapsed; - ControllerManager.InputsUpdated += InputsUpdated; + ControllerManager.InputsUpdated2 += InputsUpdated; } private void _currentWindow_ContentDialogClosed(ContentDialog contentDialog) @@ -618,7 +618,7 @@ private void InputsUpdated(ControllerState controllerState) // get the associated ComboBox comboBox = ItemsControl.ItemsControlFromItemContainer(focusedElement) as ComboBox; - if (comboBox.IsDropDownOpen) + if (comboBox.IsDropDownOpen && comboBoxItem.IsEnabled) { int idx = comboBox.Items.IndexOf(comboBoxItem); if (idx == -1) @@ -880,22 +880,39 @@ private void InputsUpdated(ControllerState controllerState) if (idx == -1) idx = comboBox.Items.IndexOf(comboBoxItem.Content); - switch (direction) + while (true) // Loop to skip disabled items { - case WPFUtils.Direction.Up: - idx--; - break; + switch (direction) + { + case WPFUtils.Direction.Up: + idx--; + break; - case WPFUtils.Direction.Down: - idx++; + case WPFUtils.Direction.Down: + idx++; + break; + } + + // Ensure index is within bounds + if (idx < 0 || idx >= comboBox.Items.Count) + { + // We've reached the top or bottom, so stop the loop break; - } + } - // Get the ComboBoxItem - idx = Math.Max(0, Math.Min(comboBox.Items.Count - 1, idx)); + // Get the ComboBoxItem at the new index + focusedElement = (ComboBoxItem)comboBox.ItemContainerGenerator.ContainerFromIndex(idx); - focusedElement = (ComboBoxItem)comboBox.ItemContainerGenerator.ContainerFromIndex(idx); - Focus(focusedElement, comboBox, true); + // Check if the focused element is enabled + if (focusedElement != null && focusedElement.IsEnabled) + { + // If the element is enabled, focus it and break out of the loop + Focus(focusedElement, comboBox, true); + break; + } + + // If the element is not enabled, continue to the next item in the loop + } } return; } diff --git a/HandheldCompanion/Utils/DeviceUtils.cs b/HandheldCompanion/Utils/DeviceUtils.cs index e3779932a..327fa18da 100644 --- a/HandheldCompanion/Utils/DeviceUtils.cs +++ b/HandheldCompanion/Utils/DeviceUtils.cs @@ -57,21 +57,17 @@ public static USBDeviceInfo GetUSBDevice(string DeviceId) public static List GetSerialDevices() { - var serials = new List(); + List serials = new List(); try { - using (var searcher = - new ManagementObjectSearcher( - "SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%COM%' AND PNPClass = 'Ports'")) + using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%COM%' AND PNPClass = 'Ports'")) { - var devices = searcher.Get().Cast().ToList(); - foreach (var device in devices) + List devices = searcher.Get().Cast().ToList(); + foreach (ManagementBaseObject device in devices) serials.Add(new USBDeviceInfo(device)); } } - catch - { - } + catch { } return serials; } diff --git a/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs b/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs index 4efdca2ef..f5214f897 100644 --- a/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs +++ b/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs @@ -935,7 +935,7 @@ private void Button_PowerSettings_Create_Click(object sender, RoutedEventArgs e) }; PowerProfileManager.UpdateOrCreateProfile(powerProfile, UpdateSource.Creation); - + // localize me new Dialog(OverlayQuickTools.GetCurrent()) { diff --git a/HandheldCompanion/Views/SplashScreen.xaml b/HandheldCompanion/Views/SplashScreen.xaml index 5209f700a..64bd50c85 100644 --- a/HandheldCompanion/Views/SplashScreen.xaml +++ b/HandheldCompanion/Views/SplashScreen.xaml @@ -4,9 +4,10 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:common="clr-namespace:HandheldCompanion.Views.Classes" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:resx="clr-namespace:HandheldCompanion.Properties" - xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf" + xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" Width="450" Height="450" ui:ThemeManager.IsThemeAware="True" @@ -22,19 +23,13 @@ Margin="0,0,0,32" HorizontalAlignment="Center" VerticalAlignment="Center"> - - - - + + diff --git a/HandheldCompanion/Views/Windows/MainWindow.xaml.cs b/HandheldCompanion/Views/Windows/MainWindow.xaml.cs index 9a589f58d..9f1423b4e 100644 --- a/HandheldCompanion/Views/Windows/MainWindow.xaml.cs +++ b/HandheldCompanion/Views/Windows/MainWindow.xaml.cs @@ -24,7 +24,6 @@ using System.Windows.Input; using System.Windows.Interop; using System.Windows.Navigation; -using System.Windows.Threading; using Windows.UI.ViewManagement; using Application = System.Windows.Application; using Control = System.Windows.Controls.Control; @@ -99,8 +98,6 @@ public MainWindow(FileVersionInfo _fileVersionInfo, Assembly CurrentAssembly) #endif } - SplashScreen.LoadingSequence.Text = "Preparing UI..."; - InitializeComponent(); this.Tag = "MainWindow"; @@ -160,7 +157,6 @@ public MainWindow(FileVersionInfo _fileVersionInfo, Assembly CurrentAssembly) Title += $" ({fileVersionInfo.FileVersion})"; // initialize device - SplashScreen.LoadingSequence.Text = "Initializing device..."; CurrentDevice = IDevice.GetCurrent(); CurrentDevice.PullSensors(); @@ -184,18 +180,10 @@ public MainWindow(FileVersionInfo _fileVersionInfo, Assembly CurrentAssembly) UISounds uiSounds = new UISounds(); // load window(s) - SplashScreen.LoadingSequence.Text = "Drawing windows..."; - Dispatcher.Invoke(new Action(() => - { - loadWindows(); - }), DispatcherPriority.Background); // Lower priority + loadWindows(); // load page(s) - SplashScreen.LoadingSequence.Text = "Drawing pages..."; - Dispatcher.Invoke(new Action(() => - { - loadPages(); - }), DispatcherPriority.Background); // Lower priority + loadPages(); // manage events SystemManager.SystemStatusChanged += OnSystemStatusChanged; @@ -206,8 +194,7 @@ public MainWindow(FileVersionInfo _fileVersionInfo, Assembly CurrentAssembly) ToastManager.Start(); ToastManager.IsEnabled = SettingsManager.GetBoolean("ToastEnable"); - // start static managers in sequence - SplashScreen.LoadingSequence.Text = "Initializing managers..."; + // start static managers in sequence GPUManager.Start(); PowerProfileManager.Start(); ProfileManager.Start(); @@ -574,6 +561,9 @@ private async void OnSystemStatusChanged(SystemManager.SystemStatus status, Syst // close current device CurrentDevice.Close(); + // free memory + GC.Collect(); + // Allow system to sleep SystemManager.SetThreadExecutionState(SystemManager.ES_CONTINUOUS); LogManager.LogDebug("Tasks completed. System can now suspend if needed.");