diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 0a22a429f..7933b35bd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -14,6 +14,7 @@ labels: bug - [ ] GPD - [ ] ONEXPLAYER - [ ] VALVE +- [ ] LENOVO **Device model** Your device model diff --git a/HandheldCompanion/Controllers/NeptuneController.cs b/HandheldCompanion/Controllers/NeptuneController.cs index 9587c7685..6101451c6 100644 --- a/HandheldCompanion/Controllers/NeptuneController.cs +++ b/HandheldCompanion/Controllers/NeptuneController.cs @@ -346,6 +346,11 @@ public override void Unplug() base.Unplug(); } + public override void Cleanup() + { + TimerManager.Tick -= UpdateInputs; + } + public bool GetHapticIntensity(byte? input, sbyte minIntensity, sbyte maxIntensity, out sbyte output) { output = default; diff --git a/HandheldCompanion/Controls/Hints/Hint_HWiNFO12hLimitPassed.cs b/HandheldCompanion/Controls/Hints/Hint_HWiNFO12hLimitPassed.cs new file mode 100644 index 000000000..f91a4c092 --- /dev/null +++ b/HandheldCompanion/Controls/Hints/Hint_HWiNFO12hLimitPassed.cs @@ -0,0 +1,60 @@ +using HandheldCompanion.Managers; +using HandheldCompanion.Platforms; +using System; +using System.Windows; + +namespace HandheldCompanion.Controls.Hints +{ + public class Hint_HWiNFO12hLimitPassed : IHint + { + public Hint_HWiNFO12hLimitPassed() : base() + { + PlatformManager.HWiNFO.Updated += HWiNFO_Updated; + PlatformManager.HWiNFO.SettingValueChanged += HWiNFO_SettingValueChanged; + + PlatformManager.Initialized += PlatformManager_Initialized; + + // default state + this.HintActionButton.Visibility = Visibility.Collapsed; + + this.HintTitle.Text = Properties.Resources.Hint_HWiNFO12hLimitPassed; + this.HintDescription.Text = Properties.Resources.Hint_HWiNFO12hLimitPassedDesc; + this.HintReadMe.Text = Properties.Resources.Hint_HWiNFO12hLimitPassedReadme; + } + + private void HWiNFO_Updated(PlatformStatus status) + { + CheckSettings(); + } + + private void HWiNFO_SettingValueChanged(string name, object value) + { + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + switch(name) + { + case "SensorsSM": + this.Visibility = Convert.ToBoolean(value) ? Visibility.Collapsed : Visibility.Visible; + break; + } + }); + } + + private void PlatformManager_Initialized() + { + CheckSettings(); + } + + private void CheckSettings() + { + bool SensorsSM = PlatformManager.HWiNFO.GetProperty("SensorsSM"); + HWiNFO_SettingValueChanged("SensorsSM", SensorsSM); + } + + public override void Stop() + { + base.Stop(); + } + } +} diff --git a/HandheldCompanion/Controls/Hints/Hint_LegionGoDaemon.cs b/HandheldCompanion/Controls/Hints/Hint_LegionGoDaemon.cs new file mode 100644 index 000000000..72342fb53 --- /dev/null +++ b/HandheldCompanion/Controls/Hints/Hint_LegionGoDaemon.cs @@ -0,0 +1,81 @@ +using HandheldCompanion.Devices; +using HandheldCompanion.Views; +using Microsoft.Win32.TaskScheduler; +using System.Diagnostics; +using System.Linq; +using System.Timers; +using System.Windows; +using Task = System.Threading.Tasks.Task; + +namespace HandheldCompanion.Controls.Hints +{ + public class Hint_LegionGoDaemon : IHint + { + private Process process; + private const string taskName = "LSDaemon"; + private Timer taskTimer; + + public Hint_LegionGoDaemon() : base() + { + if (MainWindow.CurrentDevice is not LegionGo) + return; + + taskTimer = new Timer(4000); + taskTimer.Elapsed += TaskTimer_Elapsed; + taskTimer.Start(); + + // default state + this.HintActionButton.Visibility = Visibility.Visible; + + this.HintTitle.Text = Properties.Resources.Hint_LegionGoDaemon; + this.HintDescription.Text = Properties.Resources.Hint_LegionGoDaemonDesc; + this.HintReadMe.Text = Properties.Resources.Hint_LegionGoDaemonReadme; + + this.HintActionButton.Content = Properties.Resources.Hint_LegionGoDaemonAction; + } + + private void TaskTimer_Elapsed(object? sender, ElapsedEventArgs e) + { + // Get all the processes with the given name + process = Process.GetProcessesByName(taskName).FirstOrDefault(); + + // If there is at least one process, return true + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + if (process is not null && !process.HasExited) + this.Visibility = Visibility.Visible; + else + this.Visibility = Visibility.Collapsed; + }); + } + + protected override void HintActionButton_Click(object sender, RoutedEventArgs e) + { + Task.Run(async () => + { + // Get the task service instance + using (TaskService ts = new TaskService()) + { + // Get the task by name + Microsoft.Win32.TaskScheduler.Task task = ts.GetTask(taskName); + if (task != null && task.State == TaskState.Running) + { + task.Stop(); + task.Enabled = false; + } + } + }); + + // If the process exists and is running, kill it + if (process != null && !process.HasExited) + process.Kill(); + } + + public override void Stop() + { + taskTimer.Stop(); + base.Stop(); + } + } +} diff --git a/HandheldCompanion/Controls/Hints/Hint_LegionGoServices.cs b/HandheldCompanion/Controls/Hints/Hint_LegionGoServices.cs new file mode 100644 index 000000000..4e23b83c6 --- /dev/null +++ b/HandheldCompanion/Controls/Hints/Hint_LegionGoServices.cs @@ -0,0 +1,107 @@ +using HandheldCompanion.Devices; +using HandheldCompanion.Utils; +using HandheldCompanion.Views; +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceProcess; +using System.Threading.Tasks; +using System.Timers; +using System.Windows; + +namespace HandheldCompanion.Controls.Hints +{ + public class Hint_LegionGoServices : IHint + { + private List serviceNames = new() + { + "DAService", + }; + + private List serviceControllers = new(); + private Timer serviceTimer; + + public Hint_LegionGoServices() : base() + { + if (MainWindow.CurrentDevice is not LegionGo) + return; + + // Get all the services installed on the local computer + ServiceController[] services = ServiceController.GetServices(); + foreach (string serviceName in serviceNames) + { + if (services.Any(s => serviceNames.Contains(s.ServiceName))) + { + // Create a service controller object for the specified service + ServiceController serviceController = new ServiceController(serviceName); + serviceControllers.Add(serviceController); + } + } + + // Check if any of the services in the list exist + if (!serviceControllers.Any()) + return; + + serviceTimer = new Timer(4000); + serviceTimer.Elapsed += ServiceTimer_Elapsed; + serviceTimer.Start(); + + // default state + this.HintActionButton.Visibility = Visibility.Visible; + + this.HintTitle.Text = Properties.Resources.Hint_LegionGoServices; + this.HintDescription.Text = Properties.Resources.Hint_LegionGoServicesDesc; + this.HintReadMe.Text = Properties.Resources.Hint_LegionGoServicesReadme; + + this.HintActionButton.Content = Properties.Resources.Hint_LegionGoServicesAction; + } + + private void ServiceTimer_Elapsed(object? sender, ElapsedEventArgs e) + { + if(!serviceControllers.Any()) + return; + + // Check if any of the services in the list exist and are running + bool anyRunning = false; + + foreach (ServiceController serviceController in serviceControllers) + { + serviceController.Refresh(); + if (serviceController.Status == ServiceControllerStatus.Running) + { + anyRunning = true; + break; + } + } + + // UI thread (async) + Application.Current.Dispatcher.BeginInvoke(() => + { + this.Visibility = anyRunning ? Visibility.Visible : Visibility.Collapsed; + }); + } + + protected override void HintActionButton_Click(object sender, RoutedEventArgs e) + { + if (!serviceControllers.Any()) + return; + + Task.Run(async () => + { + foreach (ServiceController serviceController in serviceControllers) + { + if (serviceController.Status == ServiceControllerStatus.Running) + serviceController.Stop(); + serviceController.WaitForStatus(ServiceControllerStatus.Stopped); + ServiceUtils.ChangeStartMode(serviceController, ServiceStartMode.Disabled, out _); + } + }); + } + + public override void Stop() + { + serviceTimer.Stop(); + base.Stop(); + } + } +} diff --git a/HandheldCompanion/Devices/AOKZOE/AOKZOEA1.cs b/HandheldCompanion/Devices/AOKZOE/AOKZOEA1.cs index dcf62849b..85d6c3296 100644 --- a/HandheldCompanion/Devices/AOKZOE/AOKZOEA1.cs +++ b/HandheldCompanion/Devices/AOKZOE/AOKZOEA1.cs @@ -128,4 +128,19 @@ public override string GetGlyph(ButtonFlags button) return defaultGlyph; } + + public override string GetGlyph(ButtonFlags button) + { + switch (button) + { + case ButtonFlags.OEM1: + return "\u220C"; + case ButtonFlags.OEM2: + return "\u2210"; + case ButtonFlags.OEM3: + return "\u2211"; + } + + return defaultGlyph; + } } \ No newline at end of file diff --git a/HandheldCompanion/Devices/AYANEO/AYANEO2021.cs b/HandheldCompanion/Devices/AYANEO/AYANEO2021.cs index 5f9d66e63..e77a7c023 100644 --- a/HandheldCompanion/Devices/AYANEO/AYANEO2021.cs +++ b/HandheldCompanion/Devices/AYANEO/AYANEO2021.cs @@ -69,4 +69,19 @@ public override string GetGlyph(ButtonFlags button) return defaultGlyph; } + + public override string GetGlyph(ButtonFlags button) + { + switch (button) + { + case ButtonFlags.OEM1: + return "\uE008"; + case ButtonFlags.OEM2: + return "\u242F"; + case ButtonFlags.OEM3: + return "\u243D"; + } + + return defaultGlyph; + } } \ No newline at end of file diff --git a/HandheldCompanion/Devices/GPD/GPDWinMax2.cs b/HandheldCompanion/Devices/GPD/GPDWinMax2.cs index 63a6d8969..87b47ffb4 100644 --- a/HandheldCompanion/Devices/GPD/GPDWinMax2.cs +++ b/HandheldCompanion/Devices/GPD/GPDWinMax2.cs @@ -57,4 +57,17 @@ public override string GetGlyph(ButtonFlags button) return defaultGlyph; } + + public override string GetGlyph(ButtonFlags button) + { + switch (button) + { + case ButtonFlags.OEM2: + return "\u220E"; + case ButtonFlags.OEM3: + return "\u220F"; + } + + return defaultGlyph; + } } \ No newline at end of file diff --git a/HandheldCompanion/Devices/OneXPlayer/OneXPlayerMini.cs b/HandheldCompanion/Devices/OneXPlayer/OneXPlayerMini.cs index 902c9c99f..7ac4f79a0 100644 --- a/HandheldCompanion/Devices/OneXPlayer/OneXPlayerMini.cs +++ b/HandheldCompanion/Devices/OneXPlayer/OneXPlayerMini.cs @@ -72,6 +72,20 @@ public override string GetGlyph(ButtonFlags button) return defaultGlyph; } + public override string GetGlyph(ButtonFlags button) + { + switch (button) + { + case ButtonFlags.OEM1: + return "\u2219"; + case ButtonFlags.OEM2: + return "\u2210"; + case ButtonFlags.OEM3: + return "\u2218"; + } + + return defaultGlyph; + } public override bool Open() { diff --git a/HandheldCompanion/GraphSettings.dll b/HandheldCompanion/GraphSettings.dll new file mode 100644 index 000000000..6bcc74b1a Binary files /dev/null and b/HandheldCompanion/GraphSettings.dll differ diff --git a/HandheldCompanion/PerformanceMetrics.dll b/HandheldCompanion/PerformanceMetrics.dll new file mode 100644 index 000000000..0a85ee4c0 Binary files /dev/null and b/HandheldCompanion/PerformanceMetrics.dll differ diff --git a/HandheldCompanion/Platforms/OpenHardwareMonitor.cs b/HandheldCompanion/Platforms/OpenHardwareMonitor.cs new file mode 100644 index 000000000..7b04a1b6b --- /dev/null +++ b/HandheldCompanion/Platforms/OpenHardwareMonitor.cs @@ -0,0 +1,102 @@ +using LibreHardwareMonitor.Hardware; +using System.Timers; + +namespace HandheldCompanion.Platforms +{ + public class OpenHardwareMonitor : IPlatform + { + private Computer computer; + private string ProductName; + + private Timer updateTimer; + private int updateInterval = 1000; + + public OpenHardwareMonitor() + { + Name = "OpenHardwareMonitor"; + IsInstalled = true; + + ProductName = MotherboardInfo.Product; + + // watchdog to populate sensors + updateTimer = new Timer(updateInterval) { Enabled = false }; + updateTimer.Elapsed += UpdateTimer_Elapsed; + + // prepare for sensors reading + computer = new Computer + { + IsCpuEnabled = true, + IsGpuEnabled = true, + }; + } + + public override bool Start() + { + // open computer, slow + computer.Open(); + + updateTimer.Start(); + + return base.Start(); + } + + public override bool Stop(bool kill = false) + { + if (updateTimer is not null) + updateTimer.Stop(); + + if (computer is not null) + computer.Close(); + + return base.Stop(kill); + } + + private void UpdateTimer_Elapsed(object? sender, ElapsedEventArgs e) + { + // pull temperature sensor + foreach (var hardware in computer.Hardware) + { + if (hardware.HardwareType == HardwareType.Cpu) + { + hardware.Update(); + + foreach (ISensor? sensor in hardware.Sensors) + { + if (sensor.Value is null) + continue; + + if (sensor.SensorType == SensorType.Temperature) + { + switch (sensor.Name) + { + case "CPU Package": + case "Core (Tctl/Tdie)": + { + double value = (double)sensor.Value; + + // dirty + switch(ProductName) + { + case "Galileo": + value /= 2.0d; + break; + } + + CpuTemperatureChanged?.Invoke(value); + } + break; + } + } + } + } + } + } + + #region events + + public event CpuTemperatureChangedHandler CpuTemperatureChanged; + public delegate void CpuTemperatureChangedHandler(double value); + + #endregion + } +}