diff --git a/HandheldCompanion.iss b/HandheldCompanion.iss index c89379e23..6b9984b50 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.22.0.2' +#define MyAppVersion '0.22.0.3' #define MyAppPublisher 'BenjaminLSR' #define MyAppCopyright 'Copyright @ BenjaminLSR' #define MyAppURL 'https://github.com/Valkirie/HandheldCompanion' diff --git a/HandheldCompanion/Commands/Functions/Windows/OnScreenKeyboardLegacyCommands.cs b/HandheldCompanion/Commands/Functions/Windows/OnScreenKeyboardLegacyCommands.cs index a838284c0..649580864 100644 --- a/HandheldCompanion/Commands/Functions/Windows/OnScreenKeyboardLegacyCommands.cs +++ b/HandheldCompanion/Commands/Functions/Windows/OnScreenKeyboardLegacyCommands.cs @@ -40,7 +40,7 @@ public override void Execute(bool IsKeyDown, bool IsKeyUp, bool IsBackground) { // Start a new osk.exe process Process OSK = Process.Start(new ProcessStartInfo("osk.exe") { UseShellExecute = true, WindowStyle = ProcessWindowStyle.Hidden }); - await Task.Delay(200); + await Task.Delay(200).ConfigureAwait(false); // Avoid blocking the synchronization context // Find the OSK window. IntPtr hwndOSK = FindWindow("OSKMainClass", null); diff --git a/HandheldCompanion/Controllers/GordonController.cs b/HandheldCompanion/Controllers/GordonController.cs index 1682afcf8..5f15a5a2b 100644 --- a/HandheldCompanion/Controllers/GordonController.cs +++ b/HandheldCompanion/Controllers/GordonController.cs @@ -221,16 +221,16 @@ public override void UpdateInputs(long ticks, float delta) base.UpdateInputs(ticks, delta); } - private async Task OnControllerInputReceived(GordonControllerInputEventArgs input) - { - this.input = input; - } public override void Plug() { try { - Controller.OnControllerInputReceived = input => OnControllerInputReceived(input); + Controller.OnControllerInputReceived += input => + { + this.input = input; + return Task.CompletedTask; + }; // open controller Open(); diff --git a/HandheldCompanion/Controllers/IController.cs b/HandheldCompanion/Controllers/IController.cs index 7726a2208..00246feb1 100644 --- a/HandheldCompanion/Controllers/IController.cs +++ b/HandheldCompanion/Controllers/IController.cs @@ -300,7 +300,7 @@ public virtual void Rumble(int delay = 125, byte LargeMotor = byte.MaxValue, byt rumbleTask = Task.Run(async () => { SetVibration(LargeMotor, SmallMotor); - await Task.Delay(delay); + await Task.Delay(delay).ConfigureAwait(false); // Avoid blocking the synchronization context SetVibration(0, 0); }); } @@ -365,7 +365,7 @@ public virtual void CyclePort() Task.Run(async () => { Details.Uninstall(false); - await Task.Delay(3000); + await Task.Delay(3000).ConfigureAwait(false); // Avoid blocking the synchronization context Devcon.Refresh(); }); break; diff --git a/HandheldCompanion/Controllers/NeptuneController.cs b/HandheldCompanion/Controllers/NeptuneController.cs index 749cf97d4..b7a2fb32d 100644 --- a/HandheldCompanion/Controllers/NeptuneController.cs +++ b/HandheldCompanion/Controllers/NeptuneController.cs @@ -260,16 +260,15 @@ private void Open() Controller.RequestLizardMode(false); // create handler - Controller.OnControllerInputReceived += input => OnControllerInputReceived(input); + Controller.OnControllerInputReceived += input => + { + this.input = input; + return Task.CompletedTask; + }; } catch { } } - private async Task OnControllerInputReceived(NeptuneControllerInputEventArgs input) - { - this.input = input; - } - private void Close() { try @@ -394,7 +393,7 @@ private async void RumbleThreadLoop(object? obj) if (GetHapticIntensity(FeedbackSmallMotor, MinIntensity, MaxIntensity, out var rightIntensity)) Controller.SetHaptic2(SCHapticMotor.Right, NCHapticStyle.Weak, rightIntensity); - await Task.Delay(TimerManager.GetPeriod() * 2); + Thread.Sleep(TimerManager.GetPeriod() * 2); } } diff --git a/HandheldCompanion/Controls/Hints/Hint_SteamInput.cs b/HandheldCompanion/Controls/Hints/Hint_SteamInput.cs index 9c31284fa..9ee9fc285 100644 --- a/HandheldCompanion/Controls/Hints/Hint_SteamInput.cs +++ b/HandheldCompanion/Controls/Hints/Hint_SteamInput.cs @@ -51,7 +51,7 @@ protected override void HintActionButton_Click(object sender, RoutedEventArgs e) // halt steam and wait PlatformManager.Steam.StopProcess(); while (PlatformManager.Steam.IsRunning) - await Task.Delay(1000); + await Task.Delay(1000).ConfigureAwait(false); // Avoid blocking the synchronization context; // overwrite desktop layout PlatformManager.Steam.SetUseSteamControllerConfigValue(0); diff --git a/HandheldCompanion/Devices/ASUS/ROGAlly.cs b/HandheldCompanion/Devices/ASUS/ROGAlly.cs index 544dff1d0..b9ba72fcf 100644 --- a/HandheldCompanion/Devices/ASUS/ROGAlly.cs +++ b/HandheldCompanion/Devices/ASUS/ROGAlly.cs @@ -504,10 +504,10 @@ private void HandleEvent(byte key) case 56: // Armory crate: Click case 166: // Command center: Click { - Task.Factory.StartNew(async () => + Task.Run(async () => { KeyPress(button); - await Task.Delay(KeyPressDelay); + await Task.Delay(KeyPressDelay).ConfigureAwait(false); // Avoid blocking the synchronization context KeyRelease(button); }); } diff --git a/HandheldCompanion/Devices/MSI/ClawA1M.cs b/HandheldCompanion/Devices/MSI/ClawA1M.cs index 21175a797..98287290a 100644 --- a/HandheldCompanion/Devices/MSI/ClawA1M.cs +++ b/HandheldCompanion/Devices/MSI/ClawA1M.cs @@ -213,10 +213,10 @@ private void onWMIEvent(object sender, EventArrivedEventArgs e) case WMIEventCode.LaunchMcxMainUI: // MSI Claw: Click case WMIEventCode.LaunchMcxOSD: // Quick Settings: Click { - Task.Factory.StartNew(async () => + Task.Run(async () => { KeyPress(button); - await Task.Delay(KeyPressDelay); + await Task.Delay(KeyPressDelay).ConfigureAwait(false); // Avoid blocking the synchronization context KeyRelease(button); }); } diff --git a/HandheldCompanion/HandheldCompanion.csproj b/HandheldCompanion/HandheldCompanion.csproj index 45ccedd6d..ddb7b6d18 100644 --- a/HandheldCompanion/HandheldCompanion.csproj +++ b/HandheldCompanion/HandheldCompanion.csproj @@ -12,11 +12,12 @@ HandheldCompanion.App $(SolutionDir)bin\$(Configuration) Resources\icon.ico - 0.22.0.2 + 0.22.0.3 app.manifest AnyCPU;x64;x86 true Always + true diff --git a/HandheldCompanion/Inputs/AxisState.cs b/HandheldCompanion/Inputs/AxisState.cs index 59bc4c904..0e4e9c51e 100644 --- a/HandheldCompanion/Inputs/AxisState.cs +++ b/HandheldCompanion/Inputs/AxisState.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -8,9 +9,9 @@ namespace HandheldCompanion.Inputs; [Serializable] public partial class AxisState : ICloneable { - public Dictionary State = new(); + public ConcurrentDictionary State = new(); - public AxisState(Dictionary State) + public AxisState(ConcurrentDictionary State) { foreach (var state in State) this[state.Key] = state.Value; @@ -24,7 +25,7 @@ public AxisState() public short this[AxisFlags axis] { - get => !State.ContainsKey(axis) ? (short)0 : State[axis]; + get => State.TryGetValue(axis, out short value) ? value : (short)0; set => State[axis] = value; } @@ -77,8 +78,8 @@ public override bool Equals(object obj) return false; } - public static bool EqualsWithValues(Dictionary obj1, - Dictionary obj2) + public static bool EqualsWithValues(ConcurrentDictionary obj1, + ConcurrentDictionary obj2) { if (obj1.Count != obj2.Count) return false; { diff --git a/HandheldCompanion/Inputs/ButtonState.cs b/HandheldCompanion/Inputs/ButtonState.cs index 6372cb2f5..d840502ff 100644 --- a/HandheldCompanion/Inputs/ButtonState.cs +++ b/HandheldCompanion/Inputs/ButtonState.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -8,9 +9,9 @@ namespace HandheldCompanion.Inputs; [Serializable] public partial class ButtonState : ICloneable { - public Dictionary State = new(); + public ConcurrentDictionary State = new(); - public ButtonState(Dictionary State) + public ButtonState(ConcurrentDictionary State) { foreach (var state in State) this[state.Key] = state.Value; @@ -24,7 +25,7 @@ public ButtonState() public bool this[ButtonFlags button] { - get => State.ContainsKey(button) && State[button]; + get => State.TryGetValue(button, out bool value) && value; set => State[button] = value; } diff --git a/HandheldCompanion/Managers/ControllerManager.cs b/HandheldCompanion/Managers/ControllerManager.cs index d6fe6c96f..56c585bad 100644 --- a/HandheldCompanion/Managers/ControllerManager.cs +++ b/HandheldCompanion/Managers/ControllerManager.cs @@ -413,7 +413,7 @@ private static async void HidDeviceArrived(PnPDetails details, Guid InterfaceGui } catch { - await Task.Delay(1000); + await Task.Delay(1000).ConfigureAwait(false); // Avoid blocking the synchronization context } } @@ -600,7 +600,7 @@ private static async void HidDeviceArrived(PnPDetails details, Guid InterfaceGui } while (!controller.IsReady && controller.IsConnected()) - await Task.Delay(250); + await Task.Delay(250).ConfigureAwait(false); // Avoid blocking the synchronization context // set (un)busy controller.IsBusy = false; @@ -640,7 +640,7 @@ private static async void HidDeviceRemoved(PnPDetails details, Guid IntefaceGuid if (Controllers.TryGetValue(details.baseContainerDeviceInstanceId, out controller)) break; - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context } if (controller is null) @@ -693,7 +693,7 @@ private static void watchdogThreadLoop(object? obj) foreach (XInputController xInputController in Controllers.Values.Where(c => c.Details is not null && c.Details.isXInput)) { - byte UserIndex = DeviceManager.GetXInputIndexAsync(xInputController.Details.baseContainerDevicePath); + byte UserIndex = DeviceManager.GetXInputIndexAsync(xInputController.Details.baseContainerDevicePath, true); // controller is not ready yet if (UserIndex == byte.MaxValue) @@ -882,7 +882,7 @@ private static async void XUsbDeviceArrived(PnPDetails details, Guid IntefaceGui } while (!controller.IsReady && controller.IsConnected()) - await Task.Delay(250); + await Task.Delay(250).ConfigureAwait(false); // Avoid blocking the synchronization context // set (un)busy controller.IsBusy = false; @@ -932,7 +932,7 @@ private static async void XUsbDeviceRemoved(PnPDetails details, Guid IntefaceGui if (Controllers.TryGetValue(details.baseContainerDeviceInstanceId, out controller)) break; - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context } if (controller is null) diff --git a/HandheldCompanion/Managers/DeviceManager.cs b/HandheldCompanion/Managers/DeviceManager.cs index 5a09bbccc..0f2dd0830 100644 --- a/HandheldCompanion/Managers/DeviceManager.cs +++ b/HandheldCompanion/Managers/DeviceManager.cs @@ -501,7 +501,7 @@ private static void XUsbDevice_DeviceRemoved(DeviceEventArgs obj) while (DateTime.Now < timeout && deviceEx is null) { deviceEx = FindDevice(InstanceId); - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context } if (deviceEx is null) @@ -533,7 +533,7 @@ private static void XUsbDevice_DeviceArrived(DeviceEventArgs obj) while (DateTime.Now < timeout && deviceEx is null) { deviceEx = FindDevice(InstanceId); - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context } if (deviceEx is not null && deviceEx.isGaming) @@ -542,7 +542,7 @@ private static void XUsbDevice_DeviceArrived(DeviceEventArgs obj) deviceEx.baseContainerDevicePath = obj.SymLink; if (deviceEx.EnumeratorName.Equals("USB")) - deviceEx.XInputUserIndex = GetXInputIndexAsync(obj.SymLink); + deviceEx.XInputUserIndex = GetXInputIndexAsync(obj.SymLink, false); if (deviceEx.XInputUserIndex == byte.MaxValue) deviceEx.XInputDeviceIdx = GetDeviceIndex(obj.SymLink); @@ -576,7 +576,7 @@ private static void HidDevice_DeviceRemoved(DeviceEventArgs obj) while (DateTime.Now < timeout && deviceEx is null) { deviceEx = FindDevice(InstanceId); - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context } // skip if XInput @@ -610,7 +610,7 @@ private static void HidDevice_DeviceArrived(DeviceEventArgs obj) while (DateTime.Now < timeout && deviceEx is null) { deviceEx = GetDetails(obj.SymLink); - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context } // skip if XInput @@ -662,7 +662,7 @@ private static void UsbDevice_DeviceArrived(DeviceEventArgs obj) } } - public static byte GetXInputIndexAsync(string SymLink) + public static byte GetXInputIndexAsync(string SymLink, bool UIthread) { byte ledState = 0; @@ -684,7 +684,7 @@ public static byte GetXInputIndexAsync(string SymLink) ledState = ledStateData[2]; } - Task.Delay(1000); + Task.Delay(1000).ConfigureAwait(UIthread); } return XINPUT_LED_TO_PORT_MAP[ledState]; diff --git a/HandheldCompanion/Managers/DynamicLightingManager.cs b/HandheldCompanion/Managers/DynamicLightingManager.cs index 07e248be6..8823b7e7a 100644 --- a/HandheldCompanion/Managers/DynamicLightingManager.cs +++ b/HandheldCompanion/Managers/DynamicLightingManager.cs @@ -143,7 +143,7 @@ private static async void InitializeDirect3DDevice() if (ex.ResultCode == ResultCode.DeviceLost) { while (device is not null && device.TestCooperativeLevel() == ResultCode.DeviceLost) - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context // Recreate the device and resources ReleaseDirect3DDevice(); diff --git a/HandheldCompanion/Managers/GPUManager.cs b/HandheldCompanion/Managers/GPUManager.cs index ab4372e3b..9c6af5d39 100644 --- a/HandheldCompanion/Managers/GPUManager.cs +++ b/HandheldCompanion/Managers/GPUManager.cs @@ -185,7 +185,7 @@ private static void GPUDisconnect(GPU GPU) private static void MultimediaManager_PrimaryScreenChanged(DesktopScreen screen) { AdapterInformation key = DisplayGPU.Keys.FirstOrDefault(GPU => GPU.Details.DeviceName == screen.screen.DeviceName); - if (DisplayGPU.TryGetValue(key, out GPU gpu)) + if (key is not null && DisplayGPU.TryGetValue(key, out GPU gpu)) { LogManager.LogError("Retrieved DisplayAdapter: {0} for screen: {1}", gpu.ToString(), screen.screen.DeviceName); diff --git a/HandheldCompanion/Managers/HotkeysManager.cs b/HandheldCompanion/Managers/HotkeysManager.cs index 4443b660c..44c83db1a 100644 --- a/HandheldCompanion/Managers/HotkeysManager.cs +++ b/HandheldCompanion/Managers/HotkeysManager.cs @@ -46,8 +46,9 @@ public static async Task Start() ProcessHotkey(fileName); // get latest known version + // if last time HC version used old hotkey engine and user has no defined hotkeys Version LastVersion = Version.Parse(SettingsManager.GetString("LastVersion")); - if (LastVersion < Version.Parse(Settings.VersionHotkeyManager)) + if (LastVersion < Version.Parse(Settings.VersionHotkeyManager) && hotkeys.Count == 0) { // create a few defaults hotkeys if (!hotkeys.Values.Any(hotkey => hotkey.command is QuickToolsCommands quickToolsCommands)) @@ -152,6 +153,12 @@ private static void ProcessHotkey(string fileName) // too old throw new Exception("Hotkey is outdated."); } + else if (version <= Version.Parse("0.22.0.2")) + { + outputraw = outputraw.Replace( + "\"System.Collections.Generic.Dictionary`2[[HandheldCompanion.Inputs.ButtonFlags, HandheldCompanion],[System.Boolean, System.Private.CoreLib]], System.Private.CoreLib\"", + "\"System.Collections.Concurrent.ConcurrentDictionary`2[[HandheldCompanion.Inputs.ButtonFlags, HandheldCompanion],[System.Boolean, System.Private.CoreLib]], System.Collections.Concurrent\""); + } else if (version <= Version.Parse("0.21.8.0")) { outputraw = outputraw.Replace( @@ -178,9 +185,16 @@ private static void ProcessHotkey(string fileName) if (hotkey is null) return; - if (CheckAvailableButtonFlag(hotkey.ButtonFlags)) + // check if button flags is already used + if (IsUsedButtonFlag(hotkey.ButtonFlags)) + { + // update button flags hotkey.ButtonFlags = GetAvailableButtonFlag(); + // Delete the old file + File.Delete(fileName); + } + if (hotkey.ButtonFlags == ButtonFlags.None) return; @@ -281,16 +295,19 @@ private static void ProcessHotkey(string fileName) var isPinned = (bool)dictionary["IsPinned"]; hotkey.IsPinned = isPinned; - // Common ButtonFlags check - if (CheckAvailableButtonFlag(hotkey.ButtonFlags)) + // check if button flags is already used + if (IsUsedButtonFlag(hotkey.ButtonFlags)) + { + // update button flags hotkey.ButtonFlags = GetAvailableButtonFlag(); + // Delete the old file + File.Delete(fileName); + } + if (hotkey.ButtonFlags == ButtonFlags.None) return null; - // Delete the old file - File.Delete(fileName); - // Save new hotkey json SerializeHotkey(hotkey); @@ -301,7 +318,7 @@ private static void ProcessHotkey(string fileName) return null; } - private static bool CheckAvailableButtonFlag(ButtonFlags buttonFlags) + private static bool IsUsedButtonFlag(ButtonFlags buttonFlags) { HashSet usedFlags = hotkeys.Values.Select(h => h.ButtonFlags).ToHashSet(); return usedFlags.Contains(buttonFlags); diff --git a/HandheldCompanion/Managers/PerformanceManager.cs b/HandheldCompanion/Managers/PerformanceManager.cs index d038e0735..ec1599564 100644 --- a/HandheldCompanion/Managers/PerformanceManager.cs +++ b/HandheldCompanion/Managers/PerformanceManager.cs @@ -664,7 +664,7 @@ private static async void tdpWatchdog_Elapsed(object? sender, ElapsedEventArgs e if (ReadTDP != TDP || forcedUpdate) RequestTDP((PowerType)idx, TDP, true); - await Task.Delay(20); + await Task.Delay(20).ConfigureAwait(false); // Avoid blocking the synchronization context } // are we done ? @@ -858,7 +858,7 @@ private static async void RequestTDP(double[] values, bool immediate = false) for (int idx = (int)PowerType.Slow; idx <= (int)PowerType.Fast; idx++) { RequestTDP((PowerType)idx, values[idx], immediate); - await Task.Delay(20); + await Task.Delay(20).ConfigureAwait(false); // Avoid blocking the synchronization context } } diff --git a/HandheldCompanion/Managers/ProcessManager.cs b/HandheldCompanion/Managers/ProcessManager.cs index 54d3864ee..22a50109e 100644 --- a/HandheldCompanion/Managers/ProcessManager.cs +++ b/HandheldCompanion/Managers/ProcessManager.cs @@ -510,7 +510,7 @@ public static async void ResumeProcess(ProcessEx processEx) ProcessUtils.NtResumeProcess(process.Handle); }); - await Task.Delay(500); + await Task.Delay(500).ConfigureAwait(false); // Avoid blocking the synchronization context // restore process windows foreach (ProcessWindow processWindow in processEx.ProcessWindows.Values) @@ -527,7 +527,7 @@ public static async void SuspendProcess(ProcessEx processEx) foreach (ProcessWindow processWindow in processEx.ProcessWindows.Values) ProcessUtils.ShowWindow(processWindow.Hwnd, (int)ProcessUtils.ShowWindowCommands.Hide); - await Task.Delay(500); + await Task.Delay(500).ConfigureAwait(false); // Avoid blocking the synchronization context ProcessUtils.NtSuspendProcess(processEx.Process.Handle); diff --git a/HandheldCompanion/Managers/ProfileManager.cs b/HandheldCompanion/Managers/ProfileManager.cs index 3bc6f9432..268301ae7 100644 --- a/HandheldCompanion/Managers/ProfileManager.cs +++ b/HandheldCompanion/Managers/ProfileManager.cs @@ -517,6 +517,12 @@ private static void ProcessProfile(string fileName, bool imported = false) { // too old throw new Exception("Profile is outdated."); + } + else if (version <= Version.Parse("0.22.0.2")) + { + outputraw = outputraw.Replace( + "\"System.Collections.Generic.Dictionary`2[[HandheldCompanion.Inputs.ButtonFlags, HandheldCompanion],[System.Boolean, System.Private.CoreLib]], System.Private.CoreLib\"", + "\"System.Collections.Concurrent.ConcurrentDictionary`2[[HandheldCompanion.Inputs.ButtonFlags, HandheldCompanion],[System.Boolean, System.Private.CoreLib]], System.Collections.Concurrent\""); } else if (version <= Version.Parse("0.21.7.0")) { diff --git a/HandheldCompanion/Managers/SensorsManager.cs b/HandheldCompanion/Managers/SensorsManager.cs index 35e4b6cc6..14b0bf60d 100644 --- a/HandheldCompanion/Managers/SensorsManager.cs +++ b/HandheldCompanion/Managers/SensorsManager.cs @@ -293,7 +293,7 @@ public static async void Calibrate(Dictionary gamepadMotion for (int i = 4; i > 0; i--) { dialog.UpdateContent($"Calibration will start in {i} seconds."); - await Task.Delay(1000); + await Task.Delay(1000); // Captures synchronization context } foreach (GamepadMotion gamepadMotion in gamepadMotions.Values) @@ -306,7 +306,7 @@ public static async void Calibrate(Dictionary gamepadMotion // wait until device is steady DateTime timeout = DateTime.Now.Add(TimeSpan.FromSeconds(3)); while (DateTime.Now < timeout && !gamepadMotion.GetAutoCalibrationIsSteady()) - await Task.Delay(100); + await Task.Delay(100); // Captures synchronization context // device is either too shaky or stalled bool IsSteady = gamepadMotion.GetAutoCalibrationIsSteady(); @@ -321,7 +321,7 @@ public static async void Calibrate(Dictionary gamepadMotion dialog.UpdateContent($"Calibration device is silent or unsteady."); // wait a bit - await Task.Delay(2000); + await Task.Delay(2000); // Captures synchronization context break; } @@ -332,7 +332,7 @@ public static async void Calibrate(Dictionary gamepadMotion // give gamepad motion 3 seconds to get values timeout = DateTime.Now.Add(TimeSpan.FromSeconds(3)); while (DateTime.Now < timeout) - await Task.Delay(100); + await Task.Delay(100); // Captures synchronization context // halt continuous calibration gamepadMotion.PauseContinuousCalibration(); @@ -377,7 +377,7 @@ public static async void Calibrate(Dictionary gamepadMotion dialog.UpdateContent($"Calibration succeeded: stationary sensor noise recorded. Drift correction found. Confidence: {confidence * 100.0f}%"); // wait a bit - await Task.Delay(2000); + await Task.Delay(2000); // Captures synchronization context } Close: diff --git a/HandheldCompanion/Managers/ToastManager.cs b/HandheldCompanion/Managers/ToastManager.cs index 113661448..6ed4b5ad9 100644 --- a/HandheldCompanion/Managers/ToastManager.cs +++ b/HandheldCompanion/Managers/ToastManager.cs @@ -73,6 +73,7 @@ public static void SendToast(string title, string content = "", string img = "To } }); + ToastThread.IsBackground = true; ToastThread.Start(); } diff --git a/HandheldCompanion/Managers/VirtualManager.cs b/HandheldCompanion/Managers/VirtualManager.cs index 8cd354068..4615d7573 100644 --- a/HandheldCompanion/Managers/VirtualManager.cs +++ b/HandheldCompanion/Managers/VirtualManager.cs @@ -164,7 +164,7 @@ private static async void ProfileManager_Applied(Profile profile, UpdateSource s return; while (ControllerManager.managerStatus == ControllerManagerStatus.Busy) - await Task.Delay(1000); + await Task.Delay(1000).ConfigureAwait(false); // Avoid blocking the synchronization context switch (profile.HID) { @@ -184,7 +184,7 @@ private static async void ProfileManager_Discarded(Profile profile, bool swapped return; while (ControllerManager.managerStatus == ControllerManagerStatus.Busy) - await Task.Delay(1000); + await Task.Delay(1000).ConfigureAwait(false); // Avoid blocking the synchronization context // restore default HID mode if (profile.HID != HIDmode.NotSelected) diff --git a/HandheldCompanion/Platforms/LibreHardwareMonitor.cs b/HandheldCompanion/Platforms/LibreHardwareMonitor.cs index 2821ce7ee..5971bcc8e 100644 --- a/HandheldCompanion/Platforms/LibreHardwareMonitor.cs +++ b/HandheldCompanion/Platforms/LibreHardwareMonitor.cs @@ -8,7 +8,6 @@ namespace HandheldCompanion.Platforms public class LibreHardwareMonitor : IPlatform { private Computer computer; - private string ProductName; private Timer updateTimer; private int updateInterval = 1000; @@ -30,8 +29,6 @@ public LibreHardwareMonitor() Name = "LibreHardwareMonitor"; IsInstalled = true; - ProductName = MotherboardInfo.Product; - // watchdog to populate sensors updateTimer = new Timer(updateInterval) { Enabled = false }; updateTimer.Elapsed += UpdateTimer_Elapsed; @@ -175,15 +172,6 @@ private void HandleCPU_Temperatur(ISensor sensor) if (sensor.Name == "CPU Package" || sensor.Name == "Core (Tctl/Tdie)") { CPUTemperatur = (float)sensor.Value; - - // dirty - switch (ProductName) - { - case "Galileo": - CPUTemperatur /= 2.0f; - break; - } - CPUTemperatureChanged?.Invoke(CPUTemperatur); } } diff --git a/HandheldCompanion/Platforms/RTSS.cs b/HandheldCompanion/Platforms/RTSS.cs index 1837fb48c..f199f6484 100644 --- a/HandheldCompanion/Platforms/RTSS.cs +++ b/HandheldCompanion/Platforms/RTSS.cs @@ -194,7 +194,7 @@ private async void ProcessManager_ForegroundChanged(ProcessEx? processEx, Proces } catch { } - await Task.Delay(1000); + await Task.Delay(1000).ConfigureAwait(false); // Avoid blocking the synchronization context } while (appEntry is null && foregroundId == ProcessId && KeepAlive); if (appEntry is null) diff --git a/HandheldCompanion/Platforms/Steam.cs b/HandheldCompanion/Platforms/Steam.cs index 0f02daf72..2a8bef03e 100644 --- a/HandheldCompanion/Platforms/Steam.cs +++ b/HandheldCompanion/Platforms/Steam.cs @@ -97,7 +97,7 @@ private void ActiveUserWatcher_RegistryChanged(object? sender, RegistryChangedEv private async void ActiveFileWatch_Changed() { - await Task.Delay(1000); + await Task.Delay(1000).ConfigureAwait(false); // Avoid blocking the synchronization context int SteamInput = GetUseSteamControllerConfigValue(); base.SettingsValueChaned("UseSteamControllerConfig", SteamInput); } diff --git a/HandheldCompanion/Sensors/SerialUSBIMU.cs b/HandheldCompanion/Sensors/SerialUSBIMU.cs index 5aec3a058..a0a8817f0 100644 --- a/HandheldCompanion/Sensors/SerialUSBIMU.cs +++ b/HandheldCompanion/Sensors/SerialUSBIMU.cs @@ -143,7 +143,7 @@ public async void Open() tentative++; LogManager.LogError("{0} could not connect. Attempt: {1} out of {2}", serial.ToString(), tentative, maxTentative); - await Task.Delay(500); + await Task.Delay(500).ConfigureAwait(false); // Avoid blocking the synchronization context } } @@ -232,7 +232,7 @@ private async void DataReceivedHandler(object sender, SerialDataReceivedEventArg return; } - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context // Address write function code register = 0xA4, 0x03 // Register to read/write save settings 0x05 diff --git a/HandheldCompanion/UI/UIGamepad.cs b/HandheldCompanion/UI/UIGamepad.cs index 71a5a5af6..69273f304 100644 --- a/HandheldCompanion/UI/UIGamepad.cs +++ b/HandheldCompanion/UI/UIGamepad.cs @@ -145,6 +145,7 @@ private void _currentWindow_GotFocus(object sender, RoutedEventArgs e) _focused[window] = false; // raise event + LostFocus?.Invoke(window); } } @@ -620,8 +621,7 @@ private void InputsUpdated(ControllerState controllerState) { // get the associated ComboBox comboBox = ItemsControl.ItemsControlFromItemContainer(focusedElement) as ComboBox; - - if (comboBox.IsDropDownOpen && comboBoxItem.IsEnabled) + if (comboBox is not null && comboBox.IsDropDownOpen && comboBoxItem.IsEnabled) { int idx = comboBox.Items.IndexOf(comboBoxItem); if (idx == -1) @@ -719,8 +719,8 @@ private void InputsUpdated(ControllerState controllerState) case "ComboBoxItem": { - ComboBox comboBox = ItemsControl.ItemsControlFromItemContainer(focusedElement) as ComboBox; - comboBox.IsDropDownOpen = false; + if (ItemsControl.ItemsControlFromItemContainer(focusedElement) is ComboBox comboBox) + comboBox.IsDropDownOpen = false; } return; @@ -876,45 +876,47 @@ private void InputsUpdated(ControllerState controllerState) { if (focusedElement is ComboBoxItem comboBoxItem) { - ComboBox comboBox = ItemsControl.ItemsControlFromItemContainer(focusedElement) as ComboBox; - if (comboBox.IsDropDownOpen) + if (ItemsControl.ItemsControlFromItemContainer(focusedElement) is ComboBox comboBox) { - int idx = comboBox.Items.IndexOf(comboBoxItem); - if (idx == -1) - idx = comboBox.Items.IndexOf(comboBoxItem.Content); - - while (true) // Loop to skip disabled items + if (comboBox.IsDropDownOpen) { - switch (direction) + int idx = comboBox.Items.IndexOf(comboBoxItem); + if (idx == -1) + idx = comboBox.Items.IndexOf(comboBoxItem.Content); + + while (true) // Loop to skip disabled items { - case WPFUtils.Direction.Up: - idx--; + switch (direction) + { + case WPFUtils.Direction.Up: + idx--; + break; + + case WPFUtils.Direction.Down: + idx++; + break; + } + + // Ensure index is within bounds + if (idx < 0 || idx >= comboBox.Items.Count) + { + // We've reached the top or bottom, so stop the loop break; + } - case WPFUtils.Direction.Down: - idx++; - break; - } + // Get the ComboBoxItem at the new index + focusedElement = (ComboBoxItem)comboBox.ItemContainerGenerator.ContainerFromIndex(idx); - // Ensure index is within bounds - if (idx < 0 || idx >= comboBox.Items.Count) - { - // We've reached the top or bottom, so stop the loop - break; - } - - // Get the ComboBoxItem at the new index - focusedElement = (ComboBoxItem)comboBox.ItemContainerGenerator.ContainerFromIndex(idx); + // Check if the focused element is enabled + if (focusedElement != null && focusedElement.IsEnabled) + { + // If the element is enabled, focus it and break out of the loop + Focus(focusedElement, comboBox, true); + break; + } - // Check if the focused element is enabled - if (focusedElement != null && focusedElement.IsEnabled) - { - // If the element is enabled, focus it and break out of the loop - Focus(focusedElement, comboBox, true); - break; + // If the element is not enabled, continue to the next item in the loop } - - // If the element is not enabled, continue to the next item in the loop } } return; diff --git a/HandheldCompanion/UI/UISounds.cs b/HandheldCompanion/UI/UISounds.cs index e51a82875..76fed7394 100644 --- a/HandheldCompanion/UI/UISounds.cs +++ b/HandheldCompanion/UI/UISounds.cs @@ -62,7 +62,7 @@ private static async void SoundTimer_Elapsed(object? sender, ElapsedEventArgs e) // wait here until playback stops or should stop while (waveOut.PlaybackState == PlaybackState.Playing) - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); // Avoid blocking the synchronization context } } } diff --git a/HandheldCompanion/ViewModels/HotkeyViewModel.cs b/HandheldCompanion/ViewModels/HotkeyViewModel.cs index 5c89699cf..04abbc0ab 100644 --- a/HandheldCompanion/ViewModels/HotkeyViewModel.cs +++ b/HandheldCompanion/ViewModels/HotkeyViewModel.cs @@ -466,7 +466,7 @@ public HotkeyViewModel(Hotkey hotkey) { // todo: improve me // we need to make sure the key that was pressed to trigger the listening event isn't recorded - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context InputsManager.StartListening(hotkey.ButtonFlags, InputsChordTarget.Input); }); @@ -485,7 +485,7 @@ public HotkeyViewModel(Hotkey hotkey) { // todo: improve me // we need to make sure the key that was pressed to trigger the listening event isn't recorded - await Task.Delay(100); + await Task.Delay(100).ConfigureAwait(false); // Avoid blocking the synchronization context InputsManager.StartListening(hotkey.ButtonFlags, InputsChordTarget.Output); }); diff --git a/HandheldCompanion/Views/Pages/ControllerPage.xaml.cs b/HandheldCompanion/Views/Pages/ControllerPage.xaml.cs index 28faaad14..53404c8de 100644 --- a/HandheldCompanion/Views/Pages/ControllerPage.xaml.cs +++ b/HandheldCompanion/Views/Pages/ControllerPage.xaml.cs @@ -151,7 +151,7 @@ private void ControllerManager_Working(ControllerManagerStatus status, int attem case ControllerManagerStatus.Succeeded: { dialog.UpdateContent(Properties.Resources.ControllerPage_ControllerManagment_Done); - await Task.Delay(2000); + await Task.Delay(2000); // Captures synchronization context dialog.Hide(); } break; diff --git a/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs b/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs index 9c9cb8f82..12f82ed37 100644 --- a/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs +++ b/HandheldCompanion/Views/Pages/SettingsPage.xaml.cs @@ -410,7 +410,10 @@ private void UpdateManager_Updated(UpdateStatus status, UpdateFile updateFile, o private void B_CheckUpdate_Click(object? sender, RoutedEventArgs? e) { - new Thread(() => { UpdateManager.StartProcess(); }).Start(); + new Thread(() => + { + UpdateManager.StartProcess(); + }).Start(); } private void cB_Language_SelectionChanged(object? sender, SelectionChangedEventArgs? e) @@ -579,8 +582,8 @@ private void cB_QuickToolsDevicePath_SelectionChanged(object sender, SelectionCh if (cB_QuickToolsDevicePath.SelectedItem is DesktopScreen desktopScreen) { - SettingsManager.SetProperty("QuickToolsDevicePath", desktopScreen.DevicePath); SettingsManager.SetProperty("QuickToolsDeviceName", desktopScreen.FriendlyName); + SettingsManager.SetProperty("QuickToolsDevicePath", desktopScreen.DevicePath); } } } \ No newline at end of file diff --git a/HandheldCompanion/Views/SplashScreen.xaml b/HandheldCompanion/Views/SplashScreen.xaml index 64bd50c85..2e2aae93c 100644 --- a/HandheldCompanion/Views/SplashScreen.xaml +++ b/HandheldCompanion/Views/SplashScreen.xaml @@ -12,8 +12,6 @@ Height="450" ui:ThemeManager.IsThemeAware="True" ui:WindowHelper.SystemBackdropType="Mica" - ui:WindowHelper.UseAcrylicBackdrop="True" - ui:WindowHelper.UseAeroBackdrop="True" ui:WindowHelper.UseModernWindowStyle="True" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> @@ -30,10 +28,7 @@ Text="HC" TextAlignment="Center" /> - - - - + + Background="Red" + Foreground="White" /> diff --git a/HandheldCompanion/Views/Windows/MainWindow.xaml.cs b/HandheldCompanion/Views/Windows/MainWindow.xaml.cs index 16670ff12..cb3a9afcf 100644 --- a/HandheldCompanion/Views/Windows/MainWindow.xaml.cs +++ b/HandheldCompanion/Views/Windows/MainWindow.xaml.cs @@ -92,14 +92,11 @@ public MainWindow(FileVersionInfo _fileVersionInfo, Assembly CurrentAssembly) // get last version Version LastVersion = Version.Parse(SettingsManager.GetString("LastVersion")); - bool FirstStart = LastVersion == Version.Parse("0.0.0.0"); - if (FirstStart) - { + bool FirstStart = LastVersion == Version.Parse("0.0.0.0"); #if !DEBUG - SplashScreen.Show(); + SplashScreen.Show(); #endif - } - + InitializeComponent(); this.Tag = "MainWindow"; @@ -522,7 +519,7 @@ private async void OnSystemStatusChanged(SystemManager.SystemStatus status, Syst { // when device resumes from sleep // use device-specific delay - await Task.Delay(CurrentDevice.ResumeDelay); + await Task.Delay(CurrentDevice.ResumeDelay); // Captures synchronization context // resume manager(s) InputsManager.Start(); @@ -554,7 +551,7 @@ private async void OnSystemStatusChanged(SystemManager.SystemStatus status, Syst // when device goes to sleep // suspend manager(s) VirtualManager.Suspend(true); - await Task.Delay(CurrentDevice.ResumeDelay); + await Task.Delay(CurrentDevice.ResumeDelay); // Captures synchronization context TimerManager.Stop(); SensorsManager.Stop(); diff --git a/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml.cs b/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml.cs index f0d4bbcc5..53cb415a1 100644 --- a/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml.cs +++ b/HandheldCompanion/Views/Windows/OverlayQuickTools.xaml.cs @@ -230,6 +230,8 @@ private void UpdateLocation() // Find the corresponding Screen object targetScreen = Screen.AllScreens.FirstOrDefault(screen => screen.DeviceName.Equals(friendlyScreen.screen.DeviceName)); + if (targetScreen is null) + return; // UI thread Application.Current.Dispatcher.Invoke(() => diff --git a/HandheldCompanion/XInputPlus/XInputPlus.cs b/HandheldCompanion/XInputPlus/XInputPlus.cs index cd552ae2f..0d7eb50f1 100644 --- a/HandheldCompanion/XInputPlus/XInputPlus.cs +++ b/HandheldCompanion/XInputPlus/XInputPlus.cs @@ -146,7 +146,7 @@ private static async void ProcessManager_ProcessStarted(ProcessEx processEx, boo if (attempt == 10) return; - await Task.Delay(500); + await Task.Delay(500).ConfigureAwait(false); // Avoid blocking the synchronization context } bool x64bit = Is64bitProcess(processEx.Process); diff --git a/hidapi.net/HidDevice.cs b/hidapi.net/HidDevice.cs index e3d9db31e..81f0355ce 100644 --- a/hidapi.net/HidDevice.cs +++ b/hidapi.net/HidDevice.cs @@ -86,7 +86,7 @@ public byte[] Read(int timeout = 100) } public Task ReadAsync(byte[] data) => Task.Run(() => Read(data)); - public int Read(byte[] buffer, int timeout = 100) + public int Read(byte[] buffer, int timeout = 20) { if (buffer.Length < _inputBufferLen) throw new ArgumentException("Buffer length is lower than input buffer length."); @@ -161,7 +161,8 @@ public void BeginRead() _reading = true; _readThread = new Thread(new ThreadStart(ReadLoop)) { - IsBackground = true + IsBackground = true, + Priority = ThreadPriority.Highest }; _readThread.Start(); } diff --git a/hidapi.net/hidapi.dll b/hidapi.net/hidapi.dll index 02145e5d0..4eded6eeb 100644 Binary files a/hidapi.net/hidapi.dll and b/hidapi.net/hidapi.dll differ diff --git a/steam-hidapi.net/GordonController.cs b/steam-hidapi.net/GordonController.cs index 77036adba..bcc79a666 100644 --- a/steam-hidapi.net/GordonController.cs +++ b/steam-hidapi.net/GordonController.cs @@ -20,7 +20,11 @@ public GordonController(ushort vid, ushort pid, short index) : base(vid, pid, in { _hidDevice = new HidDevice(_vid, _pid, 64, index) { - OnInputReceived = input => Task.Run(() => OnInputReceived(input)) + OnInputReceived = input => + { + OnInputReceived(input); + return Task.CompletedTask; + } }; } diff --git a/steam-hidapi.net/NeptuneController.cs b/steam-hidapi.net/NeptuneController.cs index 017a5a73b..56201ede6 100644 --- a/steam-hidapi.net/NeptuneController.cs +++ b/steam-hidapi.net/NeptuneController.cs @@ -18,7 +18,11 @@ public NeptuneController(ushort vid, ushort pid, short index) : base(vid, pid, i { _hidDevice = new HidDevice(_vid, _pid, 64, index) { - OnInputReceived = input => Task.Run(() => OnInputReceived(input)) + OnInputReceived = input => + { + OnInputReceived(input); + return Task.CompletedTask; + } }; } @@ -76,7 +80,7 @@ internal async void ConfigureLoop() while (_active) { SetLizardMode(_lizard); - await Task.Delay(1000); + await Task.Delay(1000).ConfigureAwait(false); } }