diff --git a/.gitignore b/.gitignore index 0307020..9a9bd73 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ bin/ obj/ /.vs/ *.user +build-release/ +.vscode/ diff --git a/PerformanceOverlay/App.config b/PerformanceOverlay/App.config new file mode 100644 index 0000000..b3fb96a --- /dev/null +++ b/PerformanceOverlay/App.config @@ -0,0 +1,18 @@ + + + + +
+ + + + + + True + + + FPS + + + + \ No newline at end of file diff --git a/PerformanceOverlay/Controller.cs b/PerformanceOverlay/Controller.cs new file mode 100644 index 0000000..498b6e0 --- /dev/null +++ b/PerformanceOverlay/Controller.cs @@ -0,0 +1,140 @@ +using PerformanceOverlay.External; +using RTSSSharedMemoryNET; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PerformanceOverlay +{ + internal class Controller : IDisposable + { + Container components = new Container(); + RTSSSharedMemoryNET.OSD? osd; + ToolStripMenuItem showItem; + Sensors sensors = new Sensors(); + + LibreHardwareMonitor.Hardware.Computer libreHardwareComputer = new LibreHardwareMonitor.Hardware.Computer + { + IsCpuEnabled = true, + IsGpuEnabled = true, + IsStorageEnabled = true, + IsBatteryEnabled = true + }; + + public Controller() + { + var contextMenu = new System.Windows.Forms.ContextMenuStrip(components); + + showItem = new ToolStripMenuItem("&Show OSD"); + showItem.Click += ShowItem_Click; + showItem.Checked = Settings.Default.ShowOSD; + contextMenu.Items.Add(showItem); + contextMenu.Items.Add(new ToolStripSeparator()); + foreach (var mode in Enum.GetValues()) + { + var modeItem = new ToolStripMenuItem(mode.ToString()); + modeItem.Tag = mode; + modeItem.Click += delegate + { + Settings.Default.OSDModeParsed = mode; + updateContextItems(contextMenu); + }; + contextMenu.Items.Add(modeItem); + } + updateContextItems(contextMenu); + + contextMenu.Items.Add(new ToolStripSeparator()); + + var exitItem = contextMenu.Items.Add("&Exit"); + exitItem.Click += ExitItem_Click; + + var notifyIcon = new System.Windows.Forms.NotifyIcon(components); + notifyIcon.Icon = Resources.traffic_light_outline1; + notifyIcon.Text = "Steam Deck Fan Control"; + notifyIcon.Visible = true; + notifyIcon.ContextMenuStrip = contextMenu; + notifyIcon.Click += NotifyIcon_Click; + + var osdTimer = new System.Windows.Forms.Timer(components); + osdTimer.Tick += OsdTimer_Tick; + osdTimer.Interval = 250; + osdTimer.Enabled = true; + + GlobalHotKey.RegisterHotKey("F11", () => + { + showItem.Checked = !showItem.Checked; + }); + + // Select next overlay + GlobalHotKey.RegisterHotKey("Shift+F11", () => + { + var values = Enum.GetValues().ToList(); + + int index = values.IndexOf(Settings.Default.OSDModeParsed); + Settings.Default.OSDModeParsed = values[(index + 1) % values.Count]; + + showItem.Checked = true; + updateContextItems(contextMenu); + }); + } + + private void updateContextItems(ContextMenuStrip contextMenu) + { + foreach (ToolStripItem item in contextMenu.Items) + { + if (item.Tag is Overlays.Mode) + ((ToolStripMenuItem)item).Checked = ((Overlays.Mode)item.Tag == Settings.Default.OSDModeParsed); + } + } + + private void NotifyIcon_Click(object? sender, EventArgs e) + { + ((NotifyIcon)sender).ContextMenuStrip.Show(Control.MousePosition); + } + + private void ShowItem_Click(object? sender, EventArgs e) + { + showItem.Checked = !showItem.Checked; + } + + private void OsdTimer_Tick(object? sender, EventArgs e) + { + if (!showItem.Checked) + { + using (osd) { } + osd = null; + return; + } + + sensors.Update(); + + var osdOverlay = Overlays.GetOSD(Settings.Default.OSDModeParsed, sensors); + + try + { + if (osd == null) + osd = new OSD("PerformanceOverlay"); + osd.Update(osdOverlay); + } + catch(SystemException) + { + osd = null; + } + } + + private void ExitItem_Click(object? sender, EventArgs e) + { + Application.Exit(); + } + + public void Dispose() + { + components.Dispose(); + using (osd) { } + using (sensors) { } + } + } +} diff --git a/PerformanceOverlay/External/GlobalHotKey.cs b/PerformanceOverlay/External/GlobalHotKey.cs new file mode 100644 index 0000000..f172d1d --- /dev/null +++ b/PerformanceOverlay/External/GlobalHotKey.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Windows.Input; + +namespace PerformanceOverlay.External +{ + public class GlobalHotKey : IDisposable + { + /// + /// Registers a global hotkey + /// + /// e.g. Alt + Shift + Control + Win + S + /// Action to be called when hotkey is pressed + /// true, if registration succeeded, otherwise false + public static bool RegisterHotKey(string aKeyGestureString, Action aAction) + { + var c = new KeyGestureConverter(); + KeyGesture aKeyGesture = (KeyGesture)c.ConvertFrom(aKeyGestureString); + return RegisterHotKey(aKeyGesture.Modifiers, aKeyGesture.Key, aAction); + } + + public static bool RegisterHotKey(ModifierKeys aModifier, Key aKey, Action aAction) + { + if (aModifier == ModifierKeys.None && false) + { + throw new ArgumentException("Modifier must not be ModifierKeys.None"); + } + if (aAction is null) + { + throw new ArgumentNullException(nameof(aAction)); + } + + System.Windows.Forms.Keys aVirtualKeyCode = (System.Windows.Forms.Keys)KeyInterop.VirtualKeyFromKey(aKey); + currentID = currentID + 1; + bool aRegistered = RegisterHotKey(window.Handle, currentID, + (uint)aModifier | MOD_NOREPEAT, + (uint)aVirtualKeyCode); + + if (aRegistered) + { + registeredHotKeys.Add(new HotKeyWithAction(aModifier, aKey, aAction)); + } + return aRegistered; + } + + public void Dispose() + { + // unregister all the registered hot keys. + for (int i = currentID; i > 0; i--) + { + UnregisterHotKey(window.Handle, i); + } + + // dispose the inner native window. + window.Dispose(); + } + + static GlobalHotKey() + { + window.KeyPressed += (s, e) => + { + registeredHotKeys.ForEach(x => + { + if (e.Modifier == x.Modifier && e.Key == x.Key) + { + x.Action(); + } + }); + }; + } + + private static readonly InvisibleWindowForMessages window = new InvisibleWindowForMessages(); + private static int currentID; + private static uint MOD_NOREPEAT = 0x4000; + private static List registeredHotKeys = new List(); + + private class HotKeyWithAction + { + + public HotKeyWithAction(ModifierKeys modifier, Key key, Action action) + { + Modifier = modifier; + Key = key; + Action = action; + } + + public ModifierKeys Modifier { get; } + public Key Key { get; } + public Action Action { get; } + } + + // Registers a hot key with Windows. + [DllImport("user32.dll")] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); + // Unregisters the hot key with Windows. + [DllImport("user32.dll")] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + + private class InvisibleWindowForMessages : System.Windows.Forms.NativeWindow, IDisposable + { + public InvisibleWindowForMessages() + { + CreateHandle(new System.Windows.Forms.CreateParams()); + } + + private static int WM_HOTKEY = 0x0312; + protected override void WndProc(ref System.Windows.Forms.Message m) + { + base.WndProc(ref m); + + if (m.Msg == WM_HOTKEY) + { + var aWPFKey = KeyInterop.KeyFromVirtualKey(((int)m.LParam >> 16) & 0xFFFF); + ModifierKeys modifier = (ModifierKeys)((int)m.LParam & 0xFFFF); + if (KeyPressed != null) + { + KeyPressed(this, new HotKeyPressedEventArgs(modifier, aWPFKey)); + } + } + } + + public class HotKeyPressedEventArgs : EventArgs + { + private ModifierKeys _modifier; + private Key _key; + + internal HotKeyPressedEventArgs(ModifierKeys modifier, Key key) + { + _modifier = modifier; + _key = key; + } + + public ModifierKeys Modifier + { + get { return _modifier; } + } + + public Key Key + { + get { return _key; } + } + } + + + public event EventHandler KeyPressed; + + #region IDisposable Members + + public void Dispose() + { + this.DestroyHandle(); + } + + #endregion + } + } + +} diff --git a/PerformanceOverlay/Overlays.cs b/PerformanceOverlay/Overlays.cs new file mode 100644 index 0000000..228fee4 --- /dev/null +++ b/PerformanceOverlay/Overlays.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Policy; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using static System.Net.Mime.MediaTypeNames; + +namespace PerformanceOverlay +{ + internal class Overlays + { + public enum Mode + { + FPS, + Minimal, + Detail, + All + } + + public class Entry + { + public String? Text { get; set; } + public IList Include { get; set; } = new List(); + public IList Exclude { get; set; } = new List(); + public IList Nested { get; set; } = new List(); + public String Separator { get; set; } = ""; + public bool IgnoreMissing { get; set; } + + public static readonly Regex attributeRegex = new Regex("{([^}]+)}", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + + public Entry() + { } + + public Entry(String text) + { + this.Text = text; + } + + public IEnumerable AllAttributes + { + get + { + return attributeRegex.Matches(Text ?? ""); + } + } + + private String EvaluateText(Sensors sensors) + { + String output = Text ?? ""; + + foreach (var attribute in AllAttributes) + { + String attributeName = attribute.Groups[1].Value; + String? value = sensors.GetValue(attributeName); + if (value is null && IgnoreMissing) + return ""; + output = output.Replace(attribute.Value, value ?? "-"); + } + + return output; + } + + public String? GetValue(Mode mode, Sensors sensors) + { + if (Exclude.Count > 0 && Exclude.Contains(mode)) + return null; + if (Include.Count > 0 && !Include.Contains(mode)) + return null; + + String output = EvaluateText(sensors); + + if (Nested.Count > 0) + { + var outputs = Nested.Select(entry => entry.GetValue(mode, sensors)).Where(output => output != null); + if (outputs.Count() == 0) + return null; + + output += String.Join(Separator, outputs); + } + + if (output == String.Empty) + return null; + + return output; + } + } + + public static readonly String[] Helpers = + { + "", + "", + }; + + public static readonly Entry OSD = new Entry + { + Nested = { + new Entry { Text = " FPS", Include = { Mode.FPS } }, + + new Entry { + Nested = + { + new Entry + { + Text = "BATT", + Nested = + { + new Entry("{BATT_%} %"), + new Entry("{BATT_W} W") + } + }, + new Entry + { + Text = "GPU", + Nested = + { + new Entry("{GPU_%} %"), + new Entry("{GPU_W} W"), + new Entry { Text = "{GPU_T} C", IgnoreMissing = true } + } + }, + new Entry + { + Text = "CPU", + Nested = + { + new Entry("{CPU_%} %"), + new Entry("{CPU_W} W"), + new Entry { Text = "{CPU_T} C", IgnoreMissing = true } + } + }, + new Entry + { + Text = "RAM", + Nested = + { + new Entry("{MEM_GB} GiB") + } + }, + new Entry + { + Text = "", + Nested = + { + new Entry(" FPS") + } + }, + new Entry + { + Text = "" + } + }, + Separator = "| ", + Include = { Mode.Minimal } + }, + + new Entry { Text = "MEM {MEM_MB} MB", Exclude = { Mode.FPS, Mode.Minimal } }, + new Entry { Text = "CPU {CPU_%} %", Exclude = { Mode.FPS, Mode.Minimal } }, + new Entry { Text = "RAM {GPU_MB} MB", Exclude = { Mode.FPS, Mode.Minimal } }, + new Entry { Text = " FPS ms", Exclude = { Mode.FPS, Mode.Minimal } }, + new Entry { + Text = "BAT ", + Nested = { + new Entry("{BATT_%} %"), + new Entry("{BATT_W} W") + }, + Exclude = { Mode.FPS, Mode.Minimal } + }, + new Entry { Text = "Frametime", Exclude = { Mode.FPS, Mode.Minimal } }, + new Entry { Text = "", Exclude = { Mode.FPS, Mode.Minimal } }, + new Entry { Text = " ms", Exclude = { Mode.FPS, Mode.Minimal } } + }, + Separator = "\r\n" + }; + + public static String GetOSD(Mode mode, Sensors sensors) + { + var sb = new StringBuilder(); + + sb.AppendJoin("", Helpers); + sb.Append(OSD.GetValue(mode, sensors) ?? ""); + + return sb.ToString(); + } + } +} diff --git a/PerformanceOverlay/PerformanceOverlay.csproj b/PerformanceOverlay/PerformanceOverlay.csproj new file mode 100644 index 0000000..c671cce --- /dev/null +++ b/PerformanceOverlay/PerformanceOverlay.csproj @@ -0,0 +1,66 @@ + + + + WinExe + net6.0-windows + enable + true + enable + app.manifest + Resources\traffic-light-outline.ico + True + + + + + + + + + + + + + + + + + + + + + RTSSSharedMemoryNET.dll + + + + + + True + True + Resources.resx + + + True + True + Settings.settings + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + PreserveNewest + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + \ No newline at end of file diff --git a/PerformanceOverlay/Program.cs b/PerformanceOverlay/Program.cs new file mode 100644 index 0000000..b862fbc --- /dev/null +++ b/PerformanceOverlay/Program.cs @@ -0,0 +1,29 @@ +using RTSSSharedMemoryNET; + +namespace PerformanceOverlay +{ + internal static class Program + { + [STAThread] + static void Main() + { + ApplicationConfiguration.Initialize(); + + try + { + foreach (var entry in RTSSSharedMemoryNET.OSD.GetOSDEntries()) + { + Console.WriteLine("Entry: {0}", entry.Owner); + Console.WriteLine("\t", entry.Text); + } + } + catch(SystemException) + { } + + using (var controller = new Controller()) + { + Application.Run(); + } + } + } +} \ No newline at end of file diff --git a/PerformanceOverlay/RTSSSharedMemoryNET.dll b/PerformanceOverlay/RTSSSharedMemoryNET.dll new file mode 100644 index 0000000..d197665 Binary files /dev/null and b/PerformanceOverlay/RTSSSharedMemoryNET.dll differ diff --git a/PerformanceOverlay/Resources.Designer.cs b/PerformanceOverlay/Resources.Designer.cs new file mode 100644 index 0000000..2e0b0af --- /dev/null +++ b/PerformanceOverlay/Resources.Designer.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PerformanceOverlay { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PerformanceOverlay.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap traffic_light_outline { + get { + object obj = ResourceManager.GetObject("traffic_light_outline", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon traffic_light_outline1 { + get { + object obj = ResourceManager.GetObject("traffic_light_outline1", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + } +} diff --git a/PerformanceOverlay/Resources.resx b/PerformanceOverlay/Resources.resx new file mode 100644 index 0000000..70b93f1 --- /dev/null +++ b/PerformanceOverlay/Resources.resx @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\traffic-light-outline.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Resources\traffic-light-outline.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/PerformanceOverlay/Resources/NotifyIcon.ico b/PerformanceOverlay/Resources/NotifyIcon.ico new file mode 100644 index 0000000..5d06b9f Binary files /dev/null and b/PerformanceOverlay/Resources/NotifyIcon.ico differ diff --git a/PerformanceOverlay/Resources/traffic-light-outline.ico b/PerformanceOverlay/Resources/traffic-light-outline.ico new file mode 100644 index 0000000..81940de Binary files /dev/null and b/PerformanceOverlay/Resources/traffic-light-outline.ico differ diff --git a/PerformanceOverlay/Resources/traffic-light-outline.png b/PerformanceOverlay/Resources/traffic-light-outline.png new file mode 100644 index 0000000..e0e8c3b Binary files /dev/null and b/PerformanceOverlay/Resources/traffic-light-outline.png differ diff --git a/PerformanceOverlay/Sensors.cs b/PerformanceOverlay/Sensors.cs new file mode 100644 index 0000000..4916efa --- /dev/null +++ b/PerformanceOverlay/Sensors.cs @@ -0,0 +1,259 @@ +using LibreHardwareMonitor.Hardware; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; +using static PerformanceOverlay.Sensors; + +namespace PerformanceOverlay +{ + internal class Sensors : IDisposable + { + public abstract class Sensor + { + public abstract string? GetValue(Sensors sensors); + } + + public abstract class ValueSensor : Sensor + { + public String? Format { get; set; } + public float Multiplier { get; set; } = 1.0f; + public bool IgnoreZero { get; set; } + + protected string? ConvertToString(float value) + { + if (value == 0 && IgnoreZero) + return null; + + value *= Multiplier; + return value.ToString(Format, CultureInfo.GetCultureInfo("en-US")); + } + } + + public class UserValueSensor : ValueSensor + { + public delegate float ValueDelegate(); + + public ValueDelegate Value { get; set; } + + public override string? GetValue(Sensors sensors) + { + return ConvertToString(Value()); + } + } + + public class HardwareSensor : ValueSensor + { + public string HardwareName { get; set; } = ""; + public HardwareType HardwareType { get; set; } + public string SensorName { get; set; } = ""; + public SensorType SensorType { get; set; } + + public bool Matches(ISensor sensor) + { + return sensor != null && + sensor.Hardware.HardwareType == HardwareType && + sensor.Hardware.Name.StartsWith(HardwareName) && + sensor.SensorType == SensorType && + sensor.Name == SensorName; + } + + public string? GetValue(ISensor sensor) + { + if (!sensor.Value.HasValue) + return null; + + return ConvertToString(sensor.Value.Value); + } + + public override string? GetValue(Sensors sensors) + { + foreach (var hwSensor in sensors.AllHardwareSensors) + { + if (Matches(hwSensor)) + { + return GetValue(hwSensor); + } + } + return null; + } + } + + public readonly Dictionary AllSensors = new Dictionary + { + { + "CPU_%", new HardwareSensor() + { + HardwareType = HardwareType.Cpu, + HardwareName = "AMD Custom APU 0405", + SensorType = SensorType.Load, + SensorName = "CPU Total", + Format = "F0" + } + }, + { + "CPU_W", new HardwareSensor() + { + HardwareType = HardwareType.Cpu, + HardwareName = "AMD Custom APU 0405", + SensorType = SensorType.Power, + SensorName = "Package", + Format = "F1" + } + }, + { + "CPU_T", new HardwareSensor() + { + HardwareType = HardwareType.Cpu, + HardwareName = "AMD Custom APU 0405", + SensorType = SensorType.Temperature, + SensorName = "Core (Tctl/Tdie)", + Format = "F1", + IgnoreZero = true + } + }, + { + "MEM_GB", new HardwareSensor() + { + HardwareType = HardwareType.Memory, + HardwareName = "Generic Memory", + SensorType = SensorType.Data, + SensorName = "Memory Used", + Format = "F1" + } + }, + { + "MEM_MB", new HardwareSensor() + { + HardwareType = HardwareType.Memory, + HardwareName = "Generic Memory", + SensorType = SensorType.Data, + SensorName = "Memory Used", + Format = "F0", + Multiplier = 1024 + } + }, + { + "GPU_%", new HardwareSensor() + { + HardwareType = HardwareType.GpuAmd, + HardwareName = "AMD Custom GPU 0405", + SensorType = SensorType.Load, + SensorName = "D3D 3D", + Format = "F0" + } + }, + { + "GPU_MB", new HardwareSensor() + { + HardwareType = HardwareType.GpuAmd, + HardwareName = "AMD Custom GPU 0405", + SensorType = SensorType.SmallData, + SensorName = "D3D Dedicated Memory Used", + Format = "F0" + } + }, + { + "GPU_GB", new HardwareSensor() + { + HardwareType = HardwareType.GpuAmd, + HardwareName = "AMD Custom GPU 0405", + SensorType = SensorType.SmallData, + SensorName = "D3D Dedicated Memory Used", + Format = "F0", + Multiplier = 1.0f/1024.0f + } + }, + { + "GPU_W", new HardwareSensor() + { + HardwareType = HardwareType.GpuAmd, + HardwareName = "AMD Custom GPU 0405", + SensorType = SensorType.Power, + SensorName = "GPU SoC", + Format = "F1" + } + }, + { + "GPU_T", new HardwareSensor() + { + HardwareType = HardwareType.GpuAmd, + HardwareName = "AMD Custom GPU 0405", + SensorType = SensorType.Temperature, + SensorName = "GPU Temperature", + Format = "F1", + IgnoreZero = true + } + }, + { + "BATT_%", new HardwareSensor() + { + HardwareType = HardwareType.Battery, + HardwareName = "GETAC", + SensorType = SensorType.Level, + SensorName = "Charge Level", + Format = "F0" + } + }, + { + "BATT_W", new HardwareSensor() + { + HardwareType = HardwareType.Battery, + HardwareName = "GETAC", + SensorType = SensorType.Power, + SensorName = "Charge/Discharge Rate", + Format = "F1" + } + } + }; + + private LibreHardwareMonitor.Hardware.Computer libreHardwareComputer = new LibreHardwareMonitor.Hardware.Computer + { + IsCpuEnabled = true, + IsMemoryEnabled = true, + IsGpuEnabled = true, + IsStorageEnabled = true, + IsBatteryEnabled = true + }; + + public IList AllHardwareSensors { get; private set; } = new List(); + + public Sensors() + { + libreHardwareComputer.Open(); + } + + public void Dispose() + { + libreHardwareComputer.Close(); + } + + public void Update() + { + var allSensors = new List(); + + foreach (IHardware hardware in libreHardwareComputer.Hardware) + { + try + { + hardware.Update(); + } + catch (SystemException) { } + hardware.Accept(new SensorVisitor(sensor => allSensors.Add(sensor))); + } + + this.AllHardwareSensors = allSensors; + } + + public string? GetValue(String name) + { + if (!AllSensors.ContainsKey(name)) + return null; + + return AllSensors[name].GetValue(this); + } + } +} diff --git a/PerformanceOverlay/Settings.Designer.cs b/PerformanceOverlay/Settings.Designer.cs new file mode 100644 index 0000000..7956a7f --- /dev/null +++ b/PerformanceOverlay/Settings.Designer.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PerformanceOverlay { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool ShowOSD { + get { + return ((bool)(this["ShowOSD"])); + } + set { + this["ShowOSD"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("FPS")] + public string OSDMode { + get { + return ((string)(this["OSDMode"])); + } + set { + this["OSDMode"] = value; + } + } + } +} diff --git a/PerformanceOverlay/Settings.cs b/PerformanceOverlay/Settings.cs new file mode 100644 index 0000000..76da60c --- /dev/null +++ b/PerformanceOverlay/Settings.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static PerformanceOverlay.Overlays; + +namespace PerformanceOverlay +{ + internal partial class Settings + { + public Overlays.Mode OSDModeParsed + { + get + { + try + { + return (Mode)Enum.Parse(OSDMode); + } + catch (ArgumentException) + { + return Mode.FPS; + } + } + set + { + OSDMode = value.ToString(); + Save(); + } + } + } +} diff --git a/PerformanceOverlay/Settings.settings b/PerformanceOverlay/Settings.settings new file mode 100644 index 0000000..5191aa6 --- /dev/null +++ b/PerformanceOverlay/Settings.settings @@ -0,0 +1,12 @@ + + + + + + True + + + FPS + + + \ No newline at end of file diff --git a/PerformanceOverlay/app.manifest b/PerformanceOverlay/app.manifest new file mode 100644 index 0000000..209b401 --- /dev/null +++ b/PerformanceOverlay/app.manifest @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + true + true + + + + + + + diff --git a/SteamDeckTools.sln b/SteamDeckTools.sln index 5f8a00a..df09d7d 100644 --- a/SteamDeckTools.sln +++ b/SteamDeckTools.sln @@ -3,18 +3,44 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32901.215 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FanControl", "FanControl\FanControl.csproj", "{A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FanControl", "FanControl\FanControl.csproj", "{A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerformanceOverlay", "PerformanceOverlay\PerformanceOverlay.csproj", "{DCA71DCC-A3ED-4890-A56C-3E2183A3C023}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Debug|x64.ActiveCfg = Debug|Any CPU + {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Debug|x64.Build.0 = Debug|Any CPU + {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Debug|x86.ActiveCfg = Debug|Any CPU + {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Debug|x86.Build.0 = Debug|Any CPU {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Release|Any CPU.ActiveCfg = Release|Any CPU {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Release|Any CPU.Build.0 = Release|Any CPU + {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Release|x64.ActiveCfg = Release|Any CPU + {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Release|x64.Build.0 = Release|Any CPU + {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Release|x86.ActiveCfg = Release|Any CPU + {A0D9B170-89BA-4F7A-9331-BE6A721E8D5B}.Release|x86.Build.0 = Release|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Debug|x64.ActiveCfg = Debug|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Debug|x64.Build.0 = Debug|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Debug|x86.ActiveCfg = Debug|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Debug|x86.Build.0 = Debug|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Release|Any CPU.Build.0 = Release|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Release|x64.ActiveCfg = Release|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Release|x64.Build.0 = Release|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Release|x86.ActiveCfg = Release|Any CPU + {DCA71DCC-A3ED-4890-A56C-3E2183A3C023}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE