diff --git a/HandheldCompanion.iss b/HandheldCompanion.iss index 963a15025..3525802ac 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.20.5.6' +#define MyAppVersion '0.21.0.1' #define MyAppPublisher 'BenjaminLSR' #define MyAppCopyright 'Copyright @ BenjaminLSR' #define MyAppURL 'https://github.com/Valkirie/HandheldCompanion' @@ -49,7 +49,8 @@ #define NewDirectXVersion "9.29.1974" #define NewViGemVersion "1.22.0.0" #define NewHidHideVersion "1.5.212" -#define NewRtssVersion "7.3.6" +; RTSS 7.3.6 +#define NewRtssVersion "7.3.5.28010" //#define DotNetX64DownloadLink "https://download.visualstudio.microsoft.com/download/pr/b280d97f-25a9-4ab7-8a12-8291aa3af117/a37ed0e68f51fcd973e9f6cb4f40b1a7/windowsdesktop-runtime-8.0.0-win-x64.exe" //#define DotNetX86DownloadLink "https://download.visualstudio.microsoft.com/download/pr/f9e3b581-059d-429f-9f0d-1d1167ff7e32/bd7661030cd5d66cd3eee0fd20b24540/windowsdesktop-runtime-8.0.0-win-x86.exe" @@ -724,11 +725,11 @@ end; procedure Dependency_AddRTSS; begin - Dependency_Add_With_Version('RTSSSetup735.exe', '{#NewRtssVersion}', regGetInstalledVersion('{#RtssName}'), + Dependency_Add_With_Version('RTSSSetup736.exe', '{#NewRtssVersion}', regGetInstalledVersion('{#RtssName}'), '/S', '{#RtssName}', '{#RtssDownloadLink}', - '', True, False); + '', True, True); stopProcess('{#EncoderServer64Exe}'); stopProcess('{#RTSSHooksLoader64Exe}'); diff --git a/HandheldCompanion/ADLX_Wrapper.dll b/HandheldCompanion/ADLX_Wrapper.dll index 469cc74a4..955ff1a2b 100644 Binary files a/HandheldCompanion/ADLX_Wrapper.dll and b/HandheldCompanion/ADLX_Wrapper.dll differ diff --git a/HandheldCompanion/Controllers/LegionController.cs b/HandheldCompanion/Controllers/LegionController.cs index 961b97c8c..292f02b32 100644 --- a/HandheldCompanion/Controllers/LegionController.cs +++ b/HandheldCompanion/Controllers/LegionController.cs @@ -331,7 +331,7 @@ public override void UpdateInputs(long ticks, float delta, bool commit) base.UpdateInputs(ticks, delta); break; case LegionGo.RightJoyconIndex: - gamepadMotion.ProcessMotion(gX, gY, gZ, aX, aY, aZ, delta); + gamepadMotionR.ProcessMotion(gX, gY, gZ, aX, aY, aZ, delta); base.UpdateInputs(ticks, delta, gamepadMotionR); break; } diff --git a/HandheldCompanion/Devices/IDevice.cs b/HandheldCompanion/Devices/IDevice.cs index ddd6934cb..37b62377f 100644 --- a/HandheldCompanion/Devices/IDevice.cs +++ b/HandheldCompanion/Devices/IDevice.cs @@ -64,7 +64,7 @@ public abstract class IDevice public delegate void PowerStatusChangedEventHandler(IDevice device); protected static OpenLibSys openLibSys; - protected LockObject updateLock = new(); + protected object updateLock = new(); private static IDevice device; @@ -829,11 +829,6 @@ protected bool SuspendDevice(string InterfaceId) return false; } - protected void PowerStatusChange(IDevice device) - { - PowerStatusChanged?.Invoke(device); - } - public static IEnumerable GetHidDevices(int vendorId, int deviceId, int minFeatures = 1) { HidDevice[] HidDeviceList = HidDevices.Enumerate(vendorId, new int[] { deviceId }).ToArray(); diff --git a/HandheldCompanion/HandheldCompanion.csproj b/HandheldCompanion/HandheldCompanion.csproj index 8d2ec9041..63d535ae3 100644 --- a/HandheldCompanion/HandheldCompanion.csproj +++ b/HandheldCompanion/HandheldCompanion.csproj @@ -12,7 +12,7 @@ HandheldCompanion.App $(SolutionDir)bin\$(Configuration) Resources\icon.ico - 0.20.5.6 + 0.21.0.1 app.manifest AnyCPU;x64;x86 true @@ -150,11 +150,10 @@ - - + diff --git a/HandheldCompanion/Managers/PerformanceManager.cs b/HandheldCompanion/Managers/PerformanceManager.cs index ac855009f..3935e886d 100644 --- a/HandheldCompanion/Managers/PerformanceManager.cs +++ b/HandheldCompanion/Managers/PerformanceManager.cs @@ -570,7 +570,10 @@ private static async void cpuWatchdog_Elapsed(object? sender, ElapsedEventArgs e // only request an update if current limit is different than stored if (ReadTDP != TDP) + { processor.SetTDPLimit(type, TDP); + CurrentTDP[idx] = TDP; + } await Task.Delay(20); } @@ -727,28 +730,18 @@ private static void RequestTDP(PowerType type, double value, bool immediate = fa // immediately apply if (immediate) + { processor.SetTDPLimit((PowerType)idx, value, immediate); + CurrentTDP[idx] = value; + } } private static async void RequestTDP(double[] values, bool immediate = false) { - if (processor is null || !processor.IsInitialized) - return; - for (int idx = (int)PowerType.Slow; idx <= (int)PowerType.Fast; idx++) { - // make sure we're not trying to run below or above specs - values[idx] = Math.Min(TDPMax, Math.Max(TDPMin, values[idx])); - - // update value read by timer - StoredTDP[idx] = values[idx]; - - // immediately apply - if (immediate) - { - processor.SetTDPLimit((PowerType)idx, values[idx], immediate); - await Task.Delay(20); - } + RequestTDP((PowerType)idx, values[idx], immediate); + await Task.Delay(20); } } @@ -874,18 +867,15 @@ public static void Start() // initialize processor processor = Processor.GetCurrent(); - if (processor.IsInitialized) + if (processor is not null && processor.IsInitialized) { processor.StatusChanged += Processor_StatusChanged; processor.Initialize(); } - - // deprecated - /* - processor.ValueChanged += Processor_ValueChanged; - processor.LimitChanged += Processor_LimitChanged; - processor.MiscChanged += Processor_MiscChanged; - */ + else + { + ProcessorStatusChanged?.Invoke(false, false); + } IsInitialized = true; Initialized?.Invoke(); diff --git a/HandheldCompanion/Managers/ProcessManager.cs b/HandheldCompanion/Managers/ProcessManager.cs index b910daaaf..fdb10c136 100644 --- a/HandheldCompanion/Managers/ProcessManager.cs +++ b/HandheldCompanion/Managers/ProcessManager.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Automation; @@ -88,7 +89,8 @@ static ProcessManager() private static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { - ForegroundCallback(); + // avoid locking UI thread + new Thread(() => { ForegroundCallback(); }).Start(); } private static void OnWindowOpened(object sender, AutomationEventArgs automationEventArgs) diff --git a/HandheldCompanion/Managers/VirtualManager.cs b/HandheldCompanion/Managers/VirtualManager.cs index 5d5351346..7d0508467 100644 --- a/HandheldCompanion/Managers/VirtualManager.cs +++ b/HandheldCompanion/Managers/VirtualManager.cs @@ -6,7 +6,9 @@ using Nefarius.ViGEm.Client; using System; using System.Threading; +using System.Threading.Tasks; using System.Windows; +using static HandheldCompanion.Managers.ControllerManager; namespace HandheldCompanion.Managers { @@ -26,7 +28,7 @@ public static class VirtualManager public static ushort ProductId = 0x28E; // Xbox 360 public static ushort VendorId = 0x45E; // Microsoft public static ushort FakeVendorId = 0x76B; // HC - private static CrossThreadLock threadLock = new CrossThreadLock(); + private static object threadLock = new(); public static bool IsInitialized; @@ -144,12 +146,15 @@ private static void SettingsManager_SettingValueChanged(string name, object valu } } - private static void ProfileManager_Applied(Profile profile, UpdateSource source) + private static async void ProfileManager_Applied(Profile profile, UpdateSource source) { // SetControllerMode takes care of ignoring identical mode switching if (HIDmode == profile.HID || profile.HID == HIDmode.NotSelected) return; + while (ControllerManager.managerStatus == ControllerManagerStatus.Busy) + await Task.Delay(1000); + switch (profile.HID) { case HIDmode.Xbox360Controller: @@ -161,8 +166,11 @@ private static void ProfileManager_Applied(Profile profile, UpdateSource source) } } - private static void ProfileManager_Discarded(Profile profile) + private static async void ProfileManager_Discarded(Profile profile) { + while (ControllerManager.managerStatus == ControllerManagerStatus.Busy) + await Task.Delay(1000); + // restore default HID mode if (profile.HID != HIDmode.NotSelected) SetControllerMode(defaultHIDmode); @@ -178,76 +186,67 @@ private static void SetDSUStatus(bool started) public static void SetControllerMode(HIDmode mode) { - if (!threadLock.TryEnter(3000)) - return; - - // do not disconnect if similar to previous mode and connected - if (HIDmode == mode) + lock (threadLock) { - if (HIDstatus == HIDstatus.Disconnected) + // do not disconnect if similar to previous mode and connected + if (HIDmode == mode) { - threadLock.Exit(); - return; + if (HIDstatus == HIDstatus.Disconnected) + return; + else if (vTarget is not null && vTarget.IsConnected) + return; } - else if (vTarget is not null && vTarget.IsConnected) + + // disconnect current virtual controller + if (vTarget is not null) { - threadLock.Exit(); - return; + vTarget.Disconnect(); + vTarget.Dispose(); + vTarget = null; } - } - - // disconnect current virtual controller - if (vTarget is not null) - { - vTarget.Disconnect(); - vTarget.Dispose(); - vTarget = null; - } - - switch (mode) - { - default: - case HIDmode.NoController: - if (vTarget is not null) - { - vTarget.Disconnect(); - vTarget.Dispose(); - vTarget = null; - } - break; - case HIDmode.DualShock4Controller: - vTarget = new DualShock4Target(); - break; + switch (mode) + { + default: + case HIDmode.NoController: + if (vTarget is not null) + { + vTarget.Disconnect(); + vTarget.Dispose(); + vTarget = null; + } + break; - case HIDmode.Xbox360Controller: - // Generate a new random ProductId to help the controller pick empty slot rather than getting its previous one - VendorId = (ushort)new Random().Next(ushort.MinValue, ushort.MaxValue); - ProductId = (ushort)new Random().Next(ushort.MinValue, ushort.MaxValue); - vTarget = new Xbox360Target(VendorId, ProductId); - break; - } + case HIDmode.DualShock4Controller: + vTarget = new DualShock4Target(); + break; - ControllerSelected?.Invoke(mode); + case HIDmode.Xbox360Controller: + // Generate a new random ProductId to help the controller pick empty slot rather than getting its previous one + VendorId = (ushort)new Random().Next(ushort.MinValue, ushort.MaxValue); + ProductId = (ushort)new Random().Next(ushort.MinValue, ushort.MaxValue); + vTarget = new Xbox360Target(VendorId, ProductId); + break; + } - // failed to initialize controller - if (vTarget is null) - { - if (mode != HIDmode.NoController) - LogManager.LogError("Failed to initialise virtual controller with HIDmode: {0}", mode); + ControllerSelected?.Invoke(mode); - threadLock.Exit(); - return; - } + // failed to initialize controller + if (vTarget is null) + { + if (mode != HIDmode.NoController) + LogManager.LogError("Failed to initialise virtual controller with HIDmode: {0}", mode); - vTarget.Connected += OnTargetConnected; - vTarget.Disconnected += OnTargetDisconnected; - vTarget.Vibrated += OnTargetVibrated; + return; + } - // update current HIDmode - HIDmode = mode; + vTarget.Connected += OnTargetConnected; + vTarget.Disconnected += OnTargetDisconnected; + vTarget.Vibrated += OnTargetVibrated; - threadLock.Exit(); + // update current HIDmode + HIDmode = mode; + } // update status SetControllerStatus(HIDstatus); @@ -255,30 +254,25 @@ public static void SetControllerMode(HIDmode mode) public static void SetControllerStatus(HIDstatus status) { - if (!threadLock.TryEnter(3000)) - return; - - if (vTarget is null) - { - threadLock.Exit(); - return; - } - - switch (status) + lock (threadLock) { - default: - case HIDstatus.Connected: - vTarget.Connect(); - break; - case HIDstatus.Disconnected: - vTarget.Disconnect(); - break; - } + if (vTarget is null) + return; - // update current HIDstatus - HIDstatus = status; + switch (status) + { + default: + case HIDstatus.Connected: + vTarget.Connect(); + break; + case HIDstatus.Disconnected: + vTarget.Disconnect(); + break; + } - threadLock.Exit(); + // update current HIDstatus + HIDstatus = status; + } } private static void OnTargetConnected(ViGEmTarget target) diff --git a/HandheldCompanion/Platforms/RTSS.cs b/HandheldCompanion/Platforms/RTSS.cs index 7ad726f3d..d7d8b1178 100644 --- a/HandheldCompanion/Platforms/RTSS.cs +++ b/HandheldCompanion/Platforms/RTSS.cs @@ -215,7 +215,7 @@ private void ProcessManager_ProcessStopped(ProcessEx processEx) private void Watchdog_Elapsed(object? sender, ElapsedEventArgs e) { - if (Monitor.TryEnter(updateLock)) + lock (updateLock) { if (GetTargetFPS() != RequestedFramerate) SetTargetFPS(RequestedFramerate); @@ -231,8 +231,6 @@ private void Watchdog_Elapsed(object? sender, ElapsedEventArgs e) // force "On-Screen Display Support" to On if (GetEnableOSD() != true) SetEnableOSD(true); - - Monitor.Exit(updateLock); } } diff --git a/HandheldCompanion/Properties/Settings.Designer.cs b/HandheldCompanion/Properties/Settings.Designer.cs index a52c3cb3b..fb2960e33 100644 --- a/HandheldCompanion/Properties/Settings.Designer.cs +++ b/HandheldCompanion/Properties/Settings.Designer.cs @@ -17,13 +17,15 @@ namespace HandheldCompanion.Properties internal sealed partial class Settings : ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { + + public static Settings Default + { + get + { return defaultInstance; } } - + [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] @@ -1021,9 +1023,9 @@ public bool UISounds { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("2")] - public string OnScreenDisplayTimeLevel { + public int OnScreenDisplayTimeLevel { get { - return ((string)(this["OnScreenDisplayTimeLevel"])); + return ((int)(this["OnScreenDisplayTimeLevel"])); } set { this["OnScreenDisplayTimeLevel"] = value; @@ -1033,9 +1035,9 @@ public string OnScreenDisplayTimeLevel { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("2")] - public string OnScreenDisplayCPULevel { + public int OnScreenDisplayCPULevel { get { - return ((string)(this["OnScreenDisplayCPULevel"])); + return ((int)(this["OnScreenDisplayCPULevel"])); } set { this["OnScreenDisplayCPULevel"] = value; @@ -1045,9 +1047,9 @@ public string OnScreenDisplayCPULevel { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("2")] - public string OnScreenDisplayRAMLevel { + public int OnScreenDisplayRAMLevel { get { - return ((string)(this["OnScreenDisplayRAMLevel"])); + return ((int)(this["OnScreenDisplayRAMLevel"])); } set { this["OnScreenDisplayRAMLevel"] = value; @@ -1057,9 +1059,9 @@ public string OnScreenDisplayRAMLevel { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("2")] - public string OnScreenDisplayGPULevel { + public int OnScreenDisplayGPULevel { get { - return ((string)(this["OnScreenDisplayGPULevel"])); + return ((int)(this["OnScreenDisplayGPULevel"])); } set { this["OnScreenDisplayGPULevel"] = value; @@ -1069,9 +1071,9 @@ public string OnScreenDisplayGPULevel { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("2")] - public string OnScreenDisplayVRAMLevel { + public int OnScreenDisplayVRAMLevel { get { - return ((string)(this["OnScreenDisplayVRAMLevel"])); + return ((int)(this["OnScreenDisplayVRAMLevel"])); } set { this["OnScreenDisplayVRAMLevel"] = value; @@ -1081,9 +1083,9 @@ public string OnScreenDisplayVRAMLevel { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("2")] - public string OnScreenDisplayBatteryLevel { + public int OnScreenDisplayBatteryLevel { get { - return ((string)(this["OnScreenDisplayBatteryLevel"])); + return ((int)(this["OnScreenDisplayBatteryLevel"])); } set { this["OnScreenDisplayBatteryLevel"] = value; @@ -1093,9 +1095,9 @@ public string OnScreenDisplayBatteryLevel { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("2")] - public string OnScreenDisplayFPSLevel { + public int OnScreenDisplayFPSLevel { get { - return ((string)(this["OnScreenDisplayFPSLevel"])); + return ((int)(this["OnScreenDisplayFPSLevel"])); } set { this["OnScreenDisplayFPSLevel"] = value; diff --git a/HandheldCompanion/Properties/Settings.settings b/HandheldCompanion/Properties/Settings.settings index 947da597b..b2a9e5754 100644 --- a/HandheldCompanion/Properties/Settings.settings +++ b/HandheldCompanion/Properties/Settings.settings @@ -251,25 +251,25 @@ False - + 2 - + 2 - + 2 - + 2 - + 2 - + 2 - + 2 diff --git a/HandheldCompanion/Views/Pages/DevicePage.xaml b/HandheldCompanion/Views/Pages/DevicePage.xaml index fd03df759..927b84d06 100644 --- a/HandheldCompanion/Views/Pages/DevicePage.xaml +++ b/HandheldCompanion/Views/Pages/DevicePage.xaml @@ -139,7 +139,7 @@ Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center" - Maximum="64" + Maximum="75" SpinButtonPlacementMode="Inline" ValueChanged="NumberBox_TDPMax_ValueChanged" /> diff --git a/HandheldCompanion/Views/Pages/OverlayPage.xaml.cs b/HandheldCompanion/Views/Pages/OverlayPage.xaml.cs index b408ae32b..7c88a33f5 100644 --- a/HandheldCompanion/Views/Pages/OverlayPage.xaml.cs +++ b/HandheldCompanion/Views/Pages/OverlayPage.xaml.cs @@ -372,7 +372,7 @@ private void OnScreenDisplayLevel_SelectionChanged(object sender, SelectionChang if (!IsLoaded) return; - SettingsManager.SetProperty("OnScreenDisplayLevel", OnScreenDisplayLevel.SelectedIndex); + SettingsManager.SetProperty("OnScreenDisplayLevel", ((ComboBox)sender).SelectedIndex); } private void ComboBoxOnScreenDisplayTimeLevel_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -380,7 +380,7 @@ private void ComboBoxOnScreenDisplayTimeLevel_SelectionChanged(object sender, Se if (!IsLoaded) return; - SettingsManager.SetProperty("OnScreenDisplayTimeLevel", ComboBoxOnScreenDisplayCPULevel.SelectedIndex); + SettingsManager.SetProperty("OnScreenDisplayTimeLevel", ((ComboBox)sender).SelectedIndex); } @@ -389,7 +389,7 @@ private void ComboBoxOnScreenDisplayFPSLevel_SelectionChanged(object sender, Sel if (!IsLoaded) return; - SettingsManager.SetProperty("OnScreenDisplayFPSLevel", ComboBoxOnScreenDisplayCPULevel.SelectedIndex); + SettingsManager.SetProperty("OnScreenDisplayFPSLevel", ((ComboBox)sender).SelectedIndex); } private void ComboBoxOnScreenDisplayCPULevel_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -397,7 +397,7 @@ private void ComboBoxOnScreenDisplayCPULevel_SelectionChanged(object sender, Sel if (!IsLoaded) return; - SettingsManager.SetProperty("OnScreenDisplayCPULevel", ComboBoxOnScreenDisplayCPULevel.SelectedIndex); + SettingsManager.SetProperty("OnScreenDisplayCPULevel", ((ComboBox)sender).SelectedIndex); } private void ComboBoxOnScreenDisplayRAMLevel_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -405,7 +405,7 @@ private void ComboBoxOnScreenDisplayRAMLevel_SelectionChanged(object sender, Sel if (!IsLoaded) return; - SettingsManager.SetProperty("OnScreenDisplayRAMLevel", ComboBoxOnScreenDisplayRAMLevel.SelectedIndex); + SettingsManager.SetProperty("OnScreenDisplayRAMLevel", ((ComboBox)sender).SelectedIndex); } private void ComboBoxOnScreenDisplayGPULevel_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -413,7 +413,7 @@ private void ComboBoxOnScreenDisplayGPULevel_SelectionChanged(object sender, Sel if (!IsLoaded) return; - SettingsManager.SetProperty("OnScreenDisplayGPULevel", ComboBoxOnScreenDisplayGPULevel.SelectedIndex); + SettingsManager.SetProperty("OnScreenDisplayGPULevel", ((ComboBox)sender).SelectedIndex); } private void ComboBoxOnScreenDisplayVRAMLevel_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -421,7 +421,7 @@ private void ComboBoxOnScreenDisplayVRAMLevel_SelectionChanged(object sender, Se if (!IsLoaded) return; - SettingsManager.SetProperty("OnScreenDisplayVRAMLevel", ComboBoxOnScreenDisplayVRAMLevel.SelectedIndex); + SettingsManager.SetProperty("OnScreenDisplayVRAMLevel", ((ComboBox)sender).SelectedIndex); } private void ComboBoxOnScreenDisplayBATTLevel_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -429,6 +429,6 @@ private void ComboBoxOnScreenDisplayBATTLevel_SelectionChanged(object sender, Se if (!IsLoaded) return; - SettingsManager.SetProperty("OnScreenDisplayBATTLevel", ComboBoxOnScreenDisplayBATTLevel.SelectedIndex); + SettingsManager.SetProperty("OnScreenDisplayBATTLevel", ((ComboBox)sender).SelectedIndex); } } \ No newline at end of file diff --git a/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs b/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs index be807d4a2..9c43061f8 100644 --- a/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs +++ b/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs @@ -159,6 +159,7 @@ private void SettingsManager_SettingValueChanged(string? name, object value) Toggle_QuicktoolsAutoHide.IsOn = Convert.ToBoolean(value); break; case "UISounds": + Toggle_UISounds.IsEnabled = MultimediaManager.HasVolumeSupport(); Toggle_UISounds.IsOn = Convert.ToBoolean(value); break; } diff --git a/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml.cs b/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml.cs index 81f9a4b80..335eaed4c 100644 --- a/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml.cs +++ b/HandheldCompanion/Views/QuickPages/QuickHomePage.xaml.cs @@ -2,6 +2,7 @@ using HandheldCompanion.Utils; using System; using System.Linq; +using System.Threading; using System.Windows; using System.Windows.Controls; using Page = System.Windows.Controls.Page; @@ -13,8 +14,8 @@ namespace HandheldCompanion.Views.QuickPages; /// public partial class QuickHomePage : Page { - private LockObject brightnessLock = new(); - private LockObject volumeLock = new(); + private CrossThreadLock brightnessLock = new(); + private CrossThreadLock volumeLock = new(); public QuickHomePage(string Tag) : this() { @@ -76,46 +77,70 @@ private void QuickButton_Click(object sender, RoutedEventArgs e) private void SystemManager_Initialized() { - // UI thread (async) - Application.Current.Dispatcher.Invoke(() => + if (MultimediaManager.HasBrightnessSupport()) { - if (MultimediaManager.HasBrightnessSupport()) + lock (brightnessLock) { - SliderBrightness.IsEnabled = true; - SliderBrightness.Value = MultimediaManager.GetBrightness(); + // UI thread + Application.Current.Dispatcher.Invoke(() => + { + SliderBrightness.IsEnabled = true; + SliderBrightness.Value = MultimediaManager.GetBrightness(); + }); } + } - if (MultimediaManager.HasVolumeSupport()) + if (MultimediaManager.HasVolumeSupport()) + { + lock (volumeLock) { - SliderVolume.IsEnabled = true; - SliderVolume.Value = MultimediaManager.GetVolume(); - UpdateVolumeIcon((float)SliderVolume.Value); + // UI thread + Application.Current.Dispatcher.Invoke(() => + { + SliderVolume.IsEnabled = true; + SliderVolume.Value = MultimediaManager.GetVolume(); + UpdateVolumeIcon((float)SliderVolume.Value); + }); } - }); + } } private void SystemManager_BrightnessNotification(int brightness) { - using (new ScopedLock(brightnessLock)) + if (brightnessLock.TryEnter()) { - // UI thread - Application.Current.Dispatcher.Invoke(() => + try { - SliderBrightness.Value = brightness; - }); + // UI thread + Application.Current.Dispatcher.Invoke(() => + { + SliderBrightness.Value = brightness; + }); + } + finally + { + brightnessLock.Exit(); + } } } private void SystemManager_VolumeNotification(float volume) { - using (new ScopedLock(volumeLock)) + if (volumeLock.TryEnter()) { - // UI thread - Application.Current.Dispatcher.Invoke(() => + try { - UpdateVolumeIcon(volume); - SliderVolume.Value = Math.Round(volume); - }); + // UI thread + Application.Current.Dispatcher.Invoke(() => + { + UpdateVolumeIcon(volume); + SliderVolume.Value = Math.Round(volume); + }); + } + finally + { + volumeLock.Exit(); + } } } @@ -124,8 +149,8 @@ private void SliderBrightness_ValueChanged(object sender, RoutedPropertyChangedE if (!IsLoaded) return; - // wait until lock is released - if (brightnessLock) + // prevent update loop + if (brightnessLock.IsEntered()) return; MultimediaManager.SetBrightness(SliderBrightness.Value); @@ -136,8 +161,8 @@ private void SliderVolume_ValueChanged(object sender, RoutedPropertyChangedEvent if (!IsLoaded) return; - // wait until lock is released - if (volumeLock) + // prevent update loop + if (volumeLock.IsEntered()) return; MultimediaManager.SetVolume(SliderVolume.Value); diff --git a/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs b/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs index 4ab633bee..6b9307940 100644 --- a/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs +++ b/HandheldCompanion/Views/QuickPages/QuickProfilesPage.xaml.cs @@ -12,12 +12,14 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Timers; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using Page = System.Windows.Controls.Page; using Separator = System.Windows.Controls.Separator; +using Timer = System.Timers.Timer; namespace HandheldCompanion.Views.QuickPages; @@ -31,7 +33,9 @@ public partial class QuickProfilesPage : Page private ProcessEx currentProcess; private Profile selectedProfile; - private LockObject updateLock = new(); + private CrossThreadLock profileLock = new(); + private CrossThreadLock foregroundLock = new(); + private CrossThreadLock graphicLock = new(); private Hotkey GyroHotkey = new(61); private Profile realProfile; @@ -193,14 +197,11 @@ private void GPUManager_Unhooked(GPU GPU) private void OnRSRStateChanged(bool Supported, bool Enabled, int Sharpness) { - using (new ScopedLock(updateLock)) + // UI thread + Application.Current.Dispatcher.Invoke(() => { - // UI thread (async) - Application.Current.Dispatcher.Invoke(() => - { - StackProfileRSR.IsEnabled = Supported; - }); - } + StackProfileRSR.IsEnabled = Supported; + }); } private void OnGPUScalingChanged(bool Supported, bool Enabled, int Mode) @@ -208,26 +209,20 @@ private void OnGPUScalingChanged(bool Supported, bool Enabled, int Mode) // UI thread (async) Application.Current.Dispatcher.Invoke(() => { - using (new ScopedLock(updateLock)) - { - GPUScalingToggle.IsEnabled = Supported; - StackProfileRIS.IsEnabled = Supported; // check if processor is AMD should be enough - StackProfileRSR.IsEnabled = Supported; - StackProfileIS.IsEnabled = Supported; - } + GPUScalingToggle.IsEnabled = Supported; + StackProfileRIS.IsEnabled = Supported; // check if processor is AMD should be enough + StackProfileRSR.IsEnabled = Supported; + StackProfileIS.IsEnabled = Supported; }); } private void OnIntegerScalingChanged(bool Supported, bool Enabled) { - using (new ScopedLock(updateLock)) + // UI thread + Application.Current.Dispatcher.Invoke(() => { - // UI thread (async) - Application.Current.Dispatcher.Invoke(() => - { - StackProfileIS.IsEnabled = Supported; - }); - } + StackProfileIS.IsEnabled = Supported; + }); } private void RTSS_Updated(PlatformStatus status) @@ -411,116 +406,123 @@ private void ProfileManager_Applied(Profile profile, UpdateSource source) return; } - // if an update is pending, execute it and stop timer - if (UpdateTimer.Enabled) - { - UpdateTimer.Stop(); - SubmitProfile(); - } - - // update profile - selectedProfile = profile; - - using (new ScopedLock(updateLock)) + if (profileLock.TryEnter()) { - // UI thread (async) - Application.Current.Dispatcher.Invoke(() => + try { - // update profile name - CurrentProfileName.Text = selectedProfile.Name; - Toggle_ControllerLayout.IsOn = selectedProfile.LayoutEnabled; - Toggle_ControllerLayout.IsEnabled = !selectedProfile.Default; - - // sub profiles - cb_SubProfiles.Items.Clear(); - int selectedIndex = 0; - - if (profile.Default) + // if an update is pending, execute it and stop timer + if (UpdateTimer.Enabled) { - cb_SubProfiles.Items.Add(profile); - cb_SubProfiles.IsEnabled = false; + UpdateTimer.Stop(); + SubmitProfile(); } - else + + // update profile + selectedProfile = profile; + + // UI thread + Application.Current.Dispatcher.Invoke(() => { - Profile mainProfile = ProfileManager.GetProfileForSubProfile(selectedProfile); - Profile[] subProfiles = ProfileManager.GetSubProfilesFromPath(selectedProfile.Path, false); + // update profile name + CurrentProfileName.Text = selectedProfile.Name; + Toggle_ControllerLayout.IsOn = selectedProfile.LayoutEnabled; + Toggle_ControllerLayout.IsEnabled = !selectedProfile.Default; + + // sub profiles + cb_SubProfiles.Items.Clear(); + int selectedIndex = 0; - cb_SubProfiles.Items.Add(mainProfile); - foreach (Profile subProfile in subProfiles) + if (profile.Default) { - cb_SubProfiles.Items.Add(subProfile); - if (subProfile.Guid == selectedProfile.Guid) - selectedIndex = cb_SubProfiles.Items.IndexOf(subProfile); + cb_SubProfiles.Items.Add(profile); + cb_SubProfiles.IsEnabled = false; } - cb_SubProfiles.IsEnabled = true; - } + else + { + Profile mainProfile = ProfileManager.GetProfileForSubProfile(selectedProfile); + Profile[] subProfiles = ProfileManager.GetSubProfilesFromPath(selectedProfile.Path, false); - cb_SubProfiles.SelectedIndex = selectedIndex; + cb_SubProfiles.Items.Add(mainProfile); + foreach (Profile subProfile in subProfiles) + { + cb_SubProfiles.Items.Add(subProfile); + if (subProfile.Guid == selectedProfile.Guid) + selectedIndex = cb_SubProfiles.Items.IndexOf(subProfile); + } + cb_SubProfiles.IsEnabled = true; + } - // power profile - PowerProfile powerProfile = PowerProfileManager.GetProfile(profile.PowerProfile); - powerProfile?.Check(this); + cb_SubProfiles.SelectedIndex = selectedIndex; - // gyro layout - if (!selectedProfile.Layout.GyroLayout.TryGetValue(AxisLayoutFlags.Gyroscope, out IActions currentAction)) - { - // no gyro layout available, mark as disabled - cB_Output.SelectedIndex = (int)MotionOuput.Disabled; - } - else - { - // IActions - GridAntiDeadzone.Visibility = currentAction is AxisActions ? Visibility.Visible : Visibility.Collapsed; - GridGyroWeight.Visibility = currentAction is AxisActions ? Visibility.Visible : Visibility.Collapsed; + // power profile + PowerProfile powerProfile = PowerProfileManager.GetProfile(profile.PowerProfile); + powerProfile?.Check(this); - if (currentAction is AxisActions) + // gyro layout + if (!selectedProfile.Layout.GyroLayout.TryGetValue(AxisLayoutFlags.Gyroscope, out IActions currentAction)) { - cB_Output.SelectedIndex = (int)((AxisActions)currentAction).Axis; - SliderUMCAntiDeadzone.Value = ((AxisActions)currentAction).AxisAntiDeadZone; - Slider_GyroWeight.Value = ((AxisActions)currentAction).gyroWeight; + // no gyro layout available, mark as disabled + cB_Output.SelectedIndex = (int)MotionOuput.Disabled; } - else if (currentAction is MouseActions) + else { - cB_Output.SelectedIndex = (int)((MouseActions)currentAction).MouseType - 1; - } + // IActions + GridAntiDeadzone.Visibility = currentAction is AxisActions ? Visibility.Visible : Visibility.Collapsed; + GridGyroWeight.Visibility = currentAction is AxisActions ? Visibility.Visible : Visibility.Collapsed; - // GyroActions - cB_Input.SelectedIndex = (int)((GyroActions)currentAction).MotionInput; - cB_UMC_MotionDefaultOffOn.SelectedIndex = (int)((GyroActions)currentAction).MotionMode; + if (currentAction is AxisActions) + { + cB_Output.SelectedIndex = (int)((AxisActions)currentAction).Axis; + SliderUMCAntiDeadzone.Value = ((AxisActions)currentAction).AxisAntiDeadZone; + Slider_GyroWeight.Value = ((AxisActions)currentAction).gyroWeight; + } + else if (currentAction is MouseActions) + { + cB_Output.SelectedIndex = (int)((MouseActions)currentAction).MouseType - 1; + } - // todo: move me to layout ? - SliderSensitivityX.Value = selectedProfile.MotionSensivityX; - SliderSensitivityY.Value = selectedProfile.MotionSensivityY; + // GyroActions + cB_Input.SelectedIndex = (int)((GyroActions)currentAction).MotionInput; + cB_UMC_MotionDefaultOffOn.SelectedIndex = (int)((GyroActions)currentAction).MotionMode; - // todo: improve me ? - GyroHotkey.inputsChord.State = ((GyroActions)currentAction).MotionTrigger.Clone() as ButtonState; - GyroHotkey.DrawInput(); - } + // todo: move me to layout ? + SliderSensitivityX.Value = selectedProfile.MotionSensivityX; + SliderSensitivityY.Value = selectedProfile.MotionSensivityY; - // Framerate limit - DesktopScreen? desktopScreen = MultimediaManager.GetDesktopScreen(); - if (desktopScreen is not null) - cB_Framerate.SelectedItem = desktopScreen.GetClosest(selectedProfile.FramerateValue); + // todo: improve me ? + GyroHotkey.inputsChord.State = ((GyroActions)currentAction).MotionTrigger.Clone() as ButtonState; + GyroHotkey.DrawInput(); + } + + // Framerate limit + DesktopScreen? desktopScreen = MultimediaManager.GetDesktopScreen(); + if (desktopScreen is not null) + cB_Framerate.SelectedItem = desktopScreen.GetClosest(selectedProfile.FramerateValue); - // GPU Scaling - GPUScalingToggle.IsOn = selectedProfile.GPUScaling; - GPUScalingComboBox.SelectedIndex = selectedProfile.ScalingMode; + // GPU Scaling + GPUScalingToggle.IsOn = selectedProfile.GPUScaling; + GPUScalingComboBox.SelectedIndex = selectedProfile.ScalingMode; - // RSR - RSRToggle.IsOn = selectedProfile.RSREnabled; - RSRSlider.Value = selectedProfile.RSRSharpness; + // RSR + RSRToggle.IsOn = selectedProfile.RSREnabled; + RSRSlider.Value = selectedProfile.RSRSharpness; - // Integer Scaling - IntegerScalingToggle.IsOn = selectedProfile.IntegerScalingEnabled; - IntegerScalingTypeComboBox.SelectedIndex = selectedProfile.IntegerScalingType; + // Integer Scaling + IntegerScalingToggle.IsOn = selectedProfile.IntegerScalingEnabled; + IntegerScalingTypeComboBox.SelectedIndex = selectedProfile.IntegerScalingType; - if (desktopScreen is not null) - IntegerScalingComboBox.SelectedItem = desktopScreen.screenDividers.FirstOrDefault(d => d.divider == selectedProfile.IntegerScalingDivider); + if (desktopScreen is not null) + IntegerScalingComboBox.SelectedItem = desktopScreen.screenDividers.FirstOrDefault(d => d.divider == selectedProfile.IntegerScalingDivider); - // RIS - RISToggle.IsOn = selectedProfile.RISEnabled; - RISSlider.Value = selectedProfile.RISSharpness; - }); + // RIS + RISToggle.IsOn = selectedProfile.RISEnabled; + RISSlider.Value = selectedProfile.RISSharpness; + }); + } + finally + { + profileLock.Exit(); + } } } @@ -531,41 +533,55 @@ private void ProfileManager_Deleted(Profile profile) ProcessManager_ForegroundChanged(currentProcess, null); } - private void ProcessManager_ForegroundChanged(ProcessEx processEx, ProcessEx backgroundEx) + private void ProfileManager_Deleted(Profile profile) { - // update current process - currentProcess = processEx; - - // update real profile - realProfile = ProfileManager.GetProfileFromPath(processEx.Path, true); + // this shouldn't happen, someone removed the currently applied profile + if (selectedProfile == profile) + ProcessManager_ForegroundChanged(currentProcess, null); + } - using (new ScopedLock(updateLock)) + private void ProcessManager_ForegroundChanged(ProcessEx processEx, ProcessEx backgroundEx) + { + if (foregroundLock.TryEnter()) { - // UI thread (async) - Application.Current.Dispatcher.Invoke(() => + try { - ProfileToggle.IsOn = !realProfile.Default && realProfile.Enabled; - ProfileIcon.Source = processEx.ProcessIcon; + // update current process + currentProcess = processEx; - if (processEx.MainWindowHandle != IntPtr.Zero) - { - // string MainWindowTitle = ProcessUtils.GetWindowTitle(processEx.MainWindowHandle); + // update real profile + realProfile = ProfileManager.GetProfileFromPath(processEx.Path, true); - ProfileToggle.IsEnabled = true; - ProcessName.Text = currentProcess.Executable; - ProcessPath.Text = currentProcess.Path; - SubProfilesBorder.Visibility = Visibility.Visible; - } - else + // UI thread + Application.Current.Dispatcher.Invoke(() => { - ProfileIcon.Source = null; + ProfileToggle.IsOn = !realProfile.Default && realProfile.Enabled; + ProfileIcon.Source = processEx.ProcessIcon; - ProfileToggle.IsEnabled = false; - ProcessName.Text = Properties.Resources.QuickProfilesPage_Waiting; - ProcessPath.Text = string.Empty; - SubProfilesBorder.Visibility = Visibility.Collapsed; - } - }); + if (processEx.MainWindowHandle != IntPtr.Zero) + { + // string MainWindowTitle = ProcessUtils.GetWindowTitle(processEx.MainWindowHandle); + + ProfileToggle.IsEnabled = true; + ProcessName.Text = currentProcess.Executable; + ProcessPath.Text = currentProcess.Path; + SubProfilesBorder.Visibility = Visibility.Visible; + } + else + { + ProfileIcon.Source = null; + + ProfileToggle.IsEnabled = false; + ProcessName.Text = Properties.Resources.QuickProfilesPage_Waiting; + ProcessPath.Text = string.Empty; + SubProfilesBorder.Visibility = Visibility.Collapsed; + } + }); + } + finally + { + foregroundLock.Exit(); + } } } @@ -577,14 +593,15 @@ private void UpdateProfile() private void ProfileToggle_Toggled(object sender, RoutedEventArgs e) { + // prevent update loop + if (foregroundLock.IsEntered()) + return; + // update real profile realProfile = ProfileManager.GetProfileFromPath(realProfile.Path, true); if (realProfile is null) return; - if (updateLock) - return; - if (realProfile.Default) { CreateProfile(); @@ -624,7 +641,8 @@ private void cB_Input_SelectionChanged(object sender, SelectionChangedEventArgs if (selectedProfile is null) return; - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; if (!selectedProfile.Layout.GyroLayout.TryGetValue(AxisLayoutFlags.Gyroscope, out IActions currentAction)) @@ -639,7 +657,8 @@ private void cB_Output_SelectionChanged(object sender, SelectionChangedEventArgs if (selectedProfile is null) return; - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; // try get current actions, if exists @@ -699,7 +718,8 @@ private void SliderUMCAntiDeadzone_ValueChanged(object sender, RoutedPropertyCha if (selectedProfile is null) return; - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; if (!selectedProfile.Layout.GyroLayout.TryGetValue(AxisLayoutFlags.Gyroscope, out IActions currentAction)) @@ -716,7 +736,8 @@ private void Slider_GyroWeight_ValueChanged(object sender, RoutedPropertyChanged if (selectedProfile is null) return; - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; if (!selectedProfile.Layout.GyroLayout.TryGetValue(AxisLayoutFlags.Gyroscope, out IActions currentAction)) @@ -733,7 +754,8 @@ private void SliderSensitivityX_ValueChanged(object sender, RoutedPropertyChange if (selectedProfile is null) return; - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; selectedProfile.MotionSensivityX = (float)SliderSensitivityX.Value; @@ -745,7 +767,8 @@ private void SliderSensitivityY_ValueChanged(object sender, RoutedPropertyChange if (selectedProfile is null) return; - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; selectedProfile.MotionSensivityY = (float)SliderSensitivityY.Value; @@ -793,7 +816,8 @@ private void cB_UMC_MotionDefaultOffOn_SelectionChanged(object sender, RoutedEve if (cB_UMC_MotionDefaultOffOn.SelectedIndex == -1 || selectedProfile is null) return; - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; if (!selectedProfile.Layout.GyroLayout.TryGetValue(AxisLayoutFlags.Gyroscope, out IActions currentAction)) @@ -808,8 +832,8 @@ private void RSRToggle_Toggled(object sender, RoutedEventArgs e) if (selectedProfile is null) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered() || graphicLock.IsEntered()) return; UpdateGraphicsSettings(UpdateGraphicsSettingsSource.RadeonSuperResolution, RSRToggle.IsOn); @@ -824,8 +848,8 @@ private void RSRSlider_ValueChanged(object sender, RoutedPropertyChangedEventArg if (!RSRSlider.IsInitialized) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered() || graphicLock.IsEntered()) return; selectedProfile.RSRSharpness = (int)RSRSlider.Value; @@ -837,8 +861,8 @@ private void RISToggle_Toggled(object sender, RoutedEventArgs e) if (selectedProfile is null) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered() || graphicLock.IsEntered()) return; UpdateGraphicsSettings(UpdateGraphicsSettingsSource.RadeonImageSharpening, RISToggle.IsOn); @@ -853,8 +877,8 @@ private void RISSlider_ValueChanged(object sender, RoutedPropertyChangedEventArg if (!RISSlider.IsInitialized) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered() || graphicLock.IsEntered()) return; selectedProfile.RISSharpness = (int)RISSlider.Value; @@ -866,31 +890,21 @@ private void Toggle_ControllerLayout_Toggled(object sender, RoutedEventArgs e) if (selectedProfile is null) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; selectedProfile.LayoutEnabled = Toggle_ControllerLayout.IsOn; UpdateProfile(); } - private void Button_PowerSettings_Create_Click(object sender, RoutedEventArgs e) - { - int idx = PowerProfileManager.profiles.Values.Where(p => !p.IsDefault()).Count() + 1; - - string Name = string.Format(Properties.Resources.PowerProfileManualName, idx); - PowerProfile powerProfile = new PowerProfile(Name, Properties.Resources.PowerProfileManualDescription); - - PowerProfileManager.UpdateOrCreateProfile(powerProfile, UpdateSource.Creation); - } - private void IntegerScalingToggle_Toggled(object sender, RoutedEventArgs e) { if (selectedProfile is null) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered() || graphicLock.IsEntered()) return; UpdateGraphicsSettings(UpdateGraphicsSettingsSource.IntegerScaling, IntegerScalingToggle.IsOn); @@ -902,8 +916,8 @@ private void GPUScalingComboBox_SelectionChanged(object sender, SelectionChanged if (GPUScalingComboBox.SelectedIndex == -1 || selectedProfile is null) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered() || graphicLock.IsEntered()) return; int selectedIndex = GPUScalingComboBox.SelectedIndex; @@ -925,21 +939,63 @@ private void GPUScaling_Toggled(object sender, RoutedEventArgs e) if (selectedProfile is null) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered() || graphicLock.IsEntered()) return; UpdateGraphicsSettings(UpdateGraphicsSettingsSource.GPUScaling, GPUScalingToggle.IsOn); UpdateProfile(); } + private void IntegerScalingComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (IntegerScalingComboBox.SelectedIndex == -1 || selectedProfile is null) + return; + + // prevent update loop + if (profileLock.IsEntered() || graphicLock.IsEntered()) + return; + + var divider = 1; + if (IntegerScalingComboBox.SelectedItem is ScreenDivider screenDivider) + { + divider = screenDivider.divider; + } + + selectedProfile.IntegerScalingDivider = divider; + UpdateProfile(); + } + + private void IntegerScalingTypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (IntegerScalingTypeComboBox.SelectedIndex == -1 || selectedProfile is null) + return; + + // prevent update loop + if (profileLock.IsEntered() || graphicLock.IsEntered()) + return; + + selectedProfile.IntegerScalingType = (byte)IntegerScalingTypeComboBox.SelectedIndex; + UpdateProfile(); + } + + private void Button_PowerSettings_Create_Click(object sender, RoutedEventArgs e) + { + int idx = PowerProfileManager.profiles.Values.Where(p => !p.IsDefault()).Count() + 1; + + string Name = string.Format(Properties.Resources.PowerProfileManualName, idx); + PowerProfile powerProfile = new PowerProfile(Name, Properties.Resources.PowerProfileManualDescription); + + PowerProfileManager.UpdateOrCreateProfile(powerProfile, UpdateSource.Creation); + } + private void cb_SubProfiles_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (selectedProfile is null) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; // return if combobox selected item is null @@ -956,8 +1012,8 @@ private void cB_Framerate_SelectionChanged(object sender, SelectionChangedEventA if (selectedProfile is null) return; - // wait until lock is released - if (updateLock) + // prevent update loop + if (profileLock.IsEntered()) return; // return if combobox selected item is null @@ -971,38 +1027,6 @@ private void cB_Framerate_SelectionChanged(object sender, SelectionChangedEventA } } - private void IntegerScalingComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (IntegerScalingComboBox.SelectedIndex == -1 || selectedProfile is null) - return; - - // wait until lock is released - if (updateLock) - return; - - var divider = 1; - if (IntegerScalingComboBox.SelectedItem is ScreenDivider screenDivider) - { - divider = screenDivider.divider; - } - - selectedProfile.IntegerScalingDivider = divider; - UpdateProfile(); - } - - private void IntegerScalingTypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (IntegerScalingTypeComboBox.SelectedIndex == -1 || selectedProfile is null) - return; - - // wait until lock is released - if (updateLock) - return; - - selectedProfile.IntegerScalingType = (byte)IntegerScalingTypeComboBox.SelectedIndex; - UpdateProfile(); - } - private enum UpdateGraphicsSettingsSource { GPUScaling, @@ -1013,69 +1037,76 @@ private enum UpdateGraphicsSettingsSource private void UpdateGraphicsSettings(UpdateGraphicsSettingsSource source, bool isEnabled) { - using (new ScopedLock(updateLock)) + if (graphicLock.TryEnter()) { - switch (source) + try { - case UpdateGraphicsSettingsSource.GPUScaling: - { - selectedProfile.GPUScaling = isEnabled; - if (!isEnabled) + switch (source) + { + case UpdateGraphicsSettingsSource.GPUScaling: { - selectedProfile.RSREnabled = false; - selectedProfile.IntegerScalingEnabled = false; + selectedProfile.GPUScaling = isEnabled; + if (!isEnabled) + { + selectedProfile.RSREnabled = false; + selectedProfile.IntegerScalingEnabled = false; - RSRToggle.IsOn = false; - IntegerScalingToggle.IsOn = false; + RSRToggle.IsOn = false; + IntegerScalingToggle.IsOn = false; + } } - } - break; - // RSR is incompatible with RIS and IS - case UpdateGraphicsSettingsSource.RadeonSuperResolution: - { - selectedProfile.RSREnabled = isEnabled; - if (isEnabled) + break; + // RSR is incompatible with RIS and IS + case UpdateGraphicsSettingsSource.RadeonSuperResolution: { - selectedProfile.RISEnabled = false; - selectedProfile.IntegerScalingEnabled = false; - - RISToggle.IsOn = false; - IntegerScalingToggle.IsOn = false; - - // RSR does not support ScalingMode.Center - if (selectedProfile.ScalingMode == 2) + selectedProfile.RSREnabled = isEnabled; + if (isEnabled) { - selectedProfile.ScalingMode = 1; - GPUScalingComboBox.SelectedIndex = 1; + selectedProfile.RISEnabled = false; + selectedProfile.IntegerScalingEnabled = false; + + RISToggle.IsOn = false; + IntegerScalingToggle.IsOn = false; + + // RSR does not support ScalingMode.Center + if (selectedProfile.ScalingMode == 2) + { + selectedProfile.ScalingMode = 1; + GPUScalingComboBox.SelectedIndex = 1; + } } } - } - break; - // Image Sharpening is incompatible with RSR - case UpdateGraphicsSettingsSource.RadeonImageSharpening: - { - selectedProfile.RISEnabled = isEnabled; - if (isEnabled) + break; + // Image Sharpening is incompatible with RSR + case UpdateGraphicsSettingsSource.RadeonImageSharpening: { - selectedProfile.RSREnabled = false; + selectedProfile.RISEnabled = isEnabled; + if (isEnabled) + { + selectedProfile.RSREnabled = false; - RSRToggle.IsOn = false; + RSRToggle.IsOn = false; + } } - } - break; + break; - // Integer Scaling is incompatible with RSR - case UpdateGraphicsSettingsSource.IntegerScaling: - { - selectedProfile.IntegerScalingEnabled = isEnabled; - if (isEnabled) + // Integer Scaling is incompatible with RSR + case UpdateGraphicsSettingsSource.IntegerScaling: { - selectedProfile.RSREnabled = false; + selectedProfile.IntegerScalingEnabled = isEnabled; + if (isEnabled) + { + selectedProfile.RSREnabled = false; - RSRToggle.IsOn = false; + RSRToggle.IsOn = false; + } } - } - break; + break; + } + } + finally + { + graphicLock.Exit(); } } } diff --git a/HandheldCompanion/Views/Windows/MainWindow.xaml.cs b/HandheldCompanion/Views/Windows/MainWindow.xaml.cs index 63adca0cf..14b97abd9 100644 --- a/HandheldCompanion/Views/Windows/MainWindow.xaml.cs +++ b/HandheldCompanion/Views/Windows/MainWindow.xaml.cs @@ -1,824 +1,840 @@ -using HandheldCompanion.Controllers; -using HandheldCompanion.Devices; -using HandheldCompanion.Inputs; -using HandheldCompanion.Managers; -using HandheldCompanion.UI; -using HandheldCompanion.Utils; -using HandheldCompanion.Views.Classes; -using HandheldCompanion.Views.Pages; -using HandheldCompanion.Views.Windows; -using iNKORE.UI.WPF.Modern.Controls; -using Nefarius.Utilities.DeviceManagement.PnP; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Forms; -using System.Windows.Input; -using System.Windows.Interop; -using System.Windows.Navigation; -using System.Windows.Threading; -using Windows.UI.ViewManagement; -using static HandheldCompanion.Managers.InputsHotkey; -using Application = System.Windows.Application; -using Control = System.Windows.Controls.Control; -using Page = System.Windows.Controls.Page; -using RadioButton = System.Windows.Controls.RadioButton; - -namespace HandheldCompanion.Views; - -/// -/// Interaction logic for MainWindow.xaml -/// -public partial class MainWindow : GamepadWindow -{ - // devices vars - private static IDevice CurrentDevice; - - // page vars - private static readonly Dictionary _pages = new(); - - public static ControllerPage controllerPage; - public static DevicePage devicePage; - public static PerformancePage performancePage; - public static ProfilesPage profilesPage; - public static SettingsPage settingsPage; - public static AboutPage aboutPage; - public static OverlayPage overlayPage; - public static HotkeysPage hotkeysPage; - public static LayoutPage layoutPage; - public static NotificationsPage notificationsPage; - - // overlay(s) vars - public static OverlayModel overlayModel; - public static OverlayTrackpad overlayTrackpad; - public static OverlayQuickTools overlayquickTools; - - public static string CurrentExe, CurrentPath; - - private static MainWindow CurrentWindow; - public static FileVersionInfo fileVersionInfo; - - public static string InstallPath = string.Empty; - public static string SettingsPath = string.Empty; - public static string CurrentPageName = string.Empty; - - private bool appClosing; - private readonly NotifyIcon notifyIcon; - private bool NotifyInTaskbar; - private string preNavItemTag; - - private WindowState prevWindowState; - public static SplashScreen SplashScreen; - - public static UISettings uiSettings; - - private const int WM_QUERYENDSESSION = 0x0011; - private const int WM_DISPLAYCHANGE = 0x007e; - private const int WM_DEVICECHANGE = 0x0219; - - public MainWindow(FileVersionInfo _fileVersionInfo, Assembly CurrentAssembly) - { - // initialize splash screen - SplashScreen = new SplashScreen(); +using HandheldCompanion.Controllers; +using HandheldCompanion.Devices; +using HandheldCompanion.Inputs; +using HandheldCompanion.Managers; +using HandheldCompanion.Utils; +using HandheldCompanion.Views.Classes; +using HandheldCompanion.Views.Pages; +using HandheldCompanion.Views.Windows; +using iNKORE.UI.WPF.Modern.Controls; +using Nefarius.Utilities.DeviceManagement.PnP; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Forms; +using System.Windows.Input; +using System.Windows.Interop; +using System.Windows.Navigation; +using Windows.UI.ViewManagement; +using static HandheldCompanion.Managers.InputsHotkey; +using Application = System.Windows.Application; +using Control = System.Windows.Controls.Control; +using Page = System.Windows.Controls.Page; +using RadioButton = System.Windows.Controls.RadioButton; + +namespace HandheldCompanion.Views; + +/// +/// Interaction logic for MainWindow.xaml +/// +public partial class MainWindow : GamepadWindow +{ + // devices vars + public static IDevice CurrentDevice; + + // page vars + private static readonly Dictionary _pages = new(); + + public static ControllerPage controllerPage; + public static DevicePage devicePage; + public static PerformancePage performancePage; + public static ProfilesPage profilesPage; + public static SettingsPage settingsPage; + public static AboutPage aboutPage; + public static OverlayPage overlayPage; + public static HotkeysPage hotkeysPage; + public static LayoutPage layoutPage; + public static NotificationsPage notificationsPage; + + // overlay(s) vars + public static OverlayModel overlayModel; + public static OverlayTrackpad overlayTrackpad; + public static OverlayQuickTools overlayquickTools; + + public static string CurrentExe, CurrentPath; + + private static MainWindow CurrentWindow; + public static FileVersionInfo fileVersionInfo; + + public static string InstallPath = string.Empty; + public static string SettingsPath = string.Empty; + public static string CurrentPageName = string.Empty; + + private bool appClosing; + private bool IsReady; + private readonly NotifyIcon notifyIcon; + private bool NotifyInTaskbar; + private string preNavItemTag; + + private WindowState prevWindowState; + private SplashScreen splashScreen; + + public static UISettings uiSettings; + + private const int WM_QUERYENDSESSION = 0x0011; + + public MainWindow(FileVersionInfo _fileVersionInfo, Assembly CurrentAssembly) + { + InitializeComponent(); + + fileVersionInfo = _fileVersionInfo; + CurrentWindow = this; + + // used by system manager, controller manager + uiSettings = new UISettings(); + + // used by gamepad navigation + Tag = "MainWindow"; + + // get process + var process = Process.GetCurrentProcess(); + + // fix touch support + TabletDeviceCollection tabletDevices = Tablet.TabletDevices; + /*if (tabletDevices.Count > 0) + { + // Get the Type of InputManager. + Type inputManagerType = typeof(System.Windows.Input.InputManager); + + // Call the StylusLogic method on the InputManager.Current instance. + object stylusLogic = inputManagerType.InvokeMember("StylusLogic", + BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, + null, InputManager.Current, null); + + if (stylusLogic != null) + { + // Get the type of the stylusLogic returned from the call to StylusLogic. + Type stylusLogicType = stylusLogic.GetType(); + + // Loop until there are no more devices to remove. + while (tabletDevices.Count > 0) + { + // Remove the first tablet device in the devices collection. + stylusLogicType.InvokeMember("OnTabletRemoved", + BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic, + null, stylusLogic, new object[] { (uint)0 }); + } + } + }*/ // get first start - bool FirstStart = SettingsManager.GetBoolean("FirstStart"); - - if (FirstStart) + bool FirstStart = SettingsManager.GetBoolean("FirstStart"); + + // define current directory + InstallPath = AppDomain.CurrentDomain.BaseDirectory; + SettingsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), + "HandheldCompanion"); + + // initialiaze path + if (!Directory.Exists(SettingsPath)) + Directory.CreateDirectory(SettingsPath); + + Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); + + // initialize XInputWrapper + XInputPlus.ExtractXInputPlusLibraries(); + + // initialize notifyIcon + notifyIcon = new NotifyIcon { -#if !DEBUG - SplashScreen.Show(); -#endif - } - - SplashScreen.LoadingSequence.Text = "Preparing UI..."; - - InitializeComponent(); - this.Tag = "MainWindow"; - - fileVersionInfo = _fileVersionInfo; - CurrentWindow = this; - - // used by system manager, controller manager - uiSettings = new UISettings(); - - // fix touch support - TabletDeviceCollection tabletDevices = Tablet.TabletDevices; - - // define current directory - InstallPath = AppDomain.CurrentDomain.BaseDirectory; - SettingsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), - "HandheldCompanion"); - - // initialiaze path - if (!Directory.Exists(SettingsPath)) - Directory.CreateDirectory(SettingsPath); - - Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); - - // initialize XInputWrapper - XInputPlus.ExtractXInputPlusLibraries(); - - // initialize notifyIcon - notifyIcon = new NotifyIcon - { - Text = Title, - Icon = System.Drawing.Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location), - Visible = false, - ContextMenuStrip = new ContextMenuStrip() - }; - - notifyIcon.DoubleClick += (sender, e) => { SwapWindowState(); }; - - AddNotifyIconItem(Properties.Resources.MainWindow_MainWindow); + Text = Title, + Icon = System.Drawing.Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location), + Visible = false, + ContextMenuStrip = new ContextMenuStrip() + }; + + notifyIcon.DoubleClick += (sender, e) => { SwapWindowState(); }; + + AddNotifyIconItem(Properties.Resources.MainWindow_MainWindow); AddNotifyIconItem(Properties.Resources.MainWindow_QuickTools); + + AddNotifyIconSeparator(); + + AddNotifyIconItem(Properties.Resources.MainWindow_Exit); + + // paths + CurrentExe = process.MainModule.FileName; + CurrentPath = AppDomain.CurrentDomain.BaseDirectory; - AddNotifyIconSeparator(); - - AddNotifyIconItem(Properties.Resources.MainWindow_Exit); - - // paths - Process process = Process.GetCurrentProcess(); - CurrentExe = process.MainModule.FileName; - CurrentPath = AppDomain.CurrentDomain.BaseDirectory; - - // initialize HidHide - HidHide.RegisterApplication(CurrentExe); - - // initialize title - Title += $" ({fileVersionInfo.FileVersion})"; - - // initialize device - SplashScreen.LoadingSequence.Text = "Initializing device..."; - CurrentDevice = IDevice.GetCurrent(); + // initialize HidHide + HidHide.RegisterApplication(CurrentExe); + + // initialize title + Title += $" ({fileVersionInfo.FileVersion})"; + + // initialize device + CurrentDevice = IDevice.GetDefault(); CurrentDevice.PullSensors(); - string currentDeviceType = CurrentDevice.GetType().Name; - switch (currentDeviceType) + // workaround for Bosch BMI320/BMI323 (as of 06/20/2023) + // todo: check if still needed with Bosch G-sensor Driver V1.0.1.7 + // https://dlcdnets.asus.com/pub/ASUS/IOTHMD/Image/Driver/Chipset/34644/BoschG-sensor_ROG_Bosch_Z_V1.0.1.7_34644.exe?model=ROG%20Ally%20(2023) + + string currentDeviceType = CurrentDevice.GetType().Name; + switch (currentDeviceType) { - /* - * workaround for Bosch BMI320/BMI323 (as of 06/20/2023) - * todo: check if still needed with Bosch G-sensor Driver V1.0.1.7 - * https://dlcdnets.asus.com/pub/ASUS/IOTHMD/Image/Driver/Chipset/34644/BoschG-sensor_ROG_Bosch_Z_V1.0.1.7_34644.exe?model=ROG%20Ally%20(2023) + case "AYANEOAIRPlus": + case "ROGAlly": + { + LogManager.LogInformation("Restarting: {0}", CurrentDevice.InternalSensorName); - case "AYANEOAIRPlus": - case "ROGAlly": + if (CurrentDevice.RestartSensor()) { - LogManager.LogInformation("Restarting: {0}", CurrentDevice.InternalSensorName); + // give the device some breathing space once restarted + Thread.Sleep(500); - if (CurrentDevice.RestartSensor()) - { - // give the device some breathing space once restarted - Thread.Sleep(500); + LogManager.LogInformation("Successfully restarted: {0}", CurrentDevice.InternalSensorName); + } + else + LogManager.LogError("Failed to restart: {0}", CurrentDevice.InternalSensorName); + } + break; + + case "SteamDeck": + { + // prevent Steam Deck controller from being hidden by default + if (FirstStart) + SettingsManager.SetProperty("HIDcloakonconnect", false); + } + break; + } + + // initialize splash screen on first start only + if (FirstStart) + { + splashScreen = new SplashScreen(); + splashScreen.Show(); + + SettingsManager.SetProperty("FirstStart", false); + } + + // load window(s) + loadWindows(); + + // load page(s) + loadPages(); + + // manage events + InputsManager.TriggerRaised += InputsManager_TriggerRaised; + PowerManager.SystemStatusChanged += OnSystemStatusChanged; + DeviceManager.UsbDeviceArrived += GenericDeviceUpdated; + DeviceManager.UsbDeviceRemoved += GenericDeviceUpdated; + ControllerManager.ControllerSelected += ControllerManager_ControllerSelected; + VirtualManager.ControllerSelected += VirtualManager_ControllerSelected; - LogManager.LogInformation("Successfully restarted: {0}", CurrentDevice.InternalSensorName); + ToastManager.Start(); + ToastManager.IsEnabled = SettingsManager.GetBoolean("ToastEnable"); + + // start static managers in sequence + PowerProfileManager.Start(); + ProfileManager.Start(); + ControllerManager.Start(); + HotkeysManager.Start(); + DeviceManager.Start(); + OSDManager.Start(); + LayoutManager.Start(); + PowerManager.Start(); + DynamicLightingManager.Start(); + SystemManager.Start(); + VirtualManager.Start(); + InputsManager.Start(); + SensorsManager.Start(); + TimerManager.Start(); + + // todo: improve overall threading logic + new Thread(() => { PlatformManager.Start(); }).Start(); + new Thread(() => { ProcessManager.Start(); }).Start(); + new Thread(() => { TaskManager.Start(CurrentExe); }).Start(); + new Thread(() => { PerformanceManager.Start(); }).Start(); + new Thread(() => { UpdateManager.Start(); }).Start(); + + // start setting last + SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; + SettingsManager.Start(); + + // update Position and Size + Height = (int)Math.Max(MinHeight, SettingsManager.GetDouble("MainWindowHeight")); + Width = (int)Math.Max(MinWidth, SettingsManager.GetDouble("MainWindowWidth")); + Left = Math.Min(SystemParameters.PrimaryScreenWidth - MinWidth, SettingsManager.GetDouble("MainWindowLeft")); + Top = Math.Min(SystemParameters.PrimaryScreenHeight - MinHeight, SettingsManager.GetDouble("MainWindowTop")); + navView.IsPaneOpen = SettingsManager.GetBoolean("MainWindowIsPaneOpen"); + } + + private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + // windows shutting down event + if (msg == WM_QUERYENDSESSION) + { + // do something + } + + return IntPtr.Zero; + } + + private void ControllerManager_ControllerSelected(IController Controller) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + GamepadUISelectIcon.Glyph = Controller.GetGlyph(ButtonFlags.B1); + GamepadUISelectIcon.Foreground = Controller.GetGlyphColor(ButtonFlags.B1); + + GamepadUIBackIcon.Glyph = Controller.GetGlyph(ButtonFlags.B2); + GamepadUIBackIcon.Foreground = Controller.GetGlyphColor(ButtonFlags.B2); + + GamepadUIToggleIcon.Glyph = Controller.GetGlyph(ButtonFlags.B4); + GamepadUIToggleIcon.Foreground = Controller.GetGlyphColor(ButtonFlags.B4); + }); + } + + private void GamepadFocusManagerOnFocused(Control control) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + // todo : localize me + string controlType = control.GetType().Name; + switch (controlType) + { + default: + { + GamepadUISelect.Visibility = Visibility.Visible; + GamepadUIBack.Visibility = Visibility.Visible; + GamepadUIToggle.Visibility = Visibility.Collapsed; + + GamepadUISelectDesc.Text = Properties.Resources.MainWindow_Select; + GamepadUIBackDesc.Text = Properties.Resources.MainWindow_Back; + } + break; + + case "Button": + { + GamepadUISelect.Visibility = Visibility.Visible; + GamepadUIBack.Visibility = Visibility.Visible; + + GamepadUISelectDesc.Text = Properties.Resources.MainWindow_Select; + GamepadUIBackDesc.Text = Properties.Resources.MainWindow_Back; + + // To get the first RadioButton in the list, if any + RadioButton firstRadioButton = WPFUtils.FindChildren(control).FirstOrDefault(c => c is RadioButton) as RadioButton; + if (firstRadioButton is not null) + { + GamepadUIToggle.Visibility = Visibility.Visible; + GamepadUIToggleDesc.Text = Properties.Resources.MainWindow_Toggle; } - else - LogManager.LogError("Failed to restart: {0}", CurrentDevice.InternalSensorName); } break; - */ - - case "SteamDeck": - { - // prevent Steam Deck controller from being hidden by default - if (FirstStart) - SettingsManager.SetProperty("HIDcloakonconnect", false); - } - break; - } - - // initialize splash screen on first start only - SettingsManager.SetProperty("FirstStart", false); - - // initialize UI sounds board - UISounds uiSounds = new UISounds(); - - // load window(s) - SplashScreen.LoadingSequence.Text = "Drawing windows..."; - Dispatcher.Invoke(new Action(() => - { - loadWindows(); - }), DispatcherPriority.Background); // Lower priority - - // load page(s) - SplashScreen.LoadingSequence.Text = "Drawing pages..."; - Dispatcher.Invoke(new Action(() => - { - loadPages(); - }), DispatcherPriority.Background); // Lower priority - - // manage events - InputsManager.TriggerRaised += InputsManager_TriggerRaised; - SystemManager.SystemStatusChanged += OnSystemStatusChanged; - DeviceManager.UsbDeviceArrived += GenericDeviceUpdated; - DeviceManager.UsbDeviceRemoved += GenericDeviceUpdated; - ControllerManager.ControllerSelected += ControllerManager_ControllerSelected; - - ToastManager.Start(); - ToastManager.IsEnabled = SettingsManager.GetBoolean("ToastEnable"); - - // start static managers in sequence - SplashScreen.LoadingSequence.Text = "Initializing managers..."; - Dispatcher.Invoke(new Action(() => - { - GPUManager.Start(); - PowerProfileManager.Start(); - ProfileManager.Start(); - ControllerManager.Start(); - HotkeysManager.Start(); - DeviceManager.Start(); - OSDManager.Start(); - LayoutManager.Start(); - SystemManager.Start(); - DynamicLightingManager.Start(); - MultimediaManager.Start(); - VirtualManager.Start(); - InputsManager.Start(); - SensorsManager.Start(); - TimerManager.Start(); - }), DispatcherPriority.Background); // Lower priority - - // todo: improve overall threading logic - new Thread(() => { PlatformManager.Start(); }).Start(); - new Thread(() => { ProcessManager.Start(); }).Start(); - new Thread(() => { TaskManager.Start(CurrentExe); }).Start(); - new Thread(() => { PerformanceManager.Start(); }).Start(); - new Thread(() => { UpdateManager.Start(); }).Start(); - - // start setting last - SettingsManager.SettingValueChanged += SettingsManager_SettingValueChanged; - SettingsManager.Start(); - - // Load MVVM pages after the Models / data have been created. - overlayquickTools.LoadPages_MVVM(); - LoadPages_MVVM(); - - // update Position and Size - Height = (int)Math.Max(MinHeight, SettingsManager.GetDouble("MainWindowHeight")); - Width = (int)Math.Max(MinWidth, SettingsManager.GetDouble("MainWindowWidth")); - Left = Math.Min(SystemParameters.PrimaryScreenWidth - MinWidth, SettingsManager.GetDouble("MainWindowLeft")); - Top = Math.Min(SystemParameters.PrimaryScreenHeight - MinHeight, SettingsManager.GetDouble("MainWindowTop")); - navView.IsPaneOpen = SettingsManager.GetBoolean("MainWindowIsPaneOpen"); - } - - private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - switch (msg) - { - case WM_DISPLAYCHANGE: - case WM_DEVICECHANGE: - DeviceManager.RefreshDisplayAdapters(); - break; - case WM_QUERYENDSESSION: - break; - } - - return IntPtr.Zero; - } - - private void ControllerManager_ControllerSelected(IController Controller) - { - // UI thread (async) - Application.Current.Dispatcher.Invoke(() => - { - GamepadUISelectIcon.Glyph = Controller.GetGlyph(ButtonFlags.B1); - GamepadUISelectIcon.Foreground = Controller.GetGlyphColor(ButtonFlags.B1); - - GamepadUIBackIcon.Glyph = Controller.GetGlyph(ButtonFlags.B2); - GamepadUIBackIcon.Foreground = Controller.GetGlyphColor(ButtonFlags.B2); - - GamepadUIToggleIcon.Glyph = Controller.GetGlyph(ButtonFlags.B4); - GamepadUIToggleIcon.Foreground = Controller.GetGlyphColor(ButtonFlags.B4); - }); - } - - private void GamepadFocusManagerOnFocused(Control control) - { - // UI thread (async) - Application.Current.Dispatcher.Invoke(() => - { - // todo : localize me - string controlType = control.GetType().Name; - switch (controlType) - { - default: - { - GamepadUISelect.Visibility = Visibility.Visible; - GamepadUIBack.Visibility = Visibility.Visible; - GamepadUIToggle.Visibility = Visibility.Collapsed; - - GamepadUISelectDesc.Text = Properties.Resources.MainWindow_Select; - GamepadUIBackDesc.Text = Properties.Resources.MainWindow_Back; - } - break; - - case "Button": - { - GamepadUISelect.Visibility = Visibility.Visible; - GamepadUIBack.Visibility = Visibility.Visible; - - GamepadUISelectDesc.Text = Properties.Resources.MainWindow_Select; - GamepadUIBackDesc.Text = Properties.Resources.MainWindow_Back; - - // To get the first RadioButton in the list, if any - RadioButton firstRadioButton = WPFUtils.FindChildren(control).FirstOrDefault(c => c is RadioButton) as RadioButton; - if (firstRadioButton is not null) - { - GamepadUIToggle.Visibility = Visibility.Visible; - GamepadUIToggleDesc.Text = Properties.Resources.MainWindow_Toggle; - } - } - break; - - case "Slider": - { - GamepadUISelect.Visibility = Visibility.Collapsed; - GamepadUIBack.Visibility = Visibility.Visible; - GamepadUIToggle.Visibility = Visibility.Collapsed; - } - break; - - case "NavigationViewItem": - { - GamepadUISelect.Visibility = Visibility.Visible; - GamepadUIBack.Visibility = Visibility.Collapsed; - GamepadUIToggle.Visibility = Visibility.Collapsed; - - GamepadUISelectDesc.Text = Properties.Resources.MainWindow_Navigate; - } - break; - } - }); - } - - private void AddNotifyIconItem(string name, object tag = null) - { - tag ??= string.Concat(name.Where(c => !char.IsWhiteSpace(c))); - - var menuItemMainWindow = new ToolStripMenuItem(name); - menuItemMainWindow.Tag = tag; - menuItemMainWindow.Click += MenuItem_Click; - notifyIcon.ContextMenuStrip.Items.Add(menuItemMainWindow); - } - - private void AddNotifyIconSeparator() - { - var separator = new ToolStripSeparator(); - notifyIcon.ContextMenuStrip.Items.Add(separator); - } - - private void SettingsManager_SettingValueChanged(string name, object value) - { - switch (name) - { - case "ToastEnable": - ToastManager.IsEnabled = Convert.ToBoolean(value); - break; - case "DesktopProfileOnStart": - if (SettingsManager.IsInitialized) - break; - - var DesktopLayout = Convert.ToBoolean(value); - SettingsManager.SetProperty("DesktopLayoutEnabled", DesktopLayout, false, true); - break; - } - } - - public void SwapWindowState() - { - // UI thread - Application.Current.Dispatcher.Invoke(() => - { - switch (WindowState) - { - case WindowState.Normal: - case WindowState.Maximized: - WindowState = WindowState.Minimized; - break; - case WindowState.Minimized: - WindowState = prevWindowState; - break; - } - }); - } - - public static MainWindow GetCurrent() - { - return CurrentWindow; - } - - private void loadPages() - { - // initialize pages - controllerPage = new ControllerPage("controller"); - controllerPage.Loaded += ControllerPage_Loaded; - - devicePage = new DevicePage("device"); - profilesPage = new ProfilesPage("profiles"); - settingsPage = new SettingsPage("settings"); - overlayPage = new OverlayPage("overlay"); + case "Slider": + { + GamepadUISelect.Visibility = Visibility.Collapsed; + GamepadUIBack.Visibility = Visibility.Visible; + GamepadUIToggle.Visibility = Visibility.Collapsed; + } + break; + + case "NavigationViewItem": + { + GamepadUISelect.Visibility = Visibility.Visible; + GamepadUIBack.Visibility = Visibility.Collapsed; + GamepadUIToggle.Visibility = Visibility.Collapsed; + + GamepadUISelectDesc.Text = Properties.Resources.MainWindow_Navigate; + } + break; + } + }); + } + + private void AddNotifyIconItem(string name, object tag = null) + { + tag ??= string.Concat(name.Where(c => !char.IsWhiteSpace(c))); + + var menuItemMainWindow = new ToolStripMenuItem(name); + menuItemMainWindow.Tag = tag; + menuItemMainWindow.Click += MenuItem_Click; + notifyIcon.ContextMenuStrip.Items.Add(menuItemMainWindow); + } + + private void AddNotifyIconSeparator() + { + var separator = new ToolStripSeparator(); + notifyIcon.ContextMenuStrip.Items.Add(separator); + } + + private void SettingsManager_SettingValueChanged(string name, object value) + { + switch (name) + { + case "ToastEnable": + ToastManager.IsEnabled = Convert.ToBoolean(value); + break; + case "DesktopProfileOnStart": + if (SettingsManager.IsInitialized) + break; + + var DesktopLayout = Convert.ToBoolean(value); + SettingsManager.SetProperty("DesktopLayoutEnabled", DesktopLayout, false, true); + break; + } + } + + public void SwapWindowState() + { + // UI thread + Application.Current.Dispatcher.Invoke(() => + { + switch (WindowState) + { + case WindowState.Normal: + case WindowState.Maximized: + WindowState = WindowState.Minimized; + break; + case WindowState.Minimized: + WindowState = prevWindowState; + break; + } + }); + } + + public static MainWindow GetCurrent() + { + return CurrentWindow; + } + + private void loadPages() + { + // initialize pages + controllerPage = new ControllerPage("controller"); + controllerPage.Loaded += ControllerPage_Loaded; + + devicePage = new DevicePage("device"); + performancePage = new PerformancePage("performance"); + profilesPage = new ProfilesPage("profiles"); + settingsPage = new SettingsPage("settings"); + aboutPage = new AboutPage("about"); + overlayPage = new OverlayPage("overlay"); hotkeysPage = new HotkeysPage("hotkeys"); + layoutPage = new LayoutPage("layout", navView); + notificationsPage = new NotificationsPage("notifications"); + notificationsPage.StatusChanged += NotificationsPage_LayoutUpdated; - notificationsPage = new NotificationsPage("notifications"); - notificationsPage.StatusChanged += NotificationsPage_LayoutUpdated; - - // store pages - _pages.Add("ControllerPage", controllerPage); + // store pages + _pages.Add("ControllerPage", controllerPage); _pages.Add("DevicePage", devicePage); - + _pages.Add("PerformancePage", performancePage); _pages.Add("ProfilesPage", profilesPage); - - _pages.Add("OverlayPage", overlayPage); - _pages.Add("SettingsPage", settingsPage); + _pages.Add("AboutPage", aboutPage); + _pages.Add("OverlayPage", overlayPage); + _pages.Add("SettingsPage", settingsPage); _pages.Add("HotkeysPage", hotkeysPage); + _pages.Add("LayoutPage", layoutPage); + _pages.Add("NotificationsPage", notificationsPage); + } + + private void loadWindows() + { + // initialize overlay + overlayModel = new OverlayModel(); + overlayTrackpad = new OverlayTrackpad(); + overlayquickTools = new OverlayQuickTools(); + } + + private void GenericDeviceUpdated(PnPDevice device, DeviceEventArgs obj) + { + // todo: improve me + CurrentDevice.PullSensors(); + + aboutPage.UpdateDevice(device); + settingsPage.UpdateDevice(device); + } + + private void InputsManager_TriggerRaised(string listener, InputsChord input, InputsHotkeyType type, bool IsKeyDown, + bool IsKeyUp) + { + switch (listener) + { + case "quickTools": + overlayquickTools.ToggleVisibility(); + break; + case "overlayGamepad": + overlayModel.ToggleVisibility(); + break; + case "overlayTrackpads": + overlayTrackpad.ToggleVisibility(); + break; + case "shortcutMainwindow": + SwapWindowState(); + break; + } + } + + private void MenuItem_Click(object? sender, EventArgs e) + { + switch (((ToolStripMenuItem)sender).Tag) + { + case "MainWindow": + SwapWindowState(); + break; + case "QuickTools": + overlayquickTools.ToggleVisibility(); + break; + case "Exit": + appClosing = true; + Close(); + break; + } + } + + private void Window_Loaded(object sender, RoutedEventArgs e) + { + // load gamepad navigation maanger + gamepadFocusManager = new(this, ContentFrame); + + HwndSource source = PresentationSource.FromVisual(this) as HwndSource; + source.AddHook(WndProc); // Hook into the window's message loop + } + + private void ControllerPage_Loaded(object sender, RoutedEventArgs e) + { + if (IsReady) + return; + + // hide splashscreen + if (splashScreen is not null) + splashScreen.Close(); + + // home page has loaded, display main window + WindowState = SettingsManager.GetBoolean("StartMinimized") + ? WindowState.Minimized + : (WindowState)SettingsManager.GetInt("MainWindowState"); + prevWindowState = (WindowState)SettingsManager.GetInt("MainWindowPrevState"); + + IsReady = true; + } + + private void NotificationsPage_LayoutUpdated(int status) + { + bool hasNotification = Convert.ToBoolean(status); + + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + HasNotifications.Visibility = hasNotification ? Visibility.Visible : Visibility.Collapsed; + }); + } + + private void VirtualManager_ControllerSelected(HIDmode HIDmode) + { + Application.Current.Dispatcher.BeginInvoke(() => + { + overlayModel.UpdateHIDMode(HIDmode); + }); + CurrentDevice.SetKeyPressDelay(HIDmode); + } + + public void UpdateSettings(Dictionary args) + { + foreach (var pair in args) + { + var name = pair.Key; + var property = pair.Value; + + switch (name) + { + case "DSUEnabled": + break; + case "DSUip": + break; + case "DSUport": + break; + } + } + } + + // no code from the cases inside this function will be called on program start + private async void OnSystemStatusChanged(PowerManager.SystemStatus status, PowerManager.SystemStatus prevStatus) + { + if (status == prevStatus) + return; + + switch (status) + { + case PowerManager.SystemStatus.SystemReady: + { + // resume from sleep + if (prevStatus == PowerManager.SystemStatus.SystemPending) + { + // use device-specific delay + await Task.Delay(CurrentDevice.ResumeDelay); + + // restore inputs manager + InputsManager.Start(); + + // start timer manager + TimerManager.Start(); + + // resume the virtual controller last + VirtualManager.Resume(); + + // restart IMU + SensorsManager.Resume(true); + } + + // open device, when ready + new Thread(() => + { + // wait for all HIDs to be ready + while (!CurrentDevice.IsReady()) + Thread.Sleep(500); + + // open current device (threaded to avoid device to hang) + CurrentDevice.Open(); + }).Start(); + } + break; + + case PowerManager.SystemStatus.SystemPending: + // sleep + { + // stop the virtual controller + VirtualManager.Suspend(); + + // stop timer manager + TimerManager.Stop(); + + // stop sensors + SensorsManager.Stop(); + + // pause inputs manager + InputsManager.Stop(); + + // close current device + CurrentDevice.Close(); + } + break; + } + } + + #region UI + + private void navView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) + { + if (args.InvokedItemContainer is not null) + { + var navItem = (NavigationViewItem)args.InvokedItemContainer; + var navItemTag = (string)navItem.Tag; + + switch (navItemTag) + { + default: + preNavItemTag = navItemTag; + break; + } + + NavView_Navigate(preNavItemTag); + } + } + + public void NavView_Navigate(string navItemTag) + { + var item = _pages.FirstOrDefault(p => p.Key.Equals(navItemTag)); + var _page = item.Value; + + // Get the page type before navigation so you can prevent duplicate + // entries in the backstack. + var preNavPageType = ContentFrame.CurrentSourcePageType; + + // Only navigate if the selected page isn't currently loaded. + if (!(_page is null) && !Equals(preNavPageType, _page)) NavView_Navigate(_page); + } + + public static void NavView_Navigate(Page _page) + { + CurrentWindow.ContentFrame.Navigate(_page); + CurrentWindow.scrollViewer.ScrollToTop(); + } + + private void navView_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args) + { + TryGoBack(); + } + + private void Window_Closed(object sender, EventArgs e) + { + CurrentDevice.Close(); + + notifyIcon.Visible = false; + notifyIcon.Dispose(); + + overlayModel.Close(); + overlayTrackpad.Close(); + overlayquickTools.Close(true); + + VirtualManager.Stop(); + SystemManager.Stop(); + MotionManager.Stop(); + SensorsManager.Stop(); + ControllerManager.Stop(); + InputsManager.Stop(); + DeviceManager.Stop(); + PlatformManager.Stop(); + OSDManager.Stop(); + PowerProfileManager.Stop(); + ProfileManager.Stop(); + LayoutManager.Stop(); + PowerManager.Stop(); + ProcessManager.Stop(); + ToastManager.Stop(); + TaskManager.Stop(); + PerformanceManager.Stop(); + UpdateManager.Stop(); + + // closing page(s) + controllerPage.Page_Closed(); + profilesPage.Page_Closed(); + settingsPage.Page_Closed(); + overlayPage.Page_Closed(); + hotkeysPage.Page_Closed(); + layoutPage.Page_Closed(); + notificationsPage.Page_Closed(); + + // force kill application + Environment.Exit(0); + } + + private async void Window_Closing(object sender, CancelEventArgs e) + { + // position and size settings + switch (WindowState) + { + case WindowState.Normal: + SettingsManager.SetProperty("MainWindowLeft", Left); + SettingsManager.SetProperty("MainWindowTop", Top); + SettingsManager.SetProperty("MainWindowWidth", ActualWidth); + SettingsManager.SetProperty("MainWindowHeight", ActualHeight); + break; + case WindowState.Maximized: + SettingsManager.SetProperty("MainWindowLeft", 0); + SettingsManager.SetProperty("MainWindowTop", 0); + SettingsManager.SetProperty("MainWindowWidth", SystemParameters.MaximizedPrimaryScreenWidth); + SettingsManager.SetProperty("MainWindowHeight", SystemParameters.MaximizedPrimaryScreenHeight); + + break; + } + + SettingsManager.SetProperty("MainWindowState", (int)WindowState); + SettingsManager.SetProperty("MainWindowPrevState", (int)prevWindowState); + + SettingsManager.SetProperty("MainWindowIsPaneOpen", navView.IsPaneOpen); + + if (SettingsManager.GetBoolean("CloseMinimises") && !appClosing) + { + e.Cancel = true; + WindowState = WindowState.Minimized; + return; + } + } + + private void Window_StateChanged(object sender, EventArgs e) + { + switch (WindowState) + { + case WindowState.Minimized: + notifyIcon.Visible = true; + ShowInTaskbar = false; + + if (!NotifyInTaskbar) + { + ToastManager.SendToast(Title, "is running in the background"); + NotifyInTaskbar = true; + } + + break; + case WindowState.Normal: + case WindowState.Maximized: + notifyIcon.Visible = false; + ShowInTaskbar = true; + + Activate(); + Topmost = true; // important + Topmost = false; // important + Focus(); + + prevWindowState = WindowState; + break; + } + } + + private void navView_Loaded(object sender, RoutedEventArgs e) + { + // Add handler for ContentFrame navigation. + ContentFrame.Navigated += On_Navigated; + + // NavView doesn't load any page by default, so load home page. + navView.SelectedItem = navView.MenuItems[0]; + + // If navigation occurs on SelectionChanged, this isn't needed. + // Because we use ItemInvoked to navigate, we need to call Navigate + // here to load the home page. + preNavItemTag = "ControllerPage"; + NavView_Navigate(preNavItemTag); + } + + private void GamepadWindow_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) + { + if (!e.NewFocus.GetType().IsSubclassOf(typeof(Control))) + return; + + GamepadFocusManagerOnFocused((Control)e.NewFocus); + } + + private void GamepadWindow_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) + { + // do something + } + + private bool TryGoBack() + { + if (!ContentFrame.CanGoBack) + return false; + + // Don't go back if the nav pane is overlayed. + if (navView.IsPaneOpen && + (navView.DisplayMode == NavigationViewDisplayMode.Compact || + navView.DisplayMode == NavigationViewDisplayMode.Minimal)) + return false; + + ContentFrame.GoBack(); + return true; + } + + private void On_Navigated(object sender, NavigationEventArgs e) + { + navView.IsBackEnabled = ContentFrame.CanGoBack; + + if (ContentFrame.SourcePageType is not null) + { + CurrentPageName = ContentFrame.CurrentSourcePageType.Name; + + var NavViewItem = navView.MenuItems + .OfType() + .Where(n => n.Tag.Equals(CurrentPageName)).FirstOrDefault(); + + if (!(NavViewItem is null)) + navView.SelectedItem = NavViewItem; + + navView.Header = new TextBlock() { Text = (string)((Page)e.Content).Title }; + } + } - _pages.Add("NotificationsPage", notificationsPage); - } - - private void LoadPages_MVVM() - { - layoutPage = new LayoutPage("layout", navView); - layoutPage.Initialize(); - - performancePage = new PerformancePage(); - aboutPage = new AboutPage(); - - _pages.Add("LayoutPage", layoutPage); - _pages.Add("PerformancePage", performancePage); - _pages.Add("AboutPage", aboutPage); - } - - private void loadWindows() - { - // initialize overlay - overlayModel = new OverlayModel(); - overlayTrackpad = new OverlayTrackpad(); - overlayquickTools = new OverlayQuickTools(); - } - - private void GenericDeviceUpdated(PnPDevice device, DeviceEventArgs obj) - { - // todo: improve me - CurrentDevice.PullSensors(); - } - - private void InputsManager_TriggerRaised(string listener, InputsChord input, InputsHotkeyType type, bool IsKeyDown, - bool IsKeyUp) - { - switch (listener) - { - case "quickTools": - overlayquickTools.ToggleVisibility(); - break; - case "overlayGamepad": - overlayModel.ToggleVisibility(); - break; - case "overlayTrackpads": - overlayTrackpad.ToggleVisibility(); - break; - case "shortcutMainwindow": - SwapWindowState(); - break; - } - } - - private void MenuItem_Click(object? sender, EventArgs e) - { - switch (((ToolStripMenuItem)sender).Tag) - { - case "MainWindow": - SwapWindowState(); - break; - case "QuickTools": - overlayquickTools.ToggleVisibility(); - break; - case "Exit": - appClosing = true; - Close(); - break; - } - } - - private void Window_Loaded(object sender, RoutedEventArgs e) - { - // load gamepad navigation maanger - gamepadFocusManager = new(this, ContentFrame); - - HwndSource source = PresentationSource.FromVisual(this) as HwndSource; - source.AddHook(WndProc); // Hook into the window's message loop - - // restore window state - WindowState = SettingsManager.GetBoolean("StartMinimized") ? WindowState.Minimized : (WindowState)SettingsManager.GetInt("MainWindowState"); - prevWindowState = (WindowState)SettingsManager.GetInt("MainWindowPrevState"); - } - - private void ControllerPage_Loaded(object sender, RoutedEventArgs e) - { - // hide splashscreen - if (SplashScreen is not null) - SplashScreen.Close(); - - // home page is ready, display main window - this.Visibility = Visibility.Visible; - } - - private void NotificationsPage_LayoutUpdated(int status) - { - bool hasNotification = Convert.ToBoolean(status); - - // UI thread (async) - Application.Current.Dispatcher.Invoke(() => - { - HasNotifications.Visibility = hasNotification ? Visibility.Visible : Visibility.Collapsed; - }); - } - - // no code from the cases inside this function will be called on program start - private async void OnSystemStatusChanged(SystemManager.SystemStatus status, SystemManager.SystemStatus prevStatus) - { - if (status == prevStatus) - return; - - switch (status) - { - case SystemManager.SystemStatus.SystemReady: - { - if (prevStatus == SystemManager.SystemStatus.SystemPending) - { - // when device resumes from sleep - // use device-specific delay - await Task.Delay(CurrentDevice.ResumeDelay); - - // resume manager(s) - InputsManager.Start(); - TimerManager.Start(); - VirtualManager.Resume(); - SensorsManager.Resume(true); - GPUManager.Start(); - - // resume platform(s) - PlatformManager.LibreHardwareMonitor.Start(); - } - - // open device, when ready - new Thread(() => - { - // wait for all HIDs to be ready - while (!CurrentDevice.IsReady()) - Thread.Sleep(500); - - // open current device (threaded to avoid device to hang) - CurrentDevice.Open(); - }).Start(); - } - break; - - case SystemManager.SystemStatus.SystemPending: - { - // when device goes to sleep - // suspend manager(s) - VirtualManager.Suspend(); - TimerManager.Stop(); - SensorsManager.Stop(); - InputsManager.Stop(); - GPUManager.Stop(); - - // suspend platform(s) - PlatformManager.LibreHardwareMonitor.Stop(); - - // close current device - CurrentDevice.Close(); - - // Allow system to sleep - SystemManager.SetThreadExecutionState(SystemManager.ES_CONTINUOUS); - LogManager.LogDebug("Tasks completed. System can now suspend if needed."); - } - break; - } - } - - #region UI - - private void navView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) - { - if (args.InvokedItemContainer is not null) - { - var navItem = (NavigationViewItem)args.InvokedItemContainer; - var navItemTag = (string)navItem.Tag; - - switch (navItemTag) - { - default: - preNavItemTag = navItemTag; - break; - } - - NavView_Navigate(preNavItemTag); - } - } - - public void NavView_Navigate(string navItemTag) - { - var item = _pages.FirstOrDefault(p => p.Key.Equals(navItemTag)); - var _page = item.Value; - - // Get the page type before navigation so you can prevent duplicate - // entries in the backstack. - var preNavPageType = ContentFrame.CurrentSourcePageType; - - // Only navigate if the selected page isn't currently loaded. - if (!(_page is null) && !Equals(preNavPageType, _page)) NavView_Navigate(_page); - } - - public static void NavView_Navigate(Page _page) - { - CurrentWindow.ContentFrame.Navigate(_page); - CurrentWindow.scrollViewer.ScrollToTop(); - } - - private void navView_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args) - { - TryGoBack(); - } - - private void Window_Closed(object sender, EventArgs e) - { - CurrentDevice.Close(); - - notifyIcon.Visible = false; - notifyIcon.Dispose(); - - overlayModel.Close(); - overlayTrackpad.Close(); - overlayquickTools.Close(true); - - VirtualManager.Stop(); - MultimediaManager.Stop(); - GPUManager.Stop(); - MotionManager.Stop(); - SensorsManager.Stop(); - ControllerManager.Stop(); - InputsManager.Stop(); - DeviceManager.Stop(); - PlatformManager.Stop(); - OSDManager.Stop(); - PowerProfileManager.Stop(); - ProfileManager.Stop(); - LayoutManager.Stop(); - SystemManager.Stop(); - ProcessManager.Stop(); - ToastManager.Stop(); - TaskManager.Stop(); - PerformanceManager.Stop(); - UpdateManager.Stop(); - - // closing page(s) - controllerPage.Page_Closed(); - profilesPage.Page_Closed(); - settingsPage.Page_Closed(); - overlayPage.Page_Closed(); - hotkeysPage.Page_Closed(); - layoutPage.Page_Closed(); - notificationsPage.Page_Closed(); - - // force kill application - Environment.Exit(0); - } - - private async void Window_Closing(object sender, CancelEventArgs e) - { - // position and size settings - switch (WindowState) - { - case WindowState.Normal: - SettingsManager.SetProperty("MainWindowLeft", Left); - SettingsManager.SetProperty("MainWindowTop", Top); - SettingsManager.SetProperty("MainWindowWidth", ActualWidth); - SettingsManager.SetProperty("MainWindowHeight", ActualHeight); - break; - case WindowState.Maximized: - SettingsManager.SetProperty("MainWindowLeft", 0); - SettingsManager.SetProperty("MainWindowTop", 0); - SettingsManager.SetProperty("MainWindowWidth", SystemParameters.MaximizedPrimaryScreenWidth); - SettingsManager.SetProperty("MainWindowHeight", SystemParameters.MaximizedPrimaryScreenHeight); - - break; - } - - SettingsManager.SetProperty("MainWindowState", (int)WindowState); - SettingsManager.SetProperty("MainWindowPrevState", (int)prevWindowState); - - SettingsManager.SetProperty("MainWindowIsPaneOpen", navView.IsPaneOpen); - - if (SettingsManager.GetBoolean("CloseMinimises") && !appClosing) - { - e.Cancel = true; - WindowState = WindowState.Minimized; - return; - } - } - - private void Window_StateChanged(object sender, EventArgs e) - { - switch (WindowState) - { - case WindowState.Minimized: - notifyIcon.Visible = true; - ShowInTaskbar = false; - - if (!NotifyInTaskbar) - { - ToastManager.SendToast(Title, "is running in the background"); - NotifyInTaskbar = true; - } - - break; - case WindowState.Normal: - case WindowState.Maximized: - notifyIcon.Visible = false; - ShowInTaskbar = true; - - Activate(); - Topmost = true; // important - Topmost = false; // important - Focus(); - - prevWindowState = WindowState; - break; - } - } - - private void navView_Loaded(object sender, RoutedEventArgs e) - { - // Add handler for ContentFrame navigation. - ContentFrame.Navigated += On_Navigated; - - // NavView doesn't load any page by default, so load home page. - navView.SelectedItem = navView.MenuItems[0]; - - // If navigation occurs on SelectionChanged, this isn't needed. - // Because we use ItemInvoked to navigate, we need to call Navigate - // here to load the home page. - preNavItemTag = "ControllerPage"; - NavView_Navigate(preNavItemTag); - } - - private void GamepadWindow_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) - { - if (!e.NewFocus.GetType().IsSubclassOf(typeof(Control))) - return; - - GamepadFocusManagerOnFocused((Control)e.NewFocus); - } - - private void GamepadWindow_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) - { - // do something - } - - private bool TryGoBack() - { - if (!ContentFrame.CanGoBack) - return false; - - // Don't go back if the nav pane is overlayed. - if (navView.IsPaneOpen && - (navView.DisplayMode == NavigationViewDisplayMode.Compact || - navView.DisplayMode == NavigationViewDisplayMode.Minimal)) - return false; - - ContentFrame.GoBack(); - return true; - } - - private void On_Navigated(object sender, NavigationEventArgs e) - { - navView.IsBackEnabled = ContentFrame.CanGoBack; - - if (ContentFrame.SourcePageType is not null) - { - CurrentPageName = ContentFrame.CurrentSourcePageType.Name; - - var NavViewItem = navView.MenuItems - .OfType() - .Where(n => n.Tag.Equals(CurrentPageName)).FirstOrDefault(); - - if (!(NavViewItem is null)) - navView.SelectedItem = NavViewItem; - - navView.Header = new TextBlock() { Text = (string)((Page)e.Content).Title }; - } - } - - #endregion -} + #endregion +} diff --git a/redist/RTSSSetup735Beta5.exe b/redist/RTSSSetup735Beta5.exe deleted file mode 100644 index d39579399..000000000 Binary files a/redist/RTSSSetup735Beta5.exe and /dev/null differ diff --git a/utils/Utils.iss b/utils/Utils.iss index 1ace4e7bb..3c839b6dc 100644 --- a/utils/Utils.iss +++ b/utils/Utils.iss @@ -29,7 +29,7 @@ end; function isHidHideInstalled():boolean; begin result:= false; - if(FileExists(ExpandConstant('{commonpf}') + '\Nefarius Software Solutions\HidHide\HidHide_Updater.exe')) then + if(FileExists(ExpandConstant('{commonpf}') + '\Nefarius Software Solutions\HidHide\x64\HidHideClient.exe')) then begin log('HidHide is already installed.'); result:= true; @@ -42,7 +42,7 @@ var versionNumber, filePath:string; begin result:= ''; - filePath:= ExpandConstant('{commonpf}') + '\Nefarius Software Solutions\HidHide\HidHide_Updater.exe'; + filePath:= ExpandConstant('{commonpf}') + '\Nefarius Software Solutions\HidHide\x64\HidHideClient.exe'; if(FileExists(filePath)) then begin