├── .github └── workflows │ └── dotnet.yml ├── .gitignore ├── .gitmodules ├── LICENSE.md ├── README.md ├── Slate.API └── Slate.API.csproj ├── Slate.Asus ├── Acpi │ ├── AcpiDumper.cs │ ├── AsusAcpiEndpoint.cs │ ├── AsusAcpiProxy.cs │ ├── AsusIoCtl.cs │ ├── DevsMethod.cs │ ├── DstsMethod.cs │ ├── Endpoints │ │ ├── AsusDevsEndpoint.cs │ │ └── AsusDstsEndpoint.cs │ ├── FunctionSets │ │ └── WmnbFunction.cs │ ├── KeyPressRequest.cs │ ├── RequiresAcpiSessionAttribute.cs │ └── here_be_dragons ├── AssemblyInfo.cs ├── AtkWmiEventID.cs ├── Extensions.cs ├── FanCurve.cs ├── FanCurvePoint.cs ├── MuxSwitchMode.cs ├── Native │ └── Kernel32.cs ├── PerformancePreset.cs └── Slate.Asus.csproj ├── Slate.sln └── Slate ├── App.axaml ├── App.axaml.cs ├── Controller ├── ApplicationController.AniMeMatrix.cs ├── ApplicationController.Application.cs ├── ApplicationController.Fans.cs ├── ApplicationController.GraphicsAndDisplay.cs ├── ApplicationController.Keyboard.cs ├── ApplicationController.PowerManagement.cs └── ApplicationController.cs ├── FodyWeavers.xml ├── FodyWeavers.xsd ├── Infrastructure ├── Extensions.cs ├── Native │ ├── PowrProf.cs │ └── User32.cs ├── PowerManagement │ ├── PowerMode.cs │ └── ProcessorBoostLevel.cs ├── Services │ ├── IApplicationExecutionService.cs │ ├── IAsusAnimeMatrixService.cs │ ├── IAsusAuraService.cs │ ├── IAsusHalService.cs │ ├── IDisplayManagementService.cs │ ├── IHardwareMonitorService.cs │ ├── IInputInjectionService.cs │ ├── IPowerManagementService.cs │ ├── ISettingsService.cs │ ├── IShutdownService.cs │ ├── IStorageService.cs │ ├── IWmiEventService.cs │ └── Implementations │ │ ├── ApplicationExecutionService.cs │ │ ├── AsusAnimeMatrixService.cs │ │ ├── AsusAuraService.cs │ │ ├── AsusHalService.cs │ │ ├── DisplayManagementService.cs │ │ ├── HardwareMonitorService.cs │ │ ├── InputInjectionService.cs │ │ ├── PowerManagementService.cs │ │ ├── SettingsService.cs │ │ ├── ShutdownService.cs │ │ ├── StorageService.cs │ │ └── WmiEventService.cs ├── Settings │ ├── SettingsBase.cs │ └── SettingsComponent.cs ├── SystemParameters.cs └── WMI │ └── ManagementEvent.cs ├── Model ├── ColorWrapper.cs ├── KeyBind.cs ├── KeyBindMode.cs ├── MediaKey.cs ├── Messaging │ └── Messages.cs └── Settings │ ├── Components │ ├── AniMeMatrixSettings.cs │ ├── ApplicationSettings.cs │ ├── FansSettings.cs │ ├── GraphicsAndDisplaySettings.cs │ ├── KeyboardSettings.cs │ └── PowerManagementSettings.cs │ └── ControlCenterSettings.cs ├── Program.cs ├── Resources ├── Animations │ ├── power_saving_1.gif │ ├── power_saving_2.gif │ ├── shutdown_1.gif │ ├── shutdown_2.gif │ ├── sleep_1.gif │ ├── sleep_2.gif │ ├── start_1.gif │ └── start_2.gif ├── Fonts │ ├── fa5_brands.otf │ └── segoe_fluent.ttf ├── Icons │ └── icon.ico ├── Paths │ ├── AuraIcon.axaml │ ├── FanIcon.axaml │ ├── MicrophoneIcon.axaml │ └── RogLogo.axaml └── Styles │ ├── BrightnessSelector.axaml │ ├── Card.axaml │ ├── LinkIcon.axaml │ ├── MediaPanelRadioButton.axaml │ ├── SwitchRadioButton.axaml │ ├── ToggleSwitch.axaml │ └── Transitions.axaml ├── Slate.csproj ├── View ├── Control │ ├── Icons │ │ ├── FAIcon.axaml │ │ ├── FAIcon.axaml.cs │ │ ├── SFIcon.axaml │ │ └── SFIcon.axaml.cs │ ├── PageElements │ │ ├── AniMeMatrixBuiltInSelector.axaml │ │ ├── AniMeMatrixBuiltInSelector.axaml.cs │ │ ├── AuraColorControl.axaml │ │ ├── AuraColorControl.axaml.cs │ │ ├── SettingsPalette.axaml │ │ └── SettingsPalette.axaml.cs │ └── Primitives │ │ ├── BrightnessSelector.axaml │ │ ├── BrightnessSelector.axaml.cs │ │ ├── Card.axaml │ │ ├── Card.axaml.cs │ │ ├── CoreStatisticsDisplay.axaml │ │ ├── CoreStatisticsDisplay.axaml.cs │ │ ├── DualSwitch.axaml │ │ ├── DualSwitch.axaml.cs │ │ ├── EditableChart.axaml │ │ ├── EditableChart.axaml.cs │ │ ├── GifRadioButton.axaml │ │ ├── GifRadioButton.axaml.cs │ │ ├── KeyBindingControl.axaml │ │ ├── KeyBindingControl.axaml.cs │ │ ├── MainMenuButton.axaml │ │ └── MainMenuButton.axaml.cs ├── Page │ ├── AniMeMatrixPage.axaml │ ├── AniMeMatrixPage.axaml.cs │ ├── ApplicationPage.axaml │ ├── ApplicationPage.axaml.cs │ ├── DebugPage.axaml │ ├── DebugPage.axaml.cs │ ├── FansPage.axaml │ ├── FansPage.axaml.cs │ ├── GraphicsAndDisplayPage.axaml │ ├── GraphicsAndDisplayPage.axaml.cs │ ├── KeyboardBindingsPage.axaml │ ├── KeyboardBindingsPage.axaml.cs │ ├── KeyboardPage.axaml │ ├── KeyboardPage.axaml.cs │ ├── MainMenuPage.axaml │ ├── MainMenuPage.axaml.cs │ ├── PowerManagementPage.axaml │ └── PowerManagementPage.axaml.cs ├── Pages.cs └── Window │ ├── AnimatedWindow.cs │ ├── MainWindow.axaml │ ├── MainWindow.axaml.cs │ └── WindowSlideOrigin.cs ├── ViewModel ├── Control │ ├── AuraColorControlViewModel.cs │ ├── CoreStatisticsDisplayViewModel.cs │ └── SettingsPaletteViewModel.cs ├── Page │ ├── AniMeMatrixPageViewModel.cs │ ├── ApplicationPageViewModel.cs │ ├── DebugPageViewModel.cs │ ├── FansPageViewModel.cs │ ├── GraphicsAndDisplayPageViewModel.cs │ ├── KeyboardBindingsPageViewModel.cs │ ├── KeyboardPageViewModel.cs │ └── PowerManagementPageViewModel.cs └── Window │ └── MainWindowViewModel.cs └── app.manifest /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: windows-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | with: 17 | submodules: recursive 18 | - name: Setup .NET 19 | uses: actions/setup-dotnet@v3 20 | with: 21 | dotnet-version: 7.0.x 22 | - name: Restore dependencies 23 | run: dotnet restore 24 | - name: Build 25 | run: dotnet build --no-restore 26 | - name: Upload a Build Artifact 27 | uses: actions/upload-artifact@v3.1.2 28 | with: 29 | name: Zephyrus-Control-Center_DEBUG 30 | path: Slate/bin/Debug/net7.0 31 | if-no-files-found: error 32 | retention-days: 30 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | /packages/ 4 | riderModule.iml 5 | /_ReSharper.Caches/ 6 | .idea/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Dependencies/Glitonea"] 2 | path = Dependencies/Glitonea 3 | url = https://github.com/vddCore/Glitonea.git 4 | [submodule "Dependencies/Avalonia.GIF"] 5 | path = Dependencies/Avalonia.GIF 6 | url = https://github.com/vddCore/Avalonia.GIF.git 7 | [submodule "Dependencies/Starlight"] 8 | path = Dependencies/Starlight 9 | url = https://github.com/vddCore/Starlight.git 10 | -------------------------------------------------------------------------------- /Slate.API/Slate.API.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net7.0 4 | enable 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Slate.Asus/Acpi/AcpiDumper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using Microsoft.Win32; 6 | using Slate.Asus.Native; 7 | 8 | namespace Slate.Asus.Acpi 9 | { 10 | public static class AcpiDumper 11 | { 12 | private const int AcpiId = 0x41435049; // 'A' 'C' 'P' 'I' 13 | 14 | public static int[] FetchFirmwareAcpiTableList(bool skipLicenseKeyTable = true) 15 | { 16 | var dataSize = Kernel32.EnumSystemFirmwareTables(AcpiId, null, 0); 17 | var data = new byte[dataSize]; 18 | 19 | if (dataSize > 0) 20 | { 21 | if (Kernel32.EnumSystemFirmwareTables(AcpiId, data, dataSize) > 0) 22 | { 23 | var ret = new int[dataSize / 4]; 24 | Buffer.BlockCopy(data, 0, ret, 0, (int)dataSize); 25 | 26 | return ret.Where( 27 | x => x.ToFourCharacterCode() != "SSDT" 28 | && (skipLicenseKeyTable && x.ToFourCharacterCode() != "MSDM") 29 | ).Distinct().ToArray(); 30 | } 31 | } 32 | 33 | return new int[0]; 34 | } 35 | 36 | public static void DumpFirmwareAcpiTable(int tableId, Stream outStream) 37 | { 38 | var dataSize = Kernel32.GetSystemFirmwareTable( 39 | AcpiId, 40 | tableId, 41 | null, 42 | 0 43 | ); 44 | 45 | var data = new byte[dataSize]; 46 | Kernel32.GetSystemFirmwareTable( 47 | AcpiId, 48 | tableId, 49 | data, 50 | dataSize 51 | ); 52 | 53 | outStream.Write(data); 54 | } 55 | 56 | public static int[] FetchRegistryAcpiTableList(bool skipLicenseKeyTable) 57 | { 58 | using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default)) 59 | { 60 | using (var subKey = hklm.OpenSubKey($"HARDWARE\\ACPI")) 61 | { 62 | return subKey! 63 | .GetSubKeyNames() 64 | .Select(x => x.ToFourCharacterCodeInteger()) 65 | .Where(x => skipLicenseKeyTable && x.ToFourCharacterCode() != "MSDM") 66 | .ToArray(); 67 | } 68 | } 69 | } 70 | 71 | public static void DumpRegistryAcpiTable(int tableId, Stream outStream) 72 | { 73 | var data = ReadAcpiTableFromRegistry(tableId.ToFourCharacterCode()); 74 | outStream.Write(data); 75 | } 76 | 77 | private static byte[] ReadAcpiTableFromRegistry(string fourcc) 78 | { 79 | // We drill into the registry for SSDTs & co. 80 | // precisely because GetSystemFirmwareTable 81 | // is absolute Dogshit. For fuck's sake, why 82 | // couldn't it be an enumerator? 83 | // 84 | var disposeList = new List(); 85 | 86 | using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default)) 87 | { 88 | using (var subKey = hklm.OpenSubKey($"HARDWARE\\ACPI\\{fourcc}")) 89 | { 90 | var currentKey = subKey; 91 | object? value; 92 | 93 | do 94 | { 95 | var subKeyNames = currentKey!.GetSubKeyNames(); 96 | 97 | value = currentKey.GetValue("00000000"); 98 | if (value != null) 99 | break; 100 | 101 | if (subKeyNames.Length == 0) 102 | { 103 | // We've drilled as deep as we can and still no data. 104 | // Unfortunate. 105 | break; 106 | } 107 | 108 | currentKey = currentKey.OpenSubKey(subKeyNames[0]); 109 | disposeList.Add(currentKey!); 110 | } while (value == null); 111 | 112 | foreach (var key in disposeList) 113 | key.Dispose(); 114 | 115 | if (value == null) 116 | { 117 | throw new InvalidOperationException($"No registry data for {fourcc}."); 118 | } 119 | 120 | return (byte[])value; 121 | } 122 | } 123 | } 124 | } 125 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/AsusAcpiEndpoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Slate.Asus.Acpi.FunctionSets; 3 | 4 | namespace Slate.Asus.Acpi 5 | { 6 | public abstract class AsusAcpiEndpoint where T : struct 7 | { 8 | private readonly AsusAcpiProxy _proxy; 9 | 10 | public WmnbFunction Method { get; } 11 | 12 | protected AsusAcpiEndpoint(AsusAcpiProxy proxy, WmnbFunction method) 13 | { 14 | _proxy = proxy; 15 | Method = method; 16 | } 17 | 18 | public byte[] ReadBytes(T method, int count, params byte[] args) 19 | { 20 | var methodData = BitConverter.GetBytes((int)Convert.ChangeType(method, TypeCode.Int32)); 21 | var methodArguments = new byte[sizeof(int) + args.Length]; 22 | 23 | Array.Copy(methodData, 0, methodArguments, 0, sizeof(int)); 24 | Array.Copy(args, 0, methodArguments, sizeof(int), args.Length); 25 | 26 | return _proxy.InvokeWMI(Method, count, args: methodArguments); 27 | } 28 | 29 | public int ReadInt32(T method, params byte[] args) 30 | { 31 | return BitConverter.ToInt32( 32 | ReadBytes(method, sizeof(int), args) 33 | ); 34 | } 35 | 36 | public bool ReadBoolean(T method, params byte[] args) 37 | { 38 | return ReadInt32(method, args) != 0; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/AsusAcpiProxy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Slate.Asus.Acpi.Endpoints; 4 | using Slate.Asus.Acpi.FunctionSets; 5 | using Slate.Asus.Native; 6 | 7 | namespace Slate.Asus.Acpi 8 | { 9 | public class AsusAcpiProxy : IDisposable 10 | { 11 | private readonly nint _objectHandle; 12 | 13 | public AsusDstsEndpoint DSTS { get; } 14 | public AsusDevsEndpoint DEVS { get; } 15 | 16 | public AsusAcpiProxy(string acpiDevicePath = @"\\.\\ATKACPI") 17 | { 18 | _objectHandle = Kernel32.CreateFile( 19 | acpiDevicePath, 20 | Kernel32.GENERIC_READ | Kernel32.GENERIC_WRITE, 21 | Kernel32.FILE_SHARE_READ | Kernel32.FILE_SHARE_WRITE, 22 | 0, 23 | Kernel32.OPEN_EXISTING, 24 | Kernel32.FILE_ATTRIBUTE_NORMAL, 25 | 0 26 | ); 27 | 28 | if (_objectHandle < 0) 29 | { 30 | throw new IOException($"Failed to acquire ACPI interface at '{acpiDevicePath}'."); 31 | } 32 | 33 | DSTS = new AsusDstsEndpoint(this); 34 | DEVS = new AsusDevsEndpoint(this); 35 | } 36 | 37 | public byte[] InvokeWMI(WmnbFunction wmnbFunction, int outBufferSize = 20, params byte[] args) 38 | { 39 | var inBuffer = new byte[sizeof(int) * 2 + args.Length]; 40 | var outBuffer = new byte[outBufferSize]; 41 | 42 | Array.Copy( 43 | BitConverter.GetBytes((int)wmnbFunction), 0, 44 | inBuffer, 0, sizeof(int) 45 | ); 46 | 47 | Array.Copy( 48 | BitConverter.GetBytes(args.Length), 0, 49 | inBuffer, 4, sizeof(int) 50 | ); 51 | 52 | Array.Copy(args, 0, inBuffer, 8, args.Length); 53 | 54 | unsafe 55 | { 56 | fixed (byte* inPtr = inBuffer) 57 | fixed (byte* outPtr = outBuffer) 58 | { 59 | Write(AsusIoCtl.InvokeWmnbFunction, inPtr, inBuffer.Length, outPtr, outBuffer.Length); 60 | } 61 | } 62 | 63 | return outBuffer; 64 | } 65 | 66 | private unsafe uint Write(AsusIoCtl ioctl, byte* input, int inputLength, byte* output, int outputLength) 67 | { 68 | var requestSuccessful = Kernel32.DeviceIoControl( 69 | _objectHandle, 70 | (nuint)ioctl, 71 | input, 72 | inputLength, 73 | output, 74 | outputLength, 75 | out var ret, 76 | 0 77 | ); 78 | 79 | if (!requestSuccessful) 80 | { 81 | throw new IOException($"Unable to write to ACPI interface: {Kernel32.GetLastError():X8}"); 82 | } 83 | 84 | return ret; 85 | } 86 | 87 | public void Dispose() 88 | { 89 | Kernel32.CloseHandle(_objectHandle); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/AsusIoCtl.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Asus.Acpi 2 | { 3 | public enum AsusIoCtl 4 | { 5 | AssignEvent = 0x00222400, 6 | InvokeAcpiFunction = 0x00222404, 7 | GetNotifyCode = 0x00222408, 8 | InvokeWmnbFunction = 0x0022240C 9 | } 10 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/DevsMethod.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Asus.Acpi 2 | { 3 | public enum DevsMethod 4 | { 5 | SetDisplayOverdrive = 0x00050019, 6 | SetMuxSwitch = 0x00090016, 7 | SetEcoMode = 0x00090020, 8 | Unk_0x00010003 = 0x00010003, // ACPI: CWAP 9 | Unk_0x00010012 = 0x00010012, // ACPI: WLED 10 | Unk_0x00010013 = 0x00010013, // ACPI: BLED 11 | SimulateKeyPress = 0x00100021, 12 | Unk_0x00100022 = 0x00100022, 13 | SetCpuFanCurve = 0x00110024, 14 | SetGpuFanCurve = 0x00110025, 15 | SetCpuFanSpeedDirect = 0x00110022, 16 | SetGpuFanSpeedDirect = 0x00110023, 17 | SetBatteryChargeTarget = 0x00120057, 18 | SetPerformancePreset = 0x00120075, 19 | SetTotalPPT = 0x001200A0, 20 | SetCpuEDC = 0x001200A1, 21 | SetCpuTDC = 0x001200A2, 22 | Unk_0x001200A3 = 0x001200A3, // ACPI: PLON 23 | SetCpuPPT = 0x001200B0, // ACPI: PLAO 24 | Unk_0x001200B1 = 0x001200B1, // ACPI: PLPS 25 | Unk_0x001200C0 = 0x001200C0, // no-op 26 | Unk_0x001200C1 = 0x001200C1, // ACPI: PLFW 27 | Unk_0x001200C2 = 0x001200C2, // no-op 28 | Unk_0x00130022 = 0x00130022, // ACPI: APSC 29 | } 30 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/DstsMethod.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Asus.Acpi 2 | { 3 | public enum DstsMethod 4 | { 5 | Unk_0x00010001 = 0x00010001, 6 | Unk_0x00010002 = 0x00010002, 7 | Unk_0x00010011 = 0x00010011, 8 | Unk_0x00010013 = 0x00010013, 9 | GetDisplayOverdriveStatus = 0x00050019, 10 | Unk_0x00080041 = 0x00080041, 11 | Unk_0x00080042 = 0x00080042, 12 | Unk_0x00080043 = 0x00080043, 13 | Unk_0x00080044 = 0x00080044, 14 | GetMuxSwitchStatus = 0x00090016, 15 | GetEcoModeStatus = 0x00090020, 16 | Unk_0x00100051 = 0x00100051, 17 | GetCpuFanSpeed = 0x00110013, 18 | GetGpuFanSpeed = 0x00110014, 19 | Unk_0x00110015 = 0x00110015, 20 | Unk_0x00110016 = 0x00110016, 21 | Unk_0x00110022 = 0x00110022, 22 | Unk_0x00110023 = 0x00110023, 23 | GetCpuFanCurve = 0x00110024, 24 | GetGpuFanCurve = 0x00110025, 25 | Unk_0x00110026 = 0x00110026, 26 | Unk_0x00110027 = 0x00110027, 27 | /** 28 | * & with 0x00010000 == IsSupported 29 | * & with 0x00000010 == IsOverheating 30 | * & with 0x00000001 == IsRunning 31 | * Not present in G14 ACPI but... 32 | **/ 33 | GetFanDustySupportedStatus = 0x0011001E, 34 | Unk_0x00120057 = 0x00120057, 35 | Unk_0x00120061 = 0x00120061, 36 | GetFanCurveCount = 0x00120075, 37 | Unk_0x00120079 = 0x00120079, 38 | Unk_0x00120093 = 0x00120093, 39 | GetCpuTemperature = 0x00120094, 40 | GetGpuTemperature = 0x00120097, 41 | Unk_0x0012006C = 0x0012006C, 42 | Unk_0x001200A0 = 0x001200A0, 43 | Unk_0x001200A1 = 0x001200A1, 44 | Unk_0x001200A2 = 0x001200A2, 45 | Unk_0x001200A3 = 0x001200A3, 46 | Unk_0x001200B0 = 0x001200B0, 47 | Unk_0x001200B1 = 0x001200B1, 48 | Unk_0x001200C1 = 0x001200C1, 49 | Unk_0x00130021 = 0x00130021, 50 | Unk_0x00130022 = 0x00130022, 51 | Unk_0x00130031 = 0x00130031, 52 | Unk_0x00050019 = 0x00050019, 53 | Unk_0x00050020 = 0x00050020, 54 | Unk_0x00060023 = 0x00060023, 55 | Unk_0x00060024 = 0x00060024, 56 | Unk_0x00060026 = 0x00060026, 57 | Unk_0x00060061 = 0x00060061, 58 | } 59 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/Endpoints/AsusDevsEndpoint.cs: -------------------------------------------------------------------------------- 1 | using Slate.Asus.Acpi.FunctionSets; 2 | 3 | namespace Slate.Asus.Acpi.Endpoints 4 | { 5 | public class AsusDevsEndpoint : AsusAcpiEndpoint 6 | { 7 | public AsusDevsEndpoint(AsusAcpiProxy proxy) 8 | : base(proxy, WmnbFunction.DEVS) 9 | { 10 | } 11 | 12 | public void SimulateKeyPress(KeyPressRequest request) 13 | { 14 | _ = ReadInt32( 15 | DevsMethod.SimulateKeyPress, 16 | (byte)request 17 | ); 18 | } 19 | 20 | public void SetPerformancePreset(PerformancePreset preset) 21 | { 22 | _ = ReadInt32( 23 | DevsMethod.SetPerformancePreset, 24 | (byte)preset 25 | ); 26 | } 27 | 28 | public void SetCpuFanDutyCycle(byte dutyCycle) 29 | { 30 | _ = ReadInt32( 31 | DevsMethod.SetCpuFanSpeedDirect, 32 | dutyCycle 33 | ); 34 | } 35 | 36 | public void SetGpuFanDutyCycle(byte dutyCycle) 37 | { 38 | _ = ReadInt32( 39 | DevsMethod.SetGpuFanSpeedDirect, 40 | dutyCycle 41 | ); 42 | } 43 | 44 | public void SetCpuFanCurve(FanCurve curve) 45 | { 46 | _ = ReadInt32( 47 | DevsMethod.SetCpuFanCurve, 48 | curve.RawData 49 | ); 50 | } 51 | 52 | public void SetGpuFanCurve(FanCurve curve) 53 | { 54 | _ = ReadInt32( 55 | DevsMethod.SetGpuFanCurve, 56 | curve.RawData 57 | ); 58 | } 59 | 60 | public void SetMuxSwitch(MuxSwitchMode mode) 61 | { 62 | _ = ReadInt32( 63 | DevsMethod.SetMuxSwitch, 64 | (byte)mode 65 | ); 66 | } 67 | 68 | /** 69 | * Calling this will crash your system if MUX switch is set 70 | * to Discrete. I mean - you *will* have to power-cycle it. 71 | * 72 | * Manually. Oh, also, you'll have to re-enable the discrete 73 | * GPU in Device Manager. Likewise - manually. 74 | * 75 | * But hey, this is a low-level API. Who am I to judge. 76 | **/ 77 | public void SetEcoMode(bool enable) 78 | { 79 | _ = ReadInt32( 80 | DevsMethod.SetEcoMode, 81 | enable ? (byte)1 : (byte)0 82 | ); 83 | } 84 | 85 | public void SetDisplayOverdrive(bool enable) 86 | { 87 | _ = ReadInt32( 88 | DevsMethod.SetDisplayOverdrive, 89 | enable ? (byte)1 : (byte)0 90 | ); 91 | } 92 | 93 | public void SetBatteryChargeTarget(byte value) 94 | { 95 | _ = ReadInt32( 96 | DevsMethod.SetBatteryChargeTarget, 97 | value 98 | ); 99 | } 100 | 101 | /** 102 | * These are probably the most dangerous ACPI calls. 103 | * 104 | * I'm not sure how much you can fuck your system up 105 | * by providing invalid data, and I don't trust ASUS 106 | * to obey any hard limits after seeing some of the 107 | * driver disassembly. 108 | * 109 | * Once again - this is a low-level API. Provide bogus 110 | * data at your own risk, then suffer the consequences. 111 | **/ 112 | public void SetTotalPPT(byte totalPpt) 113 | { 114 | _ = ReadInt32( 115 | DevsMethod.SetTotalPPT, 116 | totalPpt 117 | ); 118 | } 119 | 120 | public void SetCpuPPT(byte cpuPpt) 121 | { 122 | _ = ReadInt32( 123 | DevsMethod.SetCpuPPT, 124 | cpuPpt 125 | ); 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/Endpoints/AsusDstsEndpoint.cs: -------------------------------------------------------------------------------- 1 | using Slate.Asus.Acpi.FunctionSets; 2 | 3 | namespace Slate.Asus.Acpi.Endpoints 4 | { 5 | public class AsusDstsEndpoint : AsusAcpiEndpoint 6 | { 7 | public int CpuFanSpeed => (ReadInt32(DstsMethod.GetCpuFanSpeed) & 0xFFFF) * 100; 8 | public int GpuFanSpeed => (ReadInt32(DstsMethod.GetGpuFanSpeed) & 0xFFFF) * 100; 9 | 10 | public int CpuTemperatureCelsius => ReadInt32(DstsMethod.GetCpuTemperature) & 0xFFFF; 11 | public int GpuTemperatureCelsius => ReadInt32(DstsMethod.GetGpuTemperature) & 0xFFFF; 12 | 13 | public MuxSwitchMode MuxSwitchMode => (MuxSwitchMode)(ReadInt32(DstsMethod.GetMuxSwitchStatus) & 0xFFFF); 14 | 15 | public bool IsGraphicsPowerSavingEnabled => (ReadInt32(DstsMethod.GetEcoModeStatus) & 0xFFFF) != 0; 16 | public bool IsDisplayOverdriveEnabled => (ReadInt32(DstsMethod.GetDisplayOverdriveStatus) & 0xFFFF) != 0; 17 | 18 | internal AsusDstsEndpoint(AsusAcpiProxy proxy) 19 | : base(proxy, WmnbFunction.DSTS) 20 | { 21 | } 22 | 23 | public FanCurve ReadRawCpuFanCurve(PerformancePreset preset) 24 | => new(ReadBytes( 25 | DstsMethod.GetCpuFanCurve, 26 | 16, 27 | MapPresetToDstsParameter(preset) 28 | )); 29 | 30 | public FanCurve ReadRawGpuFanCurve(PerformancePreset preset) 31 | => new(ReadBytes( 32 | DstsMethod.GetGpuFanCurve, 33 | 16, 34 | MapPresetToDstsParameter(preset) 35 | )); 36 | 37 | /** 38 | * ASUS fucked up and now I have to pay the price. 39 | * 40 | * For some reason Silent and Performance are inverted for 41 | * GetCpuFanCurve and GetGpuFanCurve -- it's inconsistent 42 | * with SetPerformancePreset in DEVS. 43 | * 44 | * Of course not. That'd make way too much sense. 45 | * Am I glad I don't work in there. 46 | **/ 47 | private byte MapPresetToDstsParameter(PerformancePreset preset) 48 | { 49 | return preset switch 50 | { 51 | PerformancePreset.Performance => (byte)PerformancePreset.Silent, 52 | PerformancePreset.Silent => (byte)PerformancePreset.Performance, 53 | _ => (byte)PerformancePreset.Balanced 54 | }; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/FunctionSets/WmnbFunction.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Asus.Acpi.FunctionSets 2 | { 3 | public enum WmnbFunction 4 | { 5 | INIT = 0x54494E49, // 'T' 'I' 'N' 'I' | IIA0 6 | BSTS = 0x53545342, // 'S' 'T' 'S' 'B' 7 | SFUN = 0x4E554653, // 'N' 'U' 'F' 'S' 8 | WDOG = 0x474F4457, // 'G' 'O' 'D' 'W' | IIA0 9 | KBNI = 0x494E424B, // 'I' 'N' 'B' 'K' 10 | SCDG = 0x47444353, // 'G' 'D' 'C' 'S' | IIA0, IIA1 11 | SPEC = 0x43455053, // 'C' 'E' 'P' 'S' | IIA0 12 | OSVR = 0x5256534F, // 'R' 'V' 'O' 'S' | IIA0 13 | VERS = 0x53524556, // 'S' 'R' 'E' 'V' | IIA0, IIA1 14 | GLCD = 0x44434C47, // 'D' 'C' 'L' 'G' 15 | ANVI = 0x49564E41, // 'I' 'V' 'N' 'A' 16 | MWGF = 0x4647574D, // 'F' 'G' 'W' 'M' 17 | DSTS = 0x53545344, // 'S' 'T' 'S' 'D' 18 | DEVS = 0x53564544 // 'S' 'V' 'E' 'D' 19 | } 20 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/KeyPressRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Asus.Acpi 2 | { 3 | public enum KeyPressRequest : byte 4 | { 5 | DecreaseScreenBrightness = 0x10, 6 | IncreaseScreenBrightness = 0x20, 7 | EnterHardSleepMode = 0x35, // S3 8 | TriggerM4 = 0x38, 9 | TriggerTouchpadToggleKey = 0x6B, 10 | EnterLightSleepMode = 0x6C, // S1 11 | TriggerM3 = 0x7C, 12 | Unk_0x9E = 0x9E, 13 | Unk_0x88__Q0B = 0x88, // No-op on GA402 14 | Unk_0x8A__Q72 = 0x8A, 15 | Unk_0xA8 = 0xA8, 16 | Unk_0xA9 = 0xA9, 17 | Unk_0xAA = 0xAA, 18 | Unk_0xAB = 0xAB, 19 | TriggerFanModeCycleKey = 0xAE, 20 | TriggerAuraKey = 0xB3, 21 | IncreaseKeyboardBrightness = 0xC4, 22 | DecreaseKeyboardBrigthness = 0xC5, 23 | } 24 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/RequiresAcpiSessionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Slate.Asus.Acpi 4 | { 5 | [AttributeUsage(AttributeTargets.Method)] 6 | public class RequiresAcpiSessionAttribute : Attribute 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /Slate.Asus/Acpi/here_be_dragons: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate.Asus/Acpi/here_be_dragons -------------------------------------------------------------------------------- /Slate.Asus/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Versioning; 2 | 3 | [assembly: SupportedOSPlatform("windows")] -------------------------------------------------------------------------------- /Slate.Asus/AtkWmiEventID.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Asus 2 | { 3 | public enum AtkWmiEventID 4 | { 5 | KeyPressM4 = 56, 6 | PowerAdapterUnplugged = 87, 7 | PowerAdapterPlugged = 88, 8 | 9 | /** 10 | * Happens when USB-C or barrel plug 11 | * is connected to or disconnected 12 | * from the laptop. 13 | **/ 14 | ExternalPowerStateChanged = 123, 15 | KeyPressM3 = 124, 16 | KeyPressFnF10 = 107, 17 | KeyPressFnF5 = 174, 18 | KeyPressFnF4 = 179, 19 | 20 | /** 21 | * Happens when a HDMI cable is slotted 22 | * into the built-in socket or plugged-out 23 | * of it. 24 | */ 25 | HdmiConnectionStateChanged = 192, 26 | KeyPressFnF3 = 196, 27 | KeyPressFnF2 = 197, 28 | 29 | /** 30 | * Happens with 88 only in this particular order. 31 | * 32 | * 1. Barrel connector state change detected. (207) 33 | * 2. External power plugged-in. (88) 34 | * 3. Notify power state has changed. (123) 35 | */ 36 | BarrelConnectorPluggedIn = 207 37 | } 38 | } -------------------------------------------------------------------------------- /Slate.Asus/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace Slate.Asus 5 | { 6 | internal static class Extensions 7 | { 8 | public static (int IndexOf, int Value) Nearest(this int[] array, int value) 9 | { 10 | var bestIndex = -1; 11 | var bestValue = int.MaxValue; 12 | var minDiff = int.MaxValue; 13 | 14 | for (var i = 0; i < array.Length; i++) 15 | { 16 | var diff = Math.Abs((long)array[i] - value); 17 | 18 | if (minDiff > diff) 19 | { 20 | minDiff = (int)diff; 21 | bestValue = array[i]; 22 | bestIndex = i; 23 | } 24 | } 25 | 26 | return (bestIndex, bestValue); 27 | } 28 | 29 | public static string ToFourCharacterCode(this int value) 30 | { 31 | var bytes = BitConverter.GetBytes(value); 32 | return $"{(char)bytes[0]}{(char)bytes[1]}{(char)bytes[2]}{(char)bytes[3]}"; 33 | } 34 | 35 | public static int ToFourCharacterCodeInteger(this string fourcc) 36 | { 37 | if (fourcc.Length != 4) 38 | { 39 | throw new ArgumentException( 40 | "FOUR character code has FOUR characters. What do you not understand?", 41 | nameof(fourcc) 42 | ); 43 | } 44 | 45 | var bytes = new[] 46 | { 47 | (byte)fourcc[0], 48 | (byte)fourcc[1], 49 | (byte)fourcc[2], 50 | (byte)fourcc[3] 51 | }; 52 | 53 | return BitConverter.ToInt32(bytes); 54 | } 55 | 56 | public static int ReverseBytes(this int value) 57 | { 58 | var bytes = BitConverter.GetBytes(value); 59 | return BitConverter.ToInt32(bytes.Reverse().ToArray()); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Slate.Asus/FanCurve.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace Slate.Asus 6 | { 7 | public record FanCurve 8 | { 9 | public const int MaximumFanRPM = 6500; 10 | public const int MinimumFanRPM = 1800; 11 | public const int MinimumTemperature = 20; 12 | public const int MaximumTemperature = 110; 13 | 14 | public byte[] RawData { get; set; } = new byte[16]; 15 | public FanCurvePoint[] Points { get; set; } = new FanCurvePoint[8]; 16 | 17 | [JsonConstructor] 18 | public FanCurve() 19 | { 20 | } 21 | 22 | public FanCurve(byte[] rawData) 23 | { 24 | if (rawData.Length != 16) 25 | { 26 | throw new ArgumentException( 27 | $"Expected a 16-byte array. The provided array is {rawData.Length} long.", 28 | nameof(rawData) 29 | ); 30 | } 31 | 32 | RawData = rawData; 33 | 34 | for (var i = 0; i < 8; i++) 35 | { 36 | Points[i] = new FanCurvePoint( 37 | RawData[i], 38 | RawData[i + 8] 39 | ); 40 | } 41 | } 42 | 43 | public FanCurve(FanCurvePoint[] points) 44 | { 45 | if (points.Length != 8) 46 | { 47 | throw new ArgumentException( 48 | $"Expected an 8-point fan curve. The provided array has {points.Length} of them.", 49 | nameof(points) 50 | ); 51 | } 52 | 53 | Points = points; 54 | 55 | for (var i = 0; i < 8; i++) 56 | { 57 | RawData[i] = Points[i].Temperature; 58 | RawData[i + 8] = Points[i].LookupTableIndex; 59 | } 60 | } 61 | 62 | public override string ToString() 63 | { 64 | var sb = new StringBuilder(); 65 | 66 | foreach (var b in RawData) 67 | { 68 | sb.Append($"{b:X2} "); 69 | } 70 | 71 | sb.AppendLine(); 72 | 73 | foreach (var b in RawData) 74 | { 75 | sb.Append($"{b:D3} "); 76 | } 77 | 78 | return sb.ToString(); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /Slate.Asus/FanCurvePoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Slate.Asus 5 | { 6 | public struct FanCurvePoint 7 | { 8 | /** 9 | * ASUS' firmware does not calculate anything. 10 | * Instead, we have this neat lookup table. 11 | * 12 | * I guess. 13 | * 14 | * Nothing makes sense about this fucking software. 15 | * 16 | * *sobs* 17 | **/ 18 | [JsonIgnore] 19 | private static readonly int[] _rpmLookupForward = new[] 20 | { 21 | 1799, 1800, 1800, 1900, 1900, 2000, 22 | 2000, 2100, 2100, 2100, 2200, 2200, 23 | 2300, 2300, 2300, 2400, 2400, 2400, 24 | 2500, 2500, 2600, 2600, 2700, 2700, 25 | 2800, 2800, 2900, 2900, 2900, 3000, 26 | 3000, 3100, 3100, 3200, 3200, 3300, 27 | 3300, 3400, 3400, 3500, 3500, 3500, 28 | 3600, 3600, 3700, 3700, 3800, 3800, 29 | 3800, 3900, 3900, 4000, 4000, 4100, 30 | 4100, 4100, 4200, 4200, 4200, 4300, 31 | 4300, 4400, 4400, 4500, 4500, 4500, 32 | 4600, 4600, 4700, 4700, 4800, 4800, 33 | 4800, 4900, 4900, 5000, 5000, 5000, 34 | 5100, 5100, 5200, 5200, 5300, 5300, 35 | 5400, 5400, 5400, 5500, 5500, 5600, 36 | 5600, 5600, 5700, 5700, 5800, 5800, 37 | 5900, 5900, 5900, 6000, 6000, 6100, 38 | 6100, 6200, 6200, 6300, 6300, 6300, 39 | 6400, 6400, 6500 40 | }; 41 | 42 | /// 43 | /// Represents X axis on the fan curve. 44 | /// 45 | public byte Temperature { get; set; } 46 | 47 | /// 48 | /// Represents Y axis on the fan curve (RPM LUT index). 49 | /// 50 | public byte LookupTableIndex { get; set; } 51 | 52 | /// 53 | /// Actual RPM based on the lookup table index. 54 | /// 55 | [JsonIgnore] 56 | public int RPM => _rpmLookupForward[LookupTableIndex]; 57 | 58 | [JsonConstructor] 59 | public FanCurvePoint() 60 | { 61 | } 62 | 63 | public FanCurvePoint(byte temperature, byte lookupTableIndex) 64 | { 65 | Temperature = temperature; 66 | LookupTableIndex = (byte)Math.Min(_rpmLookupForward.Length, lookupTableIndex); 67 | } 68 | 69 | public static (byte, int) Approximate(int rpm) 70 | { 71 | if (rpm < 1800) 72 | return (0, 849); 73 | 74 | var result = _rpmLookupForward.Nearest(rpm); 75 | return ((byte)result.IndexOf, result.Value); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /Slate.Asus/MuxSwitchMode.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Asus 2 | { 3 | public enum MuxSwitchMode : byte 4 | { 5 | Discrete = 0, 6 | Switched = 1 7 | } 8 | } -------------------------------------------------------------------------------- /Slate.Asus/Native/Kernel32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Slate.Asus.Native 4 | { 5 | internal static class Kernel32 6 | { 7 | private const string LibraryName = "kernel32.dll"; 8 | 9 | public const nuint GENERIC_READ = 0x80000000; 10 | public const nuint GENERIC_WRITE = 0x40000000; 11 | public const nuint OPEN_EXISTING = 3; 12 | public const nuint FILE_ATTRIBUTE_NORMAL = 0x80; 13 | public const nuint FILE_SHARE_READ = 0x01; 14 | public const nuint FILE_SHARE_WRITE = 0x02; 15 | 16 | [DllImport(LibraryName, CharSet = CharSet.Unicode)] 17 | public static extern nint CreateFile( 18 | [MarshalAs(UnmanagedType.LPWStr)] string lpFileName, 19 | nuint dwDesiredAccess, 20 | nuint dwShareMode, 21 | nint lpSecurityAttributes, 22 | nuint dwCreationDisposition, 23 | nuint dwFlagsAndAttributes, 24 | nint hTemplateFile 25 | ); 26 | 27 | [DllImport(LibraryName, SetLastError = true)] 28 | public static extern unsafe bool DeviceIoControl( 29 | nint hDevice, 30 | nuint dwIoControlCode, 31 | byte* lpInBuffer, 32 | [MarshalAs(UnmanagedType.U4)] int nInBufferSize, 33 | byte* lpOutBuffer, 34 | [MarshalAs(UnmanagedType.U4)] int nOutBufferSize, 35 | out uint lpBytesReturned, 36 | nint lpOverlapped 37 | ); 38 | 39 | [DllImport(LibraryName)] 40 | public static extern uint GetSystemFirmwareTable( 41 | int FirmwareTableProviderSignature, 42 | int FirmwareTableID, 43 | [In, Out, MarshalAs(UnmanagedType.LPArray)] 44 | byte[]? pFirmwareBuffer, 45 | uint BufferSize 46 | ); 47 | 48 | [DllImport(LibraryName)] 49 | public static extern uint EnumSystemFirmwareTables( 50 | [In] int FirmwareTableProviderSignature, 51 | [In, Out, MarshalAs(UnmanagedType.LPArray)] 52 | byte[]? pFirmwareBuffer, 53 | uint BufferSize 54 | ); 55 | 56 | [DllImport(LibraryName)] 57 | public static extern nint GetLastError(); 58 | 59 | [DllImport(LibraryName)] 60 | public static extern bool CloseHandle(nint hObject); 61 | } 62 | } -------------------------------------------------------------------------------- /Slate.Asus/PerformancePreset.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Asus 2 | { 3 | public enum PerformancePreset : byte 4 | { 5 | Silent = 2, 6 | Balanced = 0, 7 | Performance = 1 8 | } 9 | } -------------------------------------------------------------------------------- /Slate.Asus/Slate.Asus.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net7.0 4 | win-x64 5 | enable 6 | true 7 | false 8 | 9 | 10 | -------------------------------------------------------------------------------- /Slate.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Slate", "Slate\Slate.csproj", "{65A10EE6-CB91-4582-A962-B72E9746C06B}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Slate.API", "Slate.API\Slate.API.csproj", "{67226973-C1D0-4DE3-905A-B75676584383}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Slate.Asus", "Slate.Asus\Slate.Asus.csproj", "{612B40B6-06B6-4EE5-BB20-4A4AA0983062}" 8 | EndProject 9 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependencies", "Dependencies", "{1AC64CCC-023F-4454-AB73-AD12CD19B7E3}" 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Glitonea", "Dependencies\Glitonea\Glitonea.csproj", "{11F333ED-ECDD-4191-A48C-55C68C1D8634}" 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Starlight", "Dependencies\Starlight\Starlight\Starlight.csproj", "{765DDC4A-E8B5-49F9-BC95-1B934F4A263F}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvaloniaGif", "Dependencies\Avalonia.GIF\AvaloniaGif\AvaloniaGif.csproj", "{830404FA-3ADD-42D9-8EC3-B76904AF0F5B}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | AcpiTesting|Any CPU = AcpiTesting|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {65A10EE6-CB91-4582-A962-B72E9746C06B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {65A10EE6-CB91-4582-A962-B72E9746C06B}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {65A10EE6-CB91-4582-A962-B72E9746C06B}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {65A10EE6-CB91-4582-A962-B72E9746C06B}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {65A10EE6-CB91-4582-A962-B72E9746C06B}.AcpiTesting|Any CPU.ActiveCfg = AcpiTesting|Any CPU 29 | {65A10EE6-CB91-4582-A962-B72E9746C06B}.AcpiTesting|Any CPU.Build.0 = AcpiTesting|Any CPU 30 | {11F333ED-ECDD-4191-A48C-55C68C1D8634}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {11F333ED-ECDD-4191-A48C-55C68C1D8634}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {11F333ED-ECDD-4191-A48C-55C68C1D8634}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {11F333ED-ECDD-4191-A48C-55C68C1D8634}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {11F333ED-ECDD-4191-A48C-55C68C1D8634}.AcpiTesting|Any CPU.ActiveCfg = AcpiTesting|Any CPU 35 | {11F333ED-ECDD-4191-A48C-55C68C1D8634}.AcpiTesting|Any CPU.Build.0 = AcpiTesting|Any CPU 36 | {765DDC4A-E8B5-49F9-BC95-1B934F4A263F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {765DDC4A-E8B5-49F9-BC95-1B934F4A263F}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {765DDC4A-E8B5-49F9-BC95-1B934F4A263F}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {765DDC4A-E8B5-49F9-BC95-1B934F4A263F}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {765DDC4A-E8B5-49F9-BC95-1B934F4A263F}.AcpiTesting|Any CPU.ActiveCfg = Debug|Any CPU 41 | {765DDC4A-E8B5-49F9-BC95-1B934F4A263F}.AcpiTesting|Any CPU.Build.0 = Debug|Any CPU 42 | {830404FA-3ADD-42D9-8EC3-B76904AF0F5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {830404FA-3ADD-42D9-8EC3-B76904AF0F5B}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {830404FA-3ADD-42D9-8EC3-B76904AF0F5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {830404FA-3ADD-42D9-8EC3-B76904AF0F5B}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {830404FA-3ADD-42D9-8EC3-B76904AF0F5B}.AcpiTesting|Any CPU.ActiveCfg = Debug|Any CPU 47 | {830404FA-3ADD-42D9-8EC3-B76904AF0F5B}.AcpiTesting|Any CPU.Build.0 = Debug|Any CPU 48 | {67226973-C1D0-4DE3-905A-B75676584383}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {67226973-C1D0-4DE3-905A-B75676584383}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {67226973-C1D0-4DE3-905A-B75676584383}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {67226973-C1D0-4DE3-905A-B75676584383}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {67226973-C1D0-4DE3-905A-B75676584383}.AcpiTesting|Any CPU.ActiveCfg = Debug|Any CPU 53 | {67226973-C1D0-4DE3-905A-B75676584383}.AcpiTesting|Any CPU.Build.0 = Debug|Any CPU 54 | {612B40B6-06B6-4EE5-BB20-4A4AA0983062}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {612B40B6-06B6-4EE5-BB20-4A4AA0983062}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {612B40B6-06B6-4EE5-BB20-4A4AA0983062}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {612B40B6-06B6-4EE5-BB20-4A4AA0983062}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {612B40B6-06B6-4EE5-BB20-4A4AA0983062}.AcpiTesting|Any CPU.ActiveCfg = Debug|Any CPU 59 | {612B40B6-06B6-4EE5-BB20-4A4AA0983062}.AcpiTesting|Any CPU.Build.0 = Debug|Any CPU 60 | EndGlobalSection 61 | GlobalSection(NestedProjects) = preSolution 62 | {830404FA-3ADD-42D9-8EC3-B76904AF0F5B} = {1AC64CCC-023F-4454-AB73-AD12CD19B7E3} 63 | {11F333ED-ECDD-4191-A48C-55C68C1D8634} = {1AC64CCC-023F-4454-AB73-AD12CD19B7E3} 64 | {765DDC4A-E8B5-49F9-BC95-1B934F4A263F} = {1AC64CCC-023F-4454-AB73-AD12CD19B7E3} 65 | EndGlobalSection 66 | EndGlobal 67 | -------------------------------------------------------------------------------- /Slate/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Timers; 3 | using Avalonia; 4 | using Avalonia.Controls; 5 | using Avalonia.Controls.ApplicationLifetimes; 6 | using Avalonia.Markup.Xaml; 7 | using Avalonia.Platform; 8 | using Glitonea; 9 | using Glitonea.Extensions; 10 | using Glitonea.Mvvm.Messaging; 11 | using LiveChartsCore; 12 | using LiveChartsCore.SkiaSharpView; 13 | using PropertyChanged; 14 | using Slate.Model.Messaging; 15 | using Slate.View.Window; 16 | 17 | namespace Slate 18 | { 19 | [DoNotNotify] 20 | public class App : Application 21 | { 22 | private readonly Timer _globalTimer = new(250); 23 | private IPlatformSettings? _platformSettings; 24 | 25 | private ulong _globalTickCount; 26 | 27 | public override void Initialize() 28 | { 29 | GlitoneaCore.Initialize(); 30 | 31 | Message.Subscribe(this, OnMainWindowTransitionFinished); 32 | 33 | AvaloniaXamlLoader.Load(this); 34 | LiveCharts.Configure(c => c 35 | .AddSkiaSharp() 36 | .AddDarkTheme() 37 | ); 38 | 39 | _globalTimer.Elapsed += GlobalTime_Elapsed; 40 | } 41 | 42 | public override void OnFrameworkInitializationCompleted() 43 | { 44 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 45 | { 46 | desktop.MainWindow = new MainWindow(); 47 | } 48 | 49 | base.OnFrameworkInitializationCompleted(); 50 | 51 | TrayIcon.GetIcons(this)![0].IsVisible = true; 52 | PlatformSettings!.ColorValuesChanged += PlatformSettings_ColorValuesChanged; 53 | } 54 | 55 | private void OnMainWindowTransitionFinished(MainWindowTransitionFinishedMessage msg) 56 | { 57 | if (msg.WasSlidingIn) 58 | { 59 | _globalTimer.Start(); 60 | } 61 | else 62 | { 63 | _globalTimer.Stop(); 64 | } 65 | } 66 | 67 | private void TrayIcon_Clicked(object? sender, EventArgs e) 68 | { 69 | Message.Broadcast(); 70 | } 71 | 72 | private void GlobalTime_Elapsed(object? sender, ElapsedEventArgs elapsedEventArgs) 73 | { 74 | new GlobalTickMessage(++_globalTickCount) 75 | .Broadcast(); 76 | } 77 | 78 | private void Quit_Clicked(object? sender, EventArgs e) 79 | { 80 | this.GetDesktopLifetime() 81 | .Shutdown(); 82 | } 83 | 84 | private void PlatformSettings_ColorValuesChanged(object? sender, PlatformColorValues e) 85 | { 86 | new SystemAccentColorChangedMessage( 87 | e.AccentColor1, 88 | e.AccentColor2, 89 | e.AccentColor3 90 | ).Broadcast(); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Slate/Controller/ApplicationController.AniMeMatrix.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm.Messaging; 2 | using Slate.Model.Messaging; 3 | using Slate.Model.Settings.Components; 4 | 5 | namespace Slate.Controller 6 | { 7 | public partial class ApplicationController 8 | { 9 | private AniMeMatrixSettings AniMeMatrixSettings => ControlCenterSettings.AniMeMatrix; 10 | 11 | private void SubscribeToAniMeMatrixSettings() 12 | { 13 | Message.Subscribe(this, OnAniMeMatrixBrightnessChanged); 14 | Message.Subscribe(this, OnAniMeMatrixBuiltInsChanged); 15 | } 16 | 17 | private void OnAniMeMatrixBuiltInsChanged(AniMeMatrixBuiltInsChangedMessage msg) 18 | { 19 | _asusAnimeMatrixService.SetBuiltInAnimation( 20 | msg.PreferPowerSavingAnimation, 21 | msg.BuiltInConfiguration 22 | ); 23 | } 24 | 25 | private void OnAniMeMatrixBrightnessChanged(AniMeMatrixBrightnessChangedMessage msg) 26 | { 27 | _asusAnimeMatrixService.SetBrightness(msg.BrightnessLevel); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Slate/Controller/ApplicationController.Application.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Glitonea.Mvvm.Messaging; 4 | using Microsoft.Win32; 5 | using Slate.Model.Messaging; 6 | using Slate.Model.Settings.Components; 7 | 8 | namespace Slate.Controller 9 | { 10 | public partial class ApplicationController 11 | { 12 | private ApplicationSettings ApplicationSettings => ControlCenterSettings.Application; 13 | 14 | private void SubscribeToApplicationSettings() 15 | { 16 | Message.Subscribe(this, OnStartupLaunchChanged); 17 | } 18 | 19 | private void OnStartupLaunchChanged(StartupLaunchChangedMessage msg) 20 | { 21 | using var regKey = Registry.CurrentUser.OpenSubKey( 22 | "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 23 | true 24 | ); 25 | 26 | try 27 | { 28 | if (msg.Enabled) 29 | { 30 | regKey?.SetValue( 31 | ApplicationName, 32 | Process.GetCurrentProcess().MainModule!.FileName 33 | ); 34 | } 35 | else 36 | { 37 | regKey?.DeleteValue(ApplicationName, false); 38 | } 39 | } 40 | catch (Exception) 41 | { 42 | ApplicationSettings.RunOnStartup = false; 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Slate/Controller/ApplicationController.Fans.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm.Messaging; 2 | using Slate.Model.Messaging; 3 | using Slate.Model.Settings.Components; 4 | 5 | namespace Slate.Controller 6 | { 7 | public partial class ApplicationController 8 | { 9 | private FansSettings FansSettings => ControlCenterSettings.Fans; 10 | 11 | private void SubscribeToFansSettings() 12 | { 13 | Message.Subscribe(this, OnCpuFanCurveUpdated); 14 | Message.Subscribe(this, OnGpuFanCurveUpdated); 15 | Message.Subscribe(this, OnManualFanOverrideUpdated); 16 | } 17 | 18 | private void OnManualFanOverrideUpdated(ManualFanOverrideUpdatedMessage msg) 19 | { 20 | _asusHalService.SetPerformancePreset(FansSettings.PerformancePreset); 21 | 22 | if (msg.IsOverrideEnabled) 23 | { 24 | _asusHalService.SetCpuFanDutyCycle(msg.CpuDutyCycle); 25 | _asusHalService.SetGpuFanDutyCycle(msg.GpuDutyCycle); 26 | } 27 | else 28 | { 29 | _asusHalService.WriteCpuFanCurve(FansSettings.CpuFanCurve!); 30 | _asusHalService.WriteGpuFanCurve(FansSettings.GpuFanCurve!); 31 | } 32 | } 33 | 34 | private void OnCpuFanCurveUpdated(CpuFanCurveUpdatedMessage msg) 35 | { 36 | _asusHalService.WriteCpuFanCurve(msg.Curve); 37 | } 38 | 39 | private void OnGpuFanCurveUpdated(GpuFanCurveUpdatedMessage msg) 40 | { 41 | _asusHalService.WriteGpuFanCurve(msg.Curve); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Slate/Controller/ApplicationController.GraphicsAndDisplay.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm.Messaging; 2 | using Slate.Model.Messaging; 3 | using Slate.Model.Settings.Components; 4 | 5 | namespace Slate.Controller 6 | { 7 | public partial class ApplicationController 8 | { 9 | private GraphicsAndDisplaySettings GraphicsAndDisplaySettings => ControlCenterSettings.GraphicsAndDisplay; 10 | 11 | private void SubscribeToGraphicsAndDisplaySettings() 12 | { 13 | Message.Subscribe(this, OnGraphicsModeChanged); 14 | Message.Subscribe(this, OnGraphicsPowerSavingModeChanged); 15 | Message.Subscribe(this, OnDisplayOverdriveChanged); 16 | Message.Subscribe(this, OnDisplayRefreshRateChanged); 17 | } 18 | 19 | private void OnGraphicsModeChanged(MuxSwitchModeChangedMessage msg) 20 | { 21 | _asusHalService.SetGraphicsMode(msg.MuxSwitchMode); 22 | } 23 | 24 | private void OnGraphicsPowerSavingModeChanged(EcoModeChangedMessage msg) 25 | { 26 | _asusHalService.SetEcoMode(msg.Enabled); 27 | } 28 | 29 | private void OnDisplayOverdriveChanged(DisplayOverdriveChangedMessage msg) 30 | { 31 | _asusHalService.SetDisplayOverdrive(msg.Enabled); 32 | } 33 | 34 | private void OnDisplayRefreshRateChanged(DisplayRefreshRateChangedMessage msg) 35 | { 36 | _displayManagementService.SetInternalDisplayRefreshRate(msg.RefreshRate); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Slate/Controller/ApplicationController.Keyboard.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | using Avalonia.Threading; 4 | using Glitonea.Mvvm.Messaging; 5 | using Slate.Asus; 6 | using Slate.Model; 7 | using Slate.Model.Messaging; 8 | using Slate.Model.Settings.Components; 9 | 10 | namespace Slate.Controller 11 | { 12 | public partial class ApplicationController 13 | { 14 | private KeyboardSettings KeyboardSettings => ControlCenterSettings.Keyboard; 15 | 16 | private void SubscribeToKeyboardSettings() 17 | { 18 | Message.Subscribe(this, OnAuraSettingsChanged); 19 | } 20 | 21 | private void HandleSpecialKeyPress(AtkWmiEventID ev) 22 | { 23 | switch (ev) 24 | { 25 | case AtkWmiEventID.KeyPressM3: 26 | HandleKeyPress(KeyboardSettings.BindM3); 27 | break; 28 | 29 | case AtkWmiEventID.KeyPressM4: 30 | HandleKeyPress(KeyboardSettings.BindM4); 31 | break; 32 | 33 | case AtkWmiEventID.KeyPressFnF4: 34 | HandleKeyPress(KeyboardSettings.BindF4); 35 | break; 36 | 37 | case AtkWmiEventID.KeyPressFnF5: 38 | HandleKeyPress(KeyboardSettings.BindF5); 39 | break; 40 | } 41 | } 42 | 43 | private void HandleKeyPress(KeyBind keyBind) 44 | { 45 | switch (keyBind.Mode) 46 | { 47 | case KeyBindMode.Default: 48 | { 49 | Dispatcher.UIThread.Post(() => 50 | { 51 | Message.Broadcast(); 52 | }); 53 | 54 | break; 55 | } 56 | 57 | case KeyBindMode.Media: 58 | _inputInjectionService.SimulateMediaKeyPress(keyBind.MediaKey); 59 | break; 60 | 61 | case KeyBindMode.Command: 62 | { 63 | new Process 64 | { 65 | StartInfo = new ProcessStartInfo(keyBind.Command ?? string.Empty) 66 | { 67 | WorkingDirectory = Path.GetDirectoryName(keyBind.Command) 68 | } 69 | }.Start(); 70 | 71 | break; 72 | } 73 | } 74 | } 75 | 76 | private void OnAuraSettingsChanged(AuraSettingsChangedMessage msg) 77 | { 78 | _asusAuraService.WriteAuraSettings( 79 | msg.Animation, 80 | msg.PrimaryColor, 81 | msg.SecondaryColor, 82 | msg.AnimationSpeed 83 | ); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Slate/Controller/ApplicationController.PowerManagement.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm.Messaging; 2 | using Slate.Infrastructure.PowerManagement; 3 | using Slate.Model.Messaging; 4 | using Slate.Model.Settings.Components; 5 | 6 | namespace Slate.Controller 7 | { 8 | public partial class ApplicationController 9 | { 10 | private PowerManagementSettings PowerManagementSettings => ControlCenterSettings.PowerManagement; 11 | 12 | private void SubscribeToPowerManagementSettings() 13 | { 14 | Message.Subscribe(this, OnCpuBoostModeChanged); 15 | Message.Subscribe(this, OnBatteryChargeLimitChanged); 16 | Message.Subscribe(this, OnPowerTargetsChanged); 17 | } 18 | 19 | private void OnCpuBoostModeChanged(CpuBoostModeChangedMessage msg) 20 | { 21 | _powerManagementService.WriteProcessorBoostState( 22 | PowerMode.AC, 23 | msg.EnableOnAC 24 | ? ProcessorBoostLevel.Aggressive 25 | : ProcessorBoostLevel.Disabled 26 | ); 27 | 28 | _powerManagementService.WriteProcessorBoostState( 29 | PowerMode.DC, 30 | msg.EnableOnDC 31 | ? ProcessorBoostLevel.Aggressive 32 | : ProcessorBoostLevel.Disabled 33 | ); 34 | 35 | _powerManagementService.CommitCurrentPowerSchemeChanges(); 36 | } 37 | 38 | private void OnBatteryChargeLimitChanged(BatteryChargeLimitChangedMessage msg) 39 | { 40 | _asusHalService.SetBatteryChargeTarget(msg.Value); 41 | } 42 | 43 | private void OnPowerTargetsChanged(PowerTargetsChangedMessage msg) 44 | { 45 | _asusHalService.SetPlatformPowerTargets( 46 | msg.TotalSystemPPT, 47 | msg.CpuPPT 48 | ); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Slate/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Slate/FodyWeavers.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Used to control if the On_PropertyName_Changed feature is enabled. 12 | 13 | 14 | 15 | 16 | Used to control if the Dependent properties feature is enabled. 17 | 18 | 19 | 20 | 21 | Used to control if the IsChanged property feature is enabled. 22 | 23 | 24 | 25 | 26 | Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form. 27 | 28 | 29 | 30 | 31 | Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project. 32 | 33 | 34 | 35 | 36 | Used to control if equality checks should use the Equals method resolved from the base class. 37 | 38 | 39 | 40 | 41 | Used to control if equality checks should use the static Equals method resolved from the base class. 42 | 43 | 44 | 45 | 46 | Used to turn off build warnings from this weaver. 47 | 48 | 49 | 50 | 51 | Used to turn off build warnings about mismatched On_PropertyName_Changed methods. 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. 60 | 61 | 62 | 63 | 64 | A comma-separated list of error codes that can be safely ignored in assembly verification. 65 | 66 | 67 | 68 | 69 | 'false' to turn off automatic generation of the XML Schema file. 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Slate/Infrastructure/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.Linq; 4 | using LiveChartsCore.Defaults; 5 | using Slate.Asus; 6 | 7 | namespace Slate.Infrastructure 8 | { 9 | internal static class Extensions 10 | { 11 | public static ObservableCollection ToChartValues(this FanCurve curve, bool spaceOut = true) 12 | { 13 | if (spaceOut) 14 | { 15 | var copy = curve; 16 | 17 | for (var i = 0; i < copy.Points.Length - 1; i++) 18 | { 19 | var a = copy.Points[i + 1].Temperature; 20 | var b = copy.Points[i].Temperature; 21 | var diff = a - b; 22 | 23 | if (diff < 5) 24 | { 25 | for (var j = i; j >= 0; j--) 26 | { 27 | var newTemp = copy.Points[j].Temperature - (5 - diff); 28 | 29 | if (newTemp < FanCurve.MinimumTemperature) 30 | newTemp = FanCurve.MinimumTemperature + (j * 5); 31 | 32 | copy.Points[j].Temperature = (byte)newTemp; 33 | } 34 | } 35 | } 36 | 37 | curve = copy; 38 | } 39 | 40 | return new ObservableCollection( 41 | curve.Points.Select( 42 | x => new ObservablePoint( 43 | x.Temperature, 44 | x.RPM 45 | ) 46 | ) 47 | ); 48 | } 49 | 50 | public static FanCurve ToFanCurve(this ObservableCollection values) 51 | { 52 | var points = new FanCurvePoint[8]; 53 | 54 | for (var i = 0; i < 8; i++) 55 | { 56 | var x = (byte)(values[i].X!); 57 | var (y, _) = FanCurvePoint.Approximate((int)values[i].Y!); 58 | 59 | points[i] = new FanCurvePoint(x, y); 60 | } 61 | 62 | return new FanCurve(points); 63 | } 64 | 65 | public static string ToFourCharacterCode(this int value) 66 | { 67 | var bytes = BitConverter.GetBytes(value); 68 | return $"{(char)bytes[0]}{(char)bytes[1]}{(char)bytes[2]}{(char)bytes[3]}"; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Native/PowrProf.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Slate.Infrastructure.Native 5 | { 6 | internal static class PowrProf 7 | { 8 | public const string LibraryName = "powrprof.dll"; 9 | 10 | public static readonly Guid GUID_PROCESSOR_SETTINGS_SUBGROUP = new("54533251-82BE-4824-96C1-47B60B740D00"); 11 | public static readonly Guid GUID_PROCESSOR_PERFORMANCE_BOOST_SETTING = new("BE337238-0D82-4146-A960-4F3749D470C7"); 12 | 13 | [DllImport(LibraryName, CharSet = CharSet.Unicode)] 14 | public static extern nuint PowerGetActiveScheme( 15 | nint UserPowerKey, 16 | [Out, MarshalAs(UnmanagedType.LPStruct)] out Guid ActivePolicyGuid 17 | ); 18 | 19 | [DllImport(LibraryName, CharSet = CharSet.Unicode)] 20 | public static extern nuint PowerSetActiveScheme( 21 | nint RootPowerKey, 22 | [MarshalAs(UnmanagedType.LPStruct)] Guid SchemeGuid 23 | ); 24 | 25 | [DllImport(LibraryName, CharSet = CharSet.Unicode)] 26 | public static extern nuint PowerWriteDCValueIndex( 27 | nint RootPowerKey, 28 | [MarshalAs(UnmanagedType.LPStruct)] Guid SchemeGuid, 29 | [MarshalAs(UnmanagedType.LPStruct)] Guid SubGroupOfPowerSettingsGuid, 30 | [MarshalAs(UnmanagedType.LPStruct)] Guid PowerSettingGuid, 31 | int AcValueIndex 32 | ); 33 | 34 | [DllImport(LibraryName, CharSet = CharSet.Unicode)] 35 | public static extern nuint PowerWriteACValueIndex( 36 | nint RootPowerKey, 37 | [MarshalAs(UnmanagedType.LPStruct)] Guid SchemeGuid, 38 | [MarshalAs(UnmanagedType.LPStruct)] Guid SubGroupOfPowerSettingsGuid, 39 | [MarshalAs(UnmanagedType.LPStruct)] Guid PowerSettingGuid, 40 | int AcValueIndex 41 | ); 42 | 43 | [DllImport(LibraryName, CharSet = CharSet.Unicode)] 44 | public static extern nuint PowerReadACValueIndex( 45 | nint RootPowerKey, 46 | [MarshalAs(UnmanagedType.LPStruct)] Guid SchemeGuid, 47 | [MarshalAs(UnmanagedType.LPStruct)] Guid SubGroupOfPowerSettingsGuid, 48 | [MarshalAs(UnmanagedType.LPStruct)] Guid PowerSettingGuid, 49 | out int AcValueIndex 50 | ); 51 | 52 | [DllImport(LibraryName, CharSet = CharSet.Unicode)] 53 | public static extern nuint PowerReadDCValueIndex( 54 | nint RootPowerKey, 55 | [MarshalAs(UnmanagedType.LPStruct)] Guid SchemeGuid, 56 | [MarshalAs(UnmanagedType.LPStruct)] Guid SubGroupOfPowerSettingsGuid, 57 | [MarshalAs(UnmanagedType.LPStruct)] Guid PowerSettingGuid, 58 | out int AcValueIndex 59 | ); 60 | } 61 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/PowerManagement/PowerMode.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Infrastructure.PowerManagement 2 | { 3 | /** 4 | * Weisdjafjdsfj why not use a boolean? 5 | * IDK, looks nicer. More expressive I guess. 6 | * 7 | * Memory-efficiency? That's so 1980s. 8 | */ 9 | public enum PowerMode : byte /* Here, takes just 1 instead of 4 now. (: */ 10 | { 11 | AC, 12 | DC 13 | } 14 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/PowerManagement/ProcessorBoostLevel.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Infrastructure.PowerManagement 2 | { 3 | public enum ProcessorBoostLevel 4 | { 5 | Disabled, 6 | Enabled, 7 | Aggressive, 8 | EfficientEnabled, 9 | EfficientAggressive, 10 | AggressiveAtGuaranteed, 11 | EfficientAgressiveAtGuaranteed 12 | } 13 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IApplicationExecutionService.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm; 2 | 3 | namespace Slate.Infrastructure.Services 4 | { 5 | public interface IApplicationExecutionService : IService 6 | { 7 | void RunElevatedProcess(string path); 8 | } 9 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IAsusAnimeMatrixService.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm; 2 | using Starlight.Asus; 3 | using Starlight.Asus.AnimeMatrix; 4 | 5 | namespace Slate.Infrastructure.Services 6 | { 7 | public interface IAsusAnimeMatrixService : IService 8 | { 9 | void SetBrightness(BrightnessLevel level); 10 | void SetBuiltInAnimation(bool enable, AnimeMatrixBuiltIn builtIn); 11 | } 12 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IAsusAuraService.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using Glitonea.Mvvm; 3 | using Starlight.Asus.Aura; 4 | 5 | namespace Slate.Infrastructure.Services 6 | { 7 | public interface IAsusAuraService : IService 8 | { 9 | bool IsAvailable { get; } 10 | 11 | void WriteAuraSettings( 12 | AuraAnimation animation, 13 | Color primaryColor, 14 | Color secondaryColor, 15 | AuraAnimationSpeed speed 16 | ); 17 | } 18 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IAsusHalService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Management; 4 | using Glitonea.Mvvm; 5 | using Slate.Asus; 6 | 7 | namespace Slate.Infrastructure.Services 8 | { 9 | public interface IAsusHalService : IService 10 | { 11 | bool IsAcpiSessionOpen { get; } 12 | 13 | void SubscribeToWmiEvent(Action handler); 14 | void UnsubscribeFromWmiEvent(Action handler); 15 | void OpenAcpiSession(); 16 | int ReadCpuFanSpeed(); 17 | int ReadGpuFanSpeed(); 18 | float ReadCpuTemperatureCelsius(); 19 | float ReadGpuTemperatureCelsius(); 20 | void SetPerformancePreset(PerformancePreset preset); 21 | void SetCpuFanDutyCycle(byte dutyCycle); 22 | void SetGpuFanDutyCycle(byte dutyCycle); 23 | FanCurve ReadBuiltInCpuFanCurve(PerformancePreset performancePreset); 24 | FanCurve ReadBuiltInGpuFanCurve(PerformancePreset performancePreset); 25 | void WriteCpuFanCurve(FanCurve curve); 26 | void WriteGpuFanCurve(FanCurve curve); 27 | void SetGraphicsMode(MuxSwitchMode mode); 28 | MuxSwitchMode GetGraphicsMode(); 29 | void SetEcoMode(bool enable); 30 | bool GetEcoMode(); 31 | void SetDisplayOverdrive(bool enable); 32 | bool GetDisplayOverdrive(); 33 | void SetBatteryChargeTarget(int value); 34 | void SetPlatformPowerTargets(byte totalSystemPpt, byte cpuPpt); 35 | void DumpWmiRegisters(Stream outStream); 36 | int[] FetchFirmwareAcpiTableList(bool skipLicenseKeyTable = true); 37 | void DumpFirmwareAcpiTable(int tableId, Stream outStream); 38 | int[] FetchRegistryAcpiTableList(bool skipLicenseKeyTable = true); 39 | void DumpRegistryAcpiTable(int tableId, Stream outStream); 40 | void CloseAcpiSession(); 41 | 42 | } 43 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IDisplayManagementService.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm; 2 | 3 | namespace Slate.Infrastructure.Services 4 | { 5 | public interface IDisplayManagementService : IService 6 | { 7 | bool SetInternalDisplayRefreshRate(uint refreshRate); 8 | uint GetInternalDisplayRefreshRate(); 9 | } 10 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IHardwareMonitorService.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm; 2 | 3 | namespace Slate.Infrastructure.Services 4 | { 5 | public interface IHardwareMonitorService : IService 6 | { 7 | int CpuFanRPM { get; } 8 | int CpuTemperature { get; } 9 | 10 | int GpuFanRPM { get; } 11 | int GpuTemperature { get; } 12 | } 13 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IInputInjectionService.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm; 2 | using Slate.Model; 3 | 4 | namespace Slate.Infrastructure.Services 5 | { 6 | public interface IInputInjectionService : IService 7 | { 8 | void SimulateMediaKeyPress(MediaKey mediaKey); 9 | } 10 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IPowerManagementService.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm; 2 | using Slate.Infrastructure.PowerManagement; 3 | 4 | namespace Slate.Infrastructure.Services 5 | { 6 | public interface IPowerManagementService : IService 7 | { 8 | ProcessorBoostLevel ReadProcessorBoostState(PowerMode powerMode); 9 | void WriteProcessorBoostState(PowerMode powerMode, ProcessorBoostLevel boostLevel); 10 | 11 | void CommitCurrentPowerSchemeChanges(); 12 | } 13 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/ISettingsService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Glitonea.Mvvm; 3 | using Slate.Model.Settings; 4 | 5 | namespace Slate.Infrastructure.Services 6 | { 7 | public interface ISettingsService : IService 8 | { 9 | ControlCenterSettings? ControlCenter { get; } 10 | Task Save(); 11 | } 12 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IShutdownService.cs: -------------------------------------------------------------------------------- 1 | using Glitonea.Mvvm; 2 | 3 | namespace Slate.Infrastructure.Services 4 | { 5 | public interface IShutdownService : IService 6 | { 7 | void RequestSystemReboot(string reason); 8 | } 9 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IStorageService.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Glitonea.Mvvm; 3 | 4 | namespace Slate.Infrastructure.Services 5 | { 6 | public interface IStorageService : IService 7 | { 8 | string BaseDirectory { get; } 9 | 10 | FileStream CreateFile(string storageRelativePath); 11 | FileStream OpenOrCreateFile(string storageRelativePath); 12 | } 13 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/IWmiEventService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Management; 3 | using Glitonea.Mvvm; 4 | 5 | namespace Slate.Infrastructure.Services 6 | { 7 | public interface IWmiEventService : IService 8 | { 9 | void SubscribeTo(string eventProvider, Action handler); 10 | void UnsubscribeFrom(string eventProvider, Action handler); 11 | } 12 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/ApplicationExecutionService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | 4 | namespace Slate.Infrastructure.Services.Implementations 5 | { 6 | public class ApplicationExecutionService : IApplicationExecutionService 7 | { 8 | public void RunElevatedProcess(string path) 9 | { 10 | Process.Start(new ProcessStartInfo 11 | { 12 | UseShellExecute = true, 13 | WorkingDirectory = Path.GetDirectoryName(path), 14 | FileName = path, 15 | Verb = "runas" 16 | }); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/AsusAnimeMatrixService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Starlight.Asus; 3 | using Starlight.Asus.AnimeMatrix; 4 | 5 | namespace Slate.Infrastructure.Services.Implementations 6 | { 7 | public class AsusAnimeMatrixService : IAsusAnimeMatrixService, IDisposable 8 | { 9 | private readonly AnimeMatrixDevice _device; 10 | 11 | public AsusAnimeMatrixService() 12 | { 13 | _device = new AnimeMatrixDevice(); 14 | } 15 | 16 | public void SetBrightness(BrightnessLevel level) 17 | => _device.SetBrightness(level); 18 | 19 | public void SetBuiltInAnimation(bool enable, AnimeMatrixBuiltIn builtIn) 20 | => _device.SetBuiltInAnimation(enable, builtIn); 21 | 22 | public void Dispose() 23 | { 24 | _device.Dispose(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/AsusAuraService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using Starlight.Asus.Aura; 4 | 5 | namespace Slate.Infrastructure.Services.Implementations 6 | { 7 | public class AsusAuraService : IAsusAuraService, IDisposable 8 | { 9 | private readonly AuraDevice? _auraDevice; 10 | 11 | public bool IsAvailable => _auraDevice != null; 12 | 13 | public AsusAuraService() 14 | { 15 | try 16 | { 17 | _auraDevice = new AuraDevice(); 18 | } 19 | catch 20 | { 21 | /* Ignore any exceptions. */ 22 | } 23 | } 24 | 25 | public void WriteAuraSettings( 26 | AuraAnimation animation, 27 | Color primaryColor, 28 | Color secondaryColor, 29 | AuraAnimationSpeed speed 30 | ) 31 | { 32 | ThrowIfUnavailable(); 33 | 34 | _auraDevice!.Mode.Animate( 35 | 0, 36 | animation, 37 | primaryColor, 38 | secondaryColor, 39 | speed 40 | ); 41 | } 42 | 43 | public void Dispose() 44 | => _auraDevice?.Dispose(); 45 | 46 | private void ThrowIfUnavailable() 47 | { 48 | if (!IsAvailable) 49 | throw new InvalidOperationException("ASUS Aura device was not found on your system."); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/DisplayManagementService.cs: -------------------------------------------------------------------------------- 1 | using Slate.Infrastructure.Native; 2 | 3 | namespace Slate.Infrastructure.Services.Implementations 4 | { 5 | public class DisplayManagementService : IDisplayManagementService 6 | { 7 | public bool SetInternalDisplayRefreshRate(uint refreshRate) 8 | { 9 | if (User32.QueryDisplayConfig( 10 | User32.QDC.ONLY_ACTIVE_PATHS, 11 | out var pathInfos, 12 | out var modeInfos, 13 | out _ 14 | ) != 0) 15 | { 16 | return false; 17 | } 18 | 19 | for (var i = 0; i < pathInfos.Length; i++) 20 | { 21 | var path = pathInfos[i]; 22 | 23 | if ((path.flags & 1) != 0 24 | && (path.targetInfo.outputTechnology & User32.DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY.INTERNAL) != 0) 25 | { 26 | for (var j = 0; j < modeInfos.Length; j++) 27 | { 28 | var mode = modeInfos[j]; 29 | 30 | if (mode.infoType == User32.DISPLAYCONFIG_MODE_INFO_TYPE.TARGET && 31 | mode.id == path.targetInfo.id) 32 | { 33 | modeInfos[j].targetMode.targetVideoSignalInfo.vSyncFreq.Numerator = refreshRate; 34 | } 35 | } 36 | } 37 | } 38 | 39 | return User32.SetDisplayConfig( 40 | (uint)pathInfos.Length, 41 | pathInfos, 42 | (uint)modeInfos.Length, 43 | modeInfos, 44 | User32.SDC.APPLY 45 | | User32.SDC.USE_SUPPLIED_DISPLAY_CONFIG 46 | | User32.SDC.SAVE_TO_DATABASE 47 | ) == 0; 48 | } 49 | 50 | public uint GetInternalDisplayRefreshRate() 51 | { 52 | if (User32.QueryDisplayConfig( 53 | User32.QDC.ONLY_ACTIVE_PATHS, 54 | out var pathInfos, 55 | out var modeInfos, 56 | out _ 57 | ) == 0) 58 | { 59 | for (var i = 0; i < pathInfos.Length; i++) 60 | { 61 | var path = pathInfos[i]; 62 | 63 | if ((path.flags & 1) != 0 64 | && (path.targetInfo.outputTechnology 65 | & User32.DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY.INTERNAL) != 0) 66 | { 67 | for (var j = 0; j < modeInfos.Length; j++) 68 | { 69 | var mode = modeInfos[j]; 70 | 71 | if (mode.infoType == User32.DISPLAYCONFIG_MODE_INFO_TYPE.TARGET && 72 | mode.id == path.targetInfo.id) 73 | { 74 | return modeInfos[j].targetMode.targetVideoSignalInfo.vSyncFreq.Numerator; 75 | } 76 | } 77 | } 78 | } 79 | } 80 | 81 | return 0; 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/HardwareMonitorService.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Glitonea.Mvvm.Messaging; 3 | using Slate.Model.Messaging; 4 | 5 | namespace Slate.Infrastructure.Services.Implementations 6 | { 7 | public class HardwareMonitorService : IHardwareMonitorService, INotifyPropertyChanged 8 | { 9 | private readonly IAsusHalService _asusHalService; 10 | 11 | public event PropertyChangedEventHandler? PropertyChanged; 12 | 13 | public int CpuFanRPM { get; private set; } 14 | public int CpuTemperature { get; private set; } 15 | 16 | public int GpuFanRPM { get; private set; } 17 | public int GpuTemperature { get; private set; } 18 | 19 | public HardwareMonitorService(IAsusHalService asusHalService) 20 | { 21 | _asusHalService = asusHalService; 22 | 23 | Message.Subscribe(this, OnGlobalTick); 24 | } 25 | 26 | private void OnGlobalTick(GlobalTickMessage _) 27 | { 28 | if (!_asusHalService.IsAcpiSessionOpen) 29 | return; 30 | 31 | CpuFanRPM = _asusHalService.ReadCpuFanSpeed(); 32 | CpuTemperature = (int)_asusHalService.ReadCpuTemperatureCelsius(); 33 | 34 | GpuFanRPM = _asusHalService.ReadGpuFanSpeed(); 35 | GpuTemperature = (int)_asusHalService.ReadGpuTemperatureCelsius(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/InputInjectionService.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Slate.Infrastructure.Native; 3 | using Slate.Model; 4 | 5 | namespace Slate.Infrastructure.Services.Implementations 6 | { 7 | public class InputInjectionService : IInputInjectionService 8 | { 9 | public void SimulateMediaKeyPress(MediaKey mediaKey) 10 | { 11 | switch (mediaKey) 12 | { 13 | case MediaKey.Previous: 14 | SendInput(User32.VK_MEDIA_PREV_TRACK); 15 | break; 16 | 17 | case MediaKey.PlayPause: 18 | SendInput(User32.VK_MEDIA_PLAY_PAUSE); 19 | break; 20 | 21 | case MediaKey.Stop: 22 | SendInput(User32.VK_MEDIA_STOP); 23 | break; 24 | 25 | case MediaKey.Next: 26 | SendInput(User32.VK_MEDIA_NEXT_TRACK); 27 | break; 28 | } 29 | } 30 | 31 | private void SendInput(ushort vkCode) 32 | { 33 | var inputDown = new User32.INPUT 34 | { 35 | type = User32.INPUT_TYPE.KEYBOARD, 36 | union = new User32.INPUTUNION 37 | { 38 | ki = new User32.KEYBDINPUT 39 | { 40 | wVk = vkCode, 41 | dwFlags = 0 42 | } 43 | } 44 | }; 45 | 46 | var inputUp = new User32.INPUT 47 | { 48 | type = User32.INPUT_TYPE.KEYBOARD, 49 | union = new User32.INPUTUNION 50 | { 51 | ki = new User32.KEYBDINPUT 52 | { 53 | wVk = vkCode, 54 | dwFlags = User32.KEYEVENTF.KEYUP 55 | } 56 | } 57 | }; 58 | 59 | User32.SendInput(2, new[] { inputDown, inputUp }, Marshal.SizeOf()); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/PowerManagementService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Slate.Infrastructure.Native; 3 | using Slate.Infrastructure.PowerManagement; 4 | 5 | namespace Slate.Infrastructure.Services.Implementations 6 | { 7 | public class PowerManagementService : IPowerManagementService 8 | { 9 | public ProcessorBoostLevel ReadProcessorBoostState(PowerMode powerMode) 10 | { 11 | PowrProf.PowerGetActiveScheme(0, out var activeSchemeGuid); 12 | 13 | if (powerMode == PowerMode.AC) 14 | { 15 | PowrProf.PowerReadACValueIndex( 16 | nint.Zero, 17 | activeSchemeGuid, 18 | PowrProf.GUID_PROCESSOR_SETTINGS_SUBGROUP, 19 | PowrProf.GUID_PROCESSOR_PERFORMANCE_BOOST_SETTING, 20 | out int value 21 | ); 22 | 23 | return (ProcessorBoostLevel)value; 24 | } 25 | else if (powerMode == PowerMode.DC) 26 | { 27 | PowrProf.PowerReadDCValueIndex( 28 | nint.Zero, 29 | activeSchemeGuid, 30 | PowrProf.GUID_PROCESSOR_SETTINGS_SUBGROUP, 31 | PowrProf.GUID_PROCESSOR_PERFORMANCE_BOOST_SETTING, 32 | out int value 33 | ); 34 | 35 | return (ProcessorBoostLevel)value; 36 | } 37 | 38 | /** 39 | * Boo-hoo it would have been avoided by design if only you used a boolean. 40 | * Shut it. It's open-source and I'm having fun here. 41 | */ 42 | throw new ArgumentException($"Invalid power mode provided UwU: {powerMode}."); 43 | } 44 | 45 | public void WriteProcessorBoostState(PowerMode powerMode, ProcessorBoostLevel boostLevel) 46 | { 47 | PowrProf.PowerGetActiveScheme(0, out var activeSchemeGuid); 48 | 49 | if (powerMode == PowerMode.AC) 50 | { 51 | PowrProf.PowerWriteACValueIndex( 52 | nint.Zero, 53 | activeSchemeGuid, 54 | PowrProf.GUID_PROCESSOR_SETTINGS_SUBGROUP, 55 | PowrProf.GUID_PROCESSOR_PERFORMANCE_BOOST_SETTING, 56 | (int)boostLevel 57 | ); 58 | } 59 | else if (powerMode == PowerMode.DC) 60 | { 61 | PowrProf.PowerWriteDCValueIndex( 62 | nint.Zero, 63 | activeSchemeGuid, 64 | PowrProf.GUID_PROCESSOR_SETTINGS_SUBGROUP, 65 | PowrProf.GUID_PROCESSOR_PERFORMANCE_BOOST_SETTING, 66 | (int)boostLevel 67 | ); 68 | 69 | } 70 | else 71 | { 72 | throw new ArgumentException($"Invalid power mode provided UwU: {powerMode}."); 73 | } 74 | } 75 | 76 | public void CommitCurrentPowerSchemeChanges() 77 | { 78 | PowrProf.PowerGetActiveScheme(0, out var activeSchemeGuid); 79 | PowrProf.PowerSetActiveScheme(0, activeSchemeGuid); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/SettingsService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text.Json; 4 | using System.Threading.Tasks; 5 | using Slate.Model.Settings; 6 | 7 | namespace Slate.Infrastructure.Services.Implementations 8 | { 9 | public class SettingsService : ISettingsService 10 | { 11 | private const string SettingsFileName = "zcc_settings.json"; 12 | 13 | private readonly IStorageService _storageService; 14 | 15 | public ControlCenterSettings? ControlCenter { get; private set; } 16 | 17 | public SettingsService(IStorageService storageService) 18 | { 19 | _storageService = storageService; 20 | ReadOrCreateSettings(); 21 | } 22 | 23 | public async Task Save() 24 | { 25 | using (var fs = _storageService.CreateFile(SettingsFileName)) 26 | { 27 | await JsonSerializer.SerializeAsync(fs, ControlCenter, new JsonSerializerOptions 28 | { 29 | WriteIndented = true, 30 | }); 31 | } 32 | } 33 | 34 | private void ReadOrCreateSettings() 35 | { 36 | try 37 | { 38 | using (var fs = _storageService.OpenOrCreateFile(SettingsFileName)) 39 | using (var sr = new StreamReader(fs)) 40 | { 41 | ControlCenter = JsonSerializer.Deserialize( 42 | sr.ReadToEnd() 43 | ); 44 | } 45 | } 46 | catch (Exception) 47 | { 48 | // todo show a message box, log a failure. anything. 49 | ControlCenter = new ControlCenterSettings(); 50 | Save().Wait(); 51 | } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/ShutdownService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Slate.Infrastructure.Services.Implementations 4 | { 5 | public class ShutdownService : IShutdownService 6 | { 7 | public void RequestSystemReboot(string reason) 8 | { 9 | Process.Start( 10 | new ProcessStartInfo("shutdown.exe", $"/r /f /t 0 /c \"{reason}\"") 11 | { 12 | UseShellExecute = true 13 | } 14 | ); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/StorageService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Slate.Infrastructure.Services.Implementations 5 | { 6 | public class StorageService : IStorageService 7 | { 8 | private const string AppStorageDirectoryName = "ZephyrusControlCenter"; 9 | 10 | public string BaseDirectory { get; } 11 | 12 | public StorageService() 13 | { 14 | BaseDirectory = GetOrCreateUserDataDirectory(); 15 | } 16 | 17 | public FileStream CreateFile(string storageRelativePath) 18 | { 19 | var absolutePath = Path.Combine(BaseDirectory, storageRelativePath); 20 | var targetDirectory = Path.GetDirectoryName(absolutePath); 21 | 22 | Directory.CreateDirectory(targetDirectory!); 23 | 24 | return new FileStream( 25 | absolutePath, 26 | FileMode.Create, 27 | FileAccess.ReadWrite, 28 | FileShare.Read 29 | ); 30 | } 31 | 32 | public FileStream OpenOrCreateFile(string storageRelativePath) 33 | { 34 | var absolutePath = Path.Combine(BaseDirectory, storageRelativePath); 35 | var targetDirectory = Path.GetDirectoryName(absolutePath); 36 | 37 | Directory.CreateDirectory(targetDirectory!); 38 | 39 | return new FileStream( 40 | absolutePath, 41 | FileMode.OpenOrCreate, 42 | FileAccess.ReadWrite, 43 | FileShare.Read 44 | ); 45 | } 46 | 47 | private string GetOrCreateUserDataDirectory() 48 | { 49 | var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 50 | var appSettingsPath = Path.Combine(appDataPath, AppStorageDirectoryName); 51 | 52 | Directory.CreateDirectory(appSettingsPath); 53 | 54 | return appSettingsPath; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Services/Implementations/WmiEventService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Management; 5 | using Slate.Infrastructure.WMI; 6 | 7 | namespace Slate.Infrastructure.Services.Implementations 8 | { 9 | public class WmiEventService : IWmiEventService, IDisposable 10 | { 11 | private Dictionary? _eventRegistry = new(); 12 | 13 | public void SubscribeTo(string eventProvider, Action handler) 14 | { 15 | ThrowIfDisposed(); 16 | 17 | if (!_eventRegistry!.ContainsKey(eventProvider)) 18 | { 19 | _eventRegistry.Add(eventProvider, new ManagementEvent(eventProvider)); 20 | } 21 | 22 | _eventRegistry[eventProvider].Subscribe(handler); 23 | } 24 | 25 | public void UnsubscribeFrom(string eventProvider, Action handler) 26 | { 27 | ThrowIfDisposed(); 28 | 29 | if (!_eventRegistry!.ContainsKey(eventProvider)) 30 | { 31 | return; 32 | } 33 | 34 | _eventRegistry[eventProvider].Unsubscribe(handler); 35 | 36 | if (!_eventRegistry.Any()) 37 | { 38 | _eventRegistry.Remove(eventProvider); 39 | } 40 | } 41 | 42 | public void Dispose() 43 | { 44 | if (_eventRegistry == null) 45 | { 46 | throw new InvalidOperationException("This service has already been disposed."); 47 | } 48 | 49 | foreach (var kvp in _eventRegistry) 50 | { 51 | kvp.Value.Dispose(); 52 | } 53 | 54 | _eventRegistry.Clear(); 55 | _eventRegistry = null; 56 | } 57 | 58 | private void ThrowIfDisposed() 59 | { 60 | if (_eventRegistry == null) 61 | { 62 | throw new InvalidOperationException("This service has been disposed."); 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Settings/SettingsBase.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Infrastructure.Settings 2 | { 3 | public abstract class SettingsBase : SettingsComponent 4 | { 5 | // Marker 6 | } 7 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/Settings/SettingsComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using Slate.Model.Messaging; 4 | 5 | namespace Slate.Infrastructure.Settings 6 | { 7 | public abstract class SettingsComponent : INotifyPropertyChanged 8 | { 9 | private bool _isEventSuppresed; 10 | 11 | public event PropertyChangedEventHandler? PropertyChanged; 12 | 13 | protected SettingsComponent() 14 | { 15 | PropertyChanged += RaiseSettingsModified; 16 | } 17 | 18 | protected void RaiseSettingsModified(object? sender, PropertyChangedEventArgs e) 19 | { 20 | if (_isEventSuppresed) 21 | return; 22 | 23 | OnSettingsModified(e.PropertyName); 24 | 25 | new SettingsModifiedMessage(this, e.PropertyName) 26 | .Broadcast(); 27 | } 28 | 29 | protected virtual void OnSettingsModified(string? propertyName) 30 | { 31 | } 32 | 33 | protected void WithEventSuppressed(Action action) 34 | { 35 | _isEventSuppresed = true; 36 | 37 | try 38 | { 39 | action(); 40 | } 41 | finally 42 | { 43 | _isEventSuppresed = false; 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/SystemParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using Avalonia.Controls; 3 | using Slate.Infrastructure.Native; 4 | 5 | namespace Slate.Infrastructure 6 | { 7 | public static class SystemParameters 8 | { 9 | public static Size PrimaryScreenSize => new( 10 | User32.GetSystemMetrics(User32.SM_CXSCREEN), 11 | User32.GetSystemMetrics(User32.SM_CYSCREEN) 12 | ); 13 | 14 | public static Size WorkingAreaSize 15 | { 16 | get 17 | { 18 | var rect = new User32.RECT(); 19 | 20 | User32.SystemParametersInfoW(User32.SPI_GETWORKAREA, 0, ref rect, 0); 21 | 22 | return new(rect.right - rect.left, rect.bottom - rect.top); 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Slate/Infrastructure/WMI/ManagementEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Management; 4 | 5 | namespace Slate.Infrastructure.WMI 6 | { 7 | public class ManagementEvent : IDisposable 8 | { 9 | private ManagementEventWatcher Watcher { get; } 10 | private HashSet> Subscribers { get; } = new(); 11 | 12 | public ManagementEvent(string eventProvider) 13 | { 14 | Watcher = new ManagementEventWatcher( 15 | "root\\WMI", 16 | $"SELECT * FROM {eventProvider}" 17 | ); 18 | 19 | Watcher.EventArrived += Watcher_EventArrived; 20 | Watcher.Start(); 21 | } 22 | 23 | public void Subscribe(Action subscriber) 24 | { 25 | Subscribers.Add(subscriber); 26 | } 27 | 28 | public void Unsubscribe(Action subscriber) 29 | { 30 | Subscribers.Remove(subscriber); 31 | } 32 | 33 | private void Watcher_EventArrived(object sender, EventArrivedEventArgs e) 34 | { 35 | var invocationList = new List>(Subscribers); 36 | 37 | foreach (var subscriber in invocationList) 38 | subscriber.Invoke(e.NewEvent); 39 | } 40 | 41 | public void Dispose() 42 | { 43 | Watcher.Stop(); 44 | Watcher.Dispose(); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Slate/Model/ColorWrapper.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Slate.Model 5 | { 6 | public record ColorWrapper : INotifyPropertyChanged 7 | { 8 | public byte R { get; set; } 9 | public byte G { get; set; } 10 | public byte B { get; set; } 11 | 12 | [JsonIgnore] 13 | public System.Drawing.Color HardwareColor 14 | { 15 | get => System.Drawing.Color.FromArgb(R, G, B); 16 | set 17 | { 18 | R = value.R; 19 | G = value.G; 20 | B = value.B; 21 | } 22 | } 23 | 24 | [JsonIgnore] 25 | public Avalonia.Media.Color MediaRGB 26 | { 27 | get => Avalonia.Media.Color.FromRgb(R, G, B); 28 | set 29 | { 30 | R = value.R; 31 | G = value.G; 32 | B = value.B; 33 | } 34 | } 35 | 36 | [JsonIgnore] 37 | public Avalonia.Media.HsvColor MediaHSV 38 | { 39 | get => new(MediaRGB); 40 | set => MediaRGB = value.ToRgb(); 41 | } 42 | 43 | public event PropertyChangedEventHandler? PropertyChanged; 44 | 45 | public ColorWrapper() 46 | { 47 | } 48 | 49 | public ColorWrapper(System.Drawing.Color color) 50 | { 51 | HardwareColor = color; 52 | } 53 | 54 | public ColorWrapper(Avalonia.Media.Color color) 55 | { 56 | MediaRGB = color; 57 | } 58 | 59 | public ColorWrapper(byte r, byte g, byte b) 60 | : this() 61 | { 62 | R = r; 63 | G = g; 64 | B = b; 65 | } 66 | 67 | } 68 | } -------------------------------------------------------------------------------- /Slate/Model/KeyBind.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Model 2 | { 3 | public struct KeyBind 4 | { 5 | public KeyBindMode Mode { get; set; } = KeyBindMode.Default; 6 | public MediaKey MediaKey { get; set; } = MediaKey.PlayPause; 7 | 8 | public string? Command { get; set; } 9 | 10 | public KeyBind() 11 | { 12 | } 13 | 14 | public KeyBind(KeyBindMode mode) 15 | { 16 | Mode = mode; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Slate/Model/KeyBindMode.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Model 2 | { 3 | public enum KeyBindMode 4 | { 5 | Default, 6 | Media, 7 | Command 8 | } 9 | } -------------------------------------------------------------------------------- /Slate/Model/MediaKey.cs: -------------------------------------------------------------------------------- 1 | namespace Slate.Model 2 | { 3 | public enum MediaKey 4 | { 5 | Previous, 6 | Next, 7 | Stop, 8 | PlayPause 9 | } 10 | } -------------------------------------------------------------------------------- /Slate/Model/Messaging/Messages.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Media; 2 | using Glitonea.Mvvm.Messaging; 3 | using Slate.Asus; 4 | using Slate.Infrastructure.Settings; 5 | using Slate.View; 6 | using Starlight.Asus; 7 | using Starlight.Asus.AnimeMatrix; 8 | using Starlight.Asus.Aura; 9 | 10 | namespace Slate.Model.Messaging 11 | { 12 | public sealed record GlobalTickMessage(ulong TotalTicksElapsed) 13 | : Message; 14 | 15 | public sealed record TrayIconClickedMessage 16 | : Message; 17 | 18 | public sealed record MainWindowLoadedMessage 19 | : Message; 20 | 21 | public sealed record MainWindowTransitionFinishedMessage(bool WasSlidingIn) 22 | : Message; 23 | 24 | public sealed record NavigationRequestedMessage(PageMarker PageMarker) 25 | : Message; 26 | 27 | public sealed record NavigatedToPageMessage(PageMarker PageMarker) 28 | : Message; 29 | 30 | public sealed record NavigatedBackMessage(PageMarker CurrentPage) 31 | : Message; 32 | 33 | public sealed record SettingsModifiedMessage( 34 | SettingsComponent Origin, 35 | string? PropertyName 36 | ) : Message; 37 | 38 | public sealed record StartupLaunchChangedMessage(bool Enabled) 39 | : Message; 40 | 41 | public sealed record UpdateCheckChangedMessage(bool Enabled) 42 | : Message; 43 | 44 | public sealed record CpuFanCurveUpdatedMessage(FanCurve Curve) 45 | : Message; 46 | 47 | public sealed record GpuFanCurveUpdatedMessage(FanCurve Curve) 48 | : Message; 49 | 50 | public sealed record PerformancePresetUpdatedMessage(PerformancePreset Preset) 51 | : Message; 52 | 53 | public sealed record ManualFanOverrideUpdatedMessage( 54 | bool IsOverrideEnabled, 55 | byte CpuDutyCycle, 56 | byte GpuDutyCycle 57 | ) : Message; 58 | 59 | public sealed record MuxSwitchModeChangedMessage(MuxSwitchMode MuxSwitchMode) 60 | : Message; 61 | 62 | public sealed record EcoModeChangedMessage(bool Enabled) 63 | : Message; 64 | 65 | public sealed record EcoModeTransitionStartedMessage 66 | : Message; 67 | 68 | public sealed record EcoModeTransitionFinishedMessage 69 | : Message; 70 | 71 | public sealed record DisplayOverdriveChangedMessage(bool Enabled) 72 | : Message; 73 | 74 | public sealed record DisplayRefreshRateChangedMessage(uint RefreshRate) 75 | : Message; 76 | 77 | public sealed record CpuBoostModeChangedMessage( 78 | bool EnableOnAC, 79 | bool EnableOnDC 80 | ) : Message; 81 | 82 | public sealed record BatteryChargeLimitChangedMessage(int Value) 83 | : Message; 84 | 85 | public sealed record PowerTargetsChangedMessage( 86 | byte TotalSystemPPT, 87 | byte CpuPPT 88 | ) : Message; 89 | 90 | public sealed record AuraSettingsChangedMessage( 91 | AuraAnimation Animation, 92 | System.Drawing.Color PrimaryColor, 93 | System.Drawing.Color SecondaryColor, 94 | AuraAnimationSpeed AnimationSpeed 95 | ) : Message; 96 | 97 | public sealed record AuraFollowSystemAccentColorStateChangedMessage( 98 | bool Enabled 99 | ) : Message; 100 | 101 | public sealed record AniMeMatrixBrightnessChangedMessage( 102 | BrightnessLevel BrightnessLevel 103 | ) : Message; 104 | 105 | public sealed record AniMeMatrixBuiltInsChangedMessage( 106 | bool PreferPowerSavingAnimation, 107 | AnimeMatrixBuiltIn BuiltInConfiguration 108 | ) : Message; 109 | 110 | public sealed record SystemAccentColorChangedMessage( 111 | Color PrimaryAccentColor, 112 | Color SecondaryAccentColor, 113 | Color TertiaryAccentColor 114 | ) : Message; 115 | } -------------------------------------------------------------------------------- /Slate/Model/Settings/Components/AniMeMatrixSettings.cs: -------------------------------------------------------------------------------- 1 | using Slate.Infrastructure.Settings; 2 | using Slate.Model.Messaging; 3 | using Starlight.Asus; 4 | using Starlight.Asus.AnimeMatrix; 5 | 6 | namespace Slate.Model.Settings.Components 7 | { 8 | public class AniMeMatrixSettings : SettingsComponent 9 | { 10 | public BrightnessLevel Brightness { get; set; } = BrightnessLevel.Bright; 11 | 12 | public bool PreferPowerSavingAnimation { get; set; } = true; 13 | public AnimeMatrixBuiltIn.Running RunningBuiltIn { get; set; } = AnimeMatrixBuiltIn.Running.RogLogoGlitch; 14 | public AnimeMatrixBuiltIn.Sleeping SleepingBuiltIn { get; set; } = AnimeMatrixBuiltIn.Sleeping.Starfield; 15 | public AnimeMatrixBuiltIn.Shutdown ShutdownBuiltIn { get; set; } = AnimeMatrixBuiltIn.Shutdown.GlitchOut; 16 | public AnimeMatrixBuiltIn.Startup StartupBuiltIn { get; set; } = AnimeMatrixBuiltIn.Startup.GlitchConstruction; 17 | 18 | protected override void OnSettingsModified(string? propertyName) 19 | { 20 | switch (propertyName) 21 | { 22 | case nameof(Brightness): 23 | { 24 | new AniMeMatrixBrightnessChangedMessage(Brightness) 25 | .Broadcast(); 26 | 27 | break; 28 | } 29 | 30 | case nameof(PreferPowerSavingAnimation): 31 | case nameof(RunningBuiltIn) when PreferPowerSavingAnimation: 32 | case nameof(SleepingBuiltIn): 33 | case nameof(ShutdownBuiltIn): 34 | case nameof(StartupBuiltIn): 35 | { 36 | new AniMeMatrixBuiltInsChangedMessage( 37 | PreferPowerSavingAnimation, 38 | new AnimeMatrixBuiltIn( 39 | RunningBuiltIn, 40 | SleepingBuiltIn, 41 | ShutdownBuiltIn, 42 | StartupBuiltIn 43 | ) 44 | ).Broadcast(); 45 | 46 | break; 47 | } 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Slate/Model/Settings/Components/ApplicationSettings.cs: -------------------------------------------------------------------------------- 1 | using Slate.Infrastructure.Settings; 2 | using Slate.Model.Messaging; 3 | 4 | namespace Slate.Model.Settings.Components 5 | { 6 | public class ApplicationSettings : SettingsComponent 7 | { 8 | public bool RunOnStartup { get; set; } 9 | public bool CheckForUpdates { get; set; } 10 | 11 | protected override void OnSettingsModified(string? propertyName) 12 | { 13 | switch (propertyName) 14 | { 15 | case nameof(RunOnStartup): 16 | { 17 | WithEventSuppressed(() => 18 | { 19 | new StartupLaunchChangedMessage(RunOnStartup) 20 | .Broadcast(); 21 | }); 22 | 23 | break; 24 | } 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Slate/Model/Settings/Components/FansSettings.cs: -------------------------------------------------------------------------------- 1 | using Slate.Asus; 2 | using Slate.Infrastructure.Settings; 3 | using Slate.Model.Messaging; 4 | 5 | namespace Slate.Model.Settings.Components 6 | { 7 | public class FansSettings : SettingsComponent 8 | { 9 | public FanCurve? CpuFanCurve { get; set; } 10 | public FanCurve? GpuFanCurve { get; set; } 11 | 12 | public PerformancePreset PerformancePreset { get; set; } = PerformancePreset.Balanced; 13 | public bool IsManualOverrideEnabled { get; set; } = false; 14 | public byte ManualCpuFanDutyCycle { get; set; } = 64; 15 | public byte ManualGpuFanDutyCycle { get; set; } = 64; 16 | 17 | protected override void OnSettingsModified(string? propertyName) 18 | { 19 | switch (propertyName) 20 | { 21 | case nameof(PerformancePreset): 22 | { 23 | new PerformancePresetUpdatedMessage(PerformancePreset) 24 | .Broadcast(); 25 | 26 | break; 27 | } 28 | 29 | case nameof(CpuFanCurve): 30 | { 31 | new CpuFanCurveUpdatedMessage(CpuFanCurve!) 32 | .Broadcast(); 33 | 34 | break; 35 | } 36 | 37 | case nameof(GpuFanCurve): 38 | { 39 | new GpuFanCurveUpdatedMessage(GpuFanCurve!) 40 | .Broadcast(); 41 | 42 | break; 43 | } 44 | 45 | case nameof(IsManualOverrideEnabled): 46 | case nameof(ManualCpuFanDutyCycle) when IsManualOverrideEnabled: 47 | case nameof(ManualGpuFanDutyCycle) when IsManualOverrideEnabled: 48 | { 49 | new ManualFanOverrideUpdatedMessage( 50 | IsManualOverrideEnabled, 51 | ManualCpuFanDutyCycle, 52 | ManualGpuFanDutyCycle 53 | ).Broadcast(); 54 | 55 | break; 56 | } 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Slate/Model/Settings/Components/GraphicsAndDisplaySettings.cs: -------------------------------------------------------------------------------- 1 | using Slate.Asus; 2 | using Slate.Infrastructure; 3 | using Slate.Infrastructure.Settings; 4 | using Slate.Model.Messaging; 5 | 6 | namespace Slate.Model.Settings.Components 7 | { 8 | public class GraphicsAndDisplaySettings : SettingsComponent 9 | { 10 | public bool? IsEcoModeEnabled { get; set; } 11 | public bool? IsDisplayOverdriveEnabled { get; set; } 12 | public uint DisplayRefreshRate { get; set; } = 144; 13 | 14 | public MuxSwitchMode? MuxSwitchMode { get; set; } 15 | 16 | protected override void OnSettingsModified(string? propertyName) 17 | { 18 | switch (propertyName) 19 | { 20 | case nameof(IsEcoModeEnabled): 21 | { 22 | new EcoModeChangedMessage( 23 | IsEcoModeEnabled!.Value 24 | ).Broadcast(); 25 | 26 | break; 27 | } 28 | 29 | case nameof(IsDisplayOverdriveEnabled): 30 | { 31 | new DisplayOverdriveChangedMessage( 32 | IsDisplayOverdriveEnabled!.Value 33 | ).Broadcast(); 34 | 35 | break; 36 | } 37 | 38 | case nameof(DisplayRefreshRate): 39 | { 40 | new DisplayRefreshRateChangedMessage( 41 | DisplayRefreshRate 42 | ).Broadcast(); 43 | 44 | break; 45 | } 46 | 47 | case nameof(MuxSwitchMode): 48 | { 49 | new MuxSwitchModeChangedMessage( 50 | MuxSwitchMode!.Value 51 | ).Broadcast(); 52 | 53 | break; 54 | } 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Slate/Model/Settings/Components/KeyboardSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using Slate.Infrastructure.Settings; 3 | using Slate.Model.Messaging; 4 | using Starlight.Asus.Aura; 5 | 6 | namespace Slate.Model.Settings.Components 7 | { 8 | public class KeyboardSettings : SettingsComponent 9 | { 10 | public bool FollowSystemAccentColor { get; set; } = false; 11 | 12 | public AuraAnimation Animation { get; set; } = AuraAnimation.Static; 13 | public ColorWrapper PrimaryColor { get; set; } = new(Color.White); 14 | public ColorWrapper SecondaryColor { get; set; } = new(Color.White); 15 | public AuraAnimationSpeed AnimationSpeed { get; set; } = AuraAnimationSpeed.Medium; 16 | 17 | public KeyBind BindM3 { get; set; } = new(KeyBindMode.Default); 18 | public KeyBind BindM4 { get; set; } = new(KeyBindMode.Default); 19 | public KeyBind BindF4 { get; set; } = new(KeyBindMode.Default); 20 | public KeyBind BindF5 { get; set; } = new(KeyBindMode.Default); 21 | 22 | protected override void OnSettingsModified(string? propertyName) 23 | { 24 | switch (propertyName) 25 | { 26 | case nameof(Animation): 27 | case nameof(PrimaryColor): 28 | case nameof(SecondaryColor): 29 | case nameof(AnimationSpeed): 30 | { 31 | new AuraSettingsChangedMessage( 32 | Animation, 33 | PrimaryColor.HardwareColor, 34 | SecondaryColor.HardwareColor, 35 | AnimationSpeed 36 | ).Broadcast(); 37 | 38 | break; 39 | } 40 | 41 | case nameof(FollowSystemAccentColor): 42 | { 43 | new AuraFollowSystemAccentColorStateChangedMessage( 44 | FollowSystemAccentColor 45 | ).Broadcast(); 46 | 47 | break; 48 | } 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /Slate/Model/Settings/Components/PowerManagementSettings.cs: -------------------------------------------------------------------------------- 1 | using Slate.Infrastructure.Settings; 2 | using Slate.Model.Messaging; 3 | 4 | namespace Slate.Model.Settings.Components 5 | { 6 | public class PowerManagementSettings : SettingsComponent 7 | { 8 | public bool IsProcessorBoostActiveOnAC { get; set; } = true; 9 | public bool IsProcessorBoostActiveOnDC { get; set; } = false; 10 | 11 | public int BatteryChargeLimit { get; set; } = 85; /* percent of course */ 12 | public byte TotalSystemPPT { get; set; } = 90; 13 | public byte ProcessorPPT { get; set; } = 60; 14 | 15 | protected override void OnSettingsModified(string? propertyName) 16 | { 17 | switch (propertyName) 18 | { 19 | case nameof(IsProcessorBoostActiveOnAC): 20 | case nameof(IsProcessorBoostActiveOnDC): 21 | { 22 | new CpuBoostModeChangedMessage( 23 | IsProcessorBoostActiveOnAC, 24 | IsProcessorBoostActiveOnDC 25 | ).Broadcast(); 26 | 27 | break; 28 | } 29 | 30 | case nameof(BatteryChargeLimit): 31 | { 32 | new BatteryChargeLimitChangedMessage( 33 | BatteryChargeLimit 34 | ).Broadcast(); 35 | 36 | break; 37 | } 38 | 39 | case nameof(TotalSystemPPT): 40 | case nameof(ProcessorPPT): 41 | { 42 | WithEventSuppressed(() => 43 | { 44 | if (ProcessorPPT > TotalSystemPPT) 45 | ProcessorPPT = TotalSystemPPT; 46 | }); 47 | 48 | new PowerTargetsChangedMessage( 49 | TotalSystemPPT, 50 | ProcessorPPT 51 | ).Broadcast(); 52 | 53 | break; 54 | } 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Slate/Model/Settings/ControlCenterSettings.cs: -------------------------------------------------------------------------------- 1 | using Slate.Infrastructure.Settings; 2 | using Slate.Model.Settings.Components; 3 | 4 | namespace Slate.Model.Settings 5 | { 6 | public class ControlCenterSettings : SettingsBase 7 | { 8 | public ApplicationSettings Application { get; set; } = new(); 9 | public FansSettings Fans { get; set; } = new(); 10 | public GraphicsAndDisplaySettings GraphicsAndDisplay { get; set; } = new(); 11 | public PowerManagementSettings PowerManagement { get; set; } = new(); 12 | public KeyboardSettings Keyboard { get; set; } = new(); 13 | public AniMeMatrixSettings AniMeMatrix { get; set; } = new(); 14 | } 15 | } -------------------------------------------------------------------------------- /Slate/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using System; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | using Glitonea.Mvvm.Messaging; 7 | using Slate.Infrastructure.Native; 8 | using Slate.Model.Messaging; 9 | 10 | #if ACPITESTING 11 | using System.Diagnostics; 12 | using Slate.Infrastructure.Asus.Acpi; 13 | #endif 14 | 15 | namespace Slate 16 | { 17 | internal class Program 18 | { 19 | [STAThread] 20 | public static void Main(string[] args) 21 | { 22 | #if ACPITESTING 23 | var proxy = new AsusAcpiProxy(); 24 | 25 | var names = Enum.GetNames(typeof(DstsMethod)); 26 | 27 | using (var sw = new StreamWriter("acpivars.txt")) 28 | { 29 | foreach (var name in names) 30 | { 31 | try 32 | { 33 | sw.WriteLine( 34 | $"{name}: {proxy.DSTS.ReadInt32((DstsMethod)Enum.Parse(typeof(DstsMethod), name)):X8}" 35 | ); 36 | } 37 | catch 38 | { 39 | // ignore 40 | } 41 | } 42 | } 43 | 44 | Debugger.Break(); 45 | #else 46 | // var hook = User32.SetWindowsHookEx(User32.WH_KEYBOARD_LL, KeyboardProc, 0, 0); 47 | 48 | var app = BuildAvaloniaApp() 49 | .StartWithClassicDesktopLifetime(args); 50 | #endif 51 | } 52 | // 53 | // private static nint KeyboardProc(int nCode, nint wParam, nint lParam) 54 | // { 55 | // var str = Marshal.PtrToStructure(lParam); 56 | // 57 | // if (wParam == User32.WM_KEYDOWN || wParam == User32.WM_SYSKEYDOWN || wParam == User32.WM_KEYUP || wParam == User32.WM_SYSKEYUP) 58 | // { 59 | // Debug.WriteLine($"{nCode:X8} : {str.vkCode}"); 60 | // } 61 | // 62 | // return User32.CallNextHookEx(0, nCode, wParam, lParam); 63 | // } 64 | 65 | public static AppBuilder BuildAvaloniaApp() 66 | => AppBuilder 67 | .Configure() 68 | .UsePlatformDetect() 69 | .With(new Win32PlatformOptions 70 | { 71 | UseWindowsUIComposition = true 72 | }) 73 | .LogToTrace() 74 | .AfterSetup((_) => Message.Broadcast()); 75 | } 76 | } -------------------------------------------------------------------------------- /Slate/Resources/Animations/power_saving_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Animations/power_saving_1.gif -------------------------------------------------------------------------------- /Slate/Resources/Animations/power_saving_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Animations/power_saving_2.gif -------------------------------------------------------------------------------- /Slate/Resources/Animations/shutdown_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Animations/shutdown_1.gif -------------------------------------------------------------------------------- /Slate/Resources/Animations/shutdown_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Animations/shutdown_2.gif -------------------------------------------------------------------------------- /Slate/Resources/Animations/sleep_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Animations/sleep_1.gif -------------------------------------------------------------------------------- /Slate/Resources/Animations/sleep_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Animations/sleep_2.gif -------------------------------------------------------------------------------- /Slate/Resources/Animations/start_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Animations/start_1.gif -------------------------------------------------------------------------------- /Slate/Resources/Animations/start_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Animations/start_2.gif -------------------------------------------------------------------------------- /Slate/Resources/Fonts/fa5_brands.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Fonts/fa5_brands.otf -------------------------------------------------------------------------------- /Slate/Resources/Fonts/segoe_fluent.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Fonts/segoe_fluent.ttf -------------------------------------------------------------------------------- /Slate/Resources/Icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vddCore/Zephyrus-Control-Center/176f305e44f0f893e95e2d7f8e98f3be0f924c67/Slate/Resources/Icons/icon.ico -------------------------------------------------------------------------------- /Slate/Resources/Paths/AuraIcon.axaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Slate/Resources/Paths/FanIcon.axaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Slate/Resources/Paths/MicrophoneIcon.axaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 17 | 18 | 21 | 22 | 25 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Slate/Resources/Paths/RogLogo.axaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Slate/Resources/Styles/BrightnessSelector.axaml: -------------------------------------------------------------------------------- 1 |  5 | 8 | 9 | 12 | 13 | 16 | 17 | 20 | 21 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /Slate/Resources/Styles/Card.axaml: -------------------------------------------------------------------------------- 1 |  5 | 31 | -------------------------------------------------------------------------------- /Slate/Resources/Styles/LinkIcon.axaml: -------------------------------------------------------------------------------- 1 |  3 | 18 | 19 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /Slate/Resources/Styles/Transitions.axaml: -------------------------------------------------------------------------------- 1 |  4 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /Slate/View/Control/Icons/FAIcon.axaml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /Slate/View/Control/Icons/FAIcon.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using PropertyChanged; 4 | 5 | namespace Slate.View.Control.Icons 6 | { 7 | [DoNotNotify] 8 | public partial class FAIcon : UserControl 9 | { 10 | public static readonly StyledProperty GlyphProperty 11 | = AvaloniaProperty.Register(nameof(Glyph)); 12 | 13 | public char Glyph 14 | { 15 | get => GetValue(GlyphProperty); 16 | set => SetValue(GlyphProperty, value); 17 | } 18 | 19 | public FAIcon() 20 | { 21 | InitializeComponent(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Slate/View/Control/Icons/SFIcon.axaml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /Slate/View/Control/Icons/SFIcon.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using PropertyChanged; 4 | 5 | namespace Slate.View.Control.Icons 6 | { 7 | [DoNotNotify] 8 | public partial class SFIcon : UserControl 9 | { 10 | public static readonly StyledProperty GlyphProperty 11 | = AvaloniaProperty.Register(nameof(Glyph)); 12 | 13 | public char Glyph 14 | { 15 | get => GetValue(GlyphProperty); 16 | set => SetValue(GlyphProperty, value); 17 | } 18 | 19 | public SFIcon() 20 | { 21 | InitializeComponent(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Slate/View/Control/PageElements/AuraColorControl.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PropertyChanged; 3 | 4 | namespace Slate.View.Control.PageElements 5 | { 6 | [DoNotNotify] 7 | public partial class AuraColorControl : UserControl 8 | { 9 | public AuraColorControl() 10 | { 11 | InitializeComponent(); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Slate/View/Control/PageElements/SettingsPalette.axaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 45 | 46 | 47 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Slate/View/Control/PageElements/SettingsPalette.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PropertyChanged; 3 | 4 | namespace Slate.View.Control.PageElements 5 | { 6 | [DoNotNotify] 7 | public partial class SettingsPalette : UserControl 8 | { 9 | public SettingsPalette() 10 | { 11 | InitializeComponent(); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/BrightnessSelector.axaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 22 | 23 | 30 | 31 | 37 | 38 | -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/BrightnessSelector.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Interactivity; 4 | using PropertyChanged; 5 | using Starlight.Asus; 6 | 7 | namespace Slate.View.Control.Primitives 8 | { 9 | [DoNotNotify] 10 | public partial class BrightnessSelector : UserControl 11 | { 12 | public static readonly StyledProperty BrightnessLevelProperty 13 | = AvaloniaProperty.Register(nameof(BrightnessLevel)); 14 | 15 | public BrightnessLevel BrightnessLevel 16 | { 17 | get => GetValue(BrightnessLevelProperty); 18 | set => SetValue(BrightnessLevelProperty, value); 19 | } 20 | 21 | public BrightnessSelector() 22 | { 23 | InitializeComponent(); 24 | } 25 | 26 | protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) 27 | { 28 | UpdateButtonStates(BrightnessLevel); 29 | 30 | base.OnAttachedToVisualTree(e); 31 | } 32 | 33 | protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) 34 | { 35 | if (change.Property == BrightnessLevelProperty) 36 | { 37 | UpdateButtonStates(BrightnessLevel); 38 | } 39 | 40 | base.OnPropertyChanged(change); 41 | } 42 | 43 | private void UpdateButtonStates(BrightnessLevel level) 44 | { 45 | OffButton.IsChecked = level == BrightnessLevel.Off; 46 | DimButton.IsChecked = level == BrightnessLevel.Dim; 47 | MediumButton.IsChecked = level == BrightnessLevel.Medium; 48 | BrightButton.IsChecked = level == BrightnessLevel.Bright; 49 | } 50 | 51 | private void OffButton_Click(object? sender, RoutedEventArgs e) 52 | => BrightnessLevel = BrightnessLevel.Off; 53 | 54 | private void DimButton_Click(object? sender, RoutedEventArgs e) 55 | => BrightnessLevel = BrightnessLevel.Dim; 56 | 57 | private void MediumButton_Click(object? sender, RoutedEventArgs e) 58 | => BrightnessLevel = BrightnessLevel.Medium; 59 | 60 | private void BrightButton_Click(object? sender, RoutedEventArgs e) 61 | => BrightnessLevel = BrightnessLevel.Bright; 62 | } 63 | } -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/Card.axaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/Card.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using PropertyChanged; 4 | 5 | namespace Slate.View.Control.Primitives 6 | { 7 | [DoNotNotify] 8 | public partial class Card : UserControl 9 | { 10 | public static readonly StyledProperty HeaderContentProperty 11 | = AvaloniaProperty.Register(nameof(HeaderContent)); 12 | 13 | public static readonly StyledProperty ShowHeaderProperty 14 | = AvaloniaProperty.Register(nameof(ShowHeader)); 15 | 16 | public object? HeaderContent 17 | { 18 | get => GetValue(HeaderContentProperty); 19 | set => SetValue(HeaderContentProperty, value); 20 | } 21 | 22 | public bool ShowHeader 23 | { 24 | get => GetValue(ShowHeaderProperty); 25 | set => SetValue(ShowHeaderProperty, value); 26 | } 27 | 28 | public Card() 29 | { 30 | InitializeComponent(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/CoreStatisticsDisplay.axaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 11 | 16 | 17 | 22 | 23 | 24 | 27 | 32 | 33 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/CoreStatisticsDisplay.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PropertyChanged; 3 | 4 | namespace Slate.View.Control.Primitives 5 | { 6 | [DoNotNotify] 7 | public partial class CoreStatisticsDisplay : UserControl 8 | { 9 | public CoreStatisticsDisplay() 10 | { 11 | InitializeComponent(); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/DualSwitch.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Input; 2 | using Avalonia; 3 | using Avalonia.Controls; 4 | using PropertyChanged; 5 | 6 | namespace Slate.View.Control.Primitives 7 | { 8 | [DoNotNotify] 9 | public partial class DualSwitch : UserControl 10 | { 11 | public static readonly StyledProperty LeftOptionContentProperty 12 | = AvaloniaProperty.Register(nameof(LeftOptionContent)); 13 | 14 | public static readonly StyledProperty LeftOptionCommandProperty 15 | = AvaloniaProperty.Register(nameof(LeftOptionCommand)); 16 | 17 | public static readonly StyledProperty IsLeftOptionCheckedProperty 18 | = AvaloniaProperty.Register(nameof(IsLeftOptionChecked)); 19 | 20 | public static readonly StyledProperty RightOptionContentProperty 21 | = AvaloniaProperty.Register(nameof(RightOptionContent)); 22 | 23 | public static readonly StyledProperty RightOptionCommandProperty 24 | = AvaloniaProperty.Register(nameof(RightOptionCommand)); 25 | 26 | public static readonly StyledProperty IsRightOptionCheckedProperty 27 | = AvaloniaProperty.Register(nameof(IsRightOptionChecked)); 28 | 29 | 30 | public object? LeftOptionContent 31 | { 32 | get => GetValue(LeftOptionContentProperty); 33 | set => SetValue(LeftOptionContentProperty, value); 34 | } 35 | 36 | public ICommand? LeftOptionCommand 37 | { 38 | get => GetValue(LeftOptionCommandProperty); 39 | set => SetValue(LeftOptionCommandProperty, value); 40 | } 41 | 42 | public bool IsLeftOptionChecked 43 | { 44 | get => GetValue(IsLeftOptionCheckedProperty); 45 | set => SetValue(IsLeftOptionCheckedProperty, value); 46 | } 47 | 48 | public object? RightOptionContent 49 | { 50 | get => GetValue(RightOptionContentProperty); 51 | set => SetValue(RightOptionContentProperty, value); 52 | } 53 | 54 | public ICommand? RightOptionCommand 55 | { 56 | get => GetValue(RightOptionCommandProperty); 57 | set => SetValue(RightOptionCommandProperty, value); 58 | } 59 | 60 | public bool IsRightOptionChecked 61 | { 62 | get => GetValue(IsRightOptionCheckedProperty); 63 | set => SetValue(IsRightOptionCheckedProperty, value); 64 | } 65 | 66 | public DualSwitch() 67 | { 68 | InitializeComponent(); 69 | } 70 | 71 | protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) 72 | { 73 | if (change.Property == IsLeftOptionCheckedProperty) 74 | { 75 | Classes.Set("left-checked", IsLeftOptionChecked); 76 | } 77 | else if (change.Property == IsRightOptionCheckedProperty) 78 | { 79 | Classes.Set("right-checked", IsRightOptionChecked); 80 | } 81 | 82 | base.OnPropertyChanged(change); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/EditableChart.axaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | 23 | 27 | 28 | 38 | 39 | 43 | 44 | 45 | 46 | 58 | 59 | 61 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/GifRadioButton.axaml: -------------------------------------------------------------------------------- 1 | 9 | 16 | 21 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/GifRadioButton.axaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia; 3 | using Avalonia.Controls; 4 | using Avalonia.Input; 5 | using Avalonia.Interactivity; 6 | using PropertyChanged; 7 | 8 | namespace Slate.View.Control.Primitives 9 | { 10 | [DoNotNotify] 11 | public partial class GifRadioButton : UserControl 12 | { 13 | public static readonly StyledProperty GifSourceUriProperty 14 | = AvaloniaProperty.Register(nameof(GifSourceUri)); 15 | 16 | public static readonly StyledProperty GifWidthProperty 17 | = AvaloniaProperty.Register(nameof(GifWidth)); 18 | 19 | public static readonly StyledProperty GifHeightProperty 20 | = AvaloniaProperty.Register(nameof(GifHeight)); 21 | 22 | public static readonly StyledProperty SelectionGroupProperty 23 | = AvaloniaProperty.Register(nameof(SelectionGroup)); 24 | 25 | public static readonly StyledProperty IsCheckedProperty 26 | = AvaloniaProperty.Register(nameof(IsChecked)); 27 | 28 | public event EventHandler? Click; 29 | 30 | public Uri GifSourceUri 31 | { 32 | get => GetValue(GifSourceUriProperty); 33 | set => SetValue(GifSourceUriProperty, value); 34 | } 35 | 36 | public double GifWidth 37 | { 38 | get => GetValue(GifWidthProperty); 39 | set => SetValue(GifWidthProperty, value); 40 | } 41 | 42 | public double GifHeight 43 | { 44 | get => GetValue(GifHeightProperty); 45 | set => SetValue(GifHeightProperty, value); 46 | } 47 | 48 | public string? SelectionGroup 49 | { 50 | get => GetValue(SelectionGroupProperty); 51 | set => SetValue(SelectionGroupProperty, value); 52 | } 53 | 54 | public bool? IsChecked 55 | { 56 | get => GetValue(IsCheckedProperty); 57 | set => SetValue(IsCheckedProperty, value); 58 | } 59 | 60 | public GifRadioButton() 61 | { 62 | InitializeComponent(); 63 | } 64 | 65 | protected override void OnPointerEntered(PointerEventArgs e) 66 | { 67 | GifImageContainer.Start(); 68 | 69 | base.OnPointerEntered(e); 70 | } 71 | 72 | protected override void OnPointerExited(PointerEventArgs e) 73 | { 74 | GifImageContainer.Stop(); 75 | 76 | base.OnPointerExited(e); 77 | } 78 | 79 | private void Button_OnClick(object? sender, RoutedEventArgs e) 80 | { 81 | Click?.Invoke(this, e); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/MainMenuButton.axaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | 13 | 14 | 51 | -------------------------------------------------------------------------------- /Slate/View/Control/Primitives/MainMenuButton.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Input; 2 | using Avalonia; 3 | using Avalonia.Controls; 4 | using PropertyChanged; 5 | 6 | namespace Slate.View.Control.Primitives 7 | { 8 | [DoNotNotify] 9 | public partial class MainMenuButton : UserControl 10 | { 11 | public static readonly StyledProperty CommandProperty = 12 | AvaloniaProperty.Register(nameof(Command)); 13 | 14 | public static readonly StyledProperty CommandParameterProperty = 15 | AvaloniaProperty.Register(nameof(CommandParameter)); 16 | 17 | public static readonly StyledProperty ImageContentProperty = 18 | AvaloniaProperty.Register(nameof(ImageContent)); 19 | 20 | public static readonly StyledProperty HeaderProperty = 21 | AvaloniaProperty.Register(nameof(Header)); 22 | 23 | public static readonly StyledProperty DescriptionProperty = 24 | AvaloniaProperty.Register(nameof(Description)); 25 | 26 | public static readonly StyledProperty GadgetContentProperty = 27 | AvaloniaProperty.Register(nameof(GadgetContent)); 28 | 29 | public ICommand? Command 30 | { 31 | get => GetValue(CommandProperty); 32 | set => SetValue(CommandProperty, value); 33 | } 34 | 35 | public object? CommandParameter 36 | { 37 | get => GetValue(CommandParameterProperty); 38 | set => SetValue(CommandParameterProperty, value); 39 | } 40 | 41 | public object? ImageContent 42 | { 43 | get => GetValue(ImageContentProperty); 44 | set => SetValue(ImageContentProperty, value); 45 | } 46 | 47 | public string? Header 48 | { 49 | get => GetValue(HeaderProperty); 50 | set => SetValue(HeaderProperty, value); 51 | } 52 | 53 | public string? Description 54 | { 55 | get => GetValue(DescriptionProperty); 56 | set => SetValue(DescriptionProperty, value); 57 | } 58 | 59 | public object? GadgetContent 60 | { 61 | get => GetValue(GadgetContentProperty); 62 | set => SetValue(GadgetContentProperty, value); 63 | } 64 | 65 | public MainMenuButton() 66 | { 67 | InitializeComponent(); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /Slate/View/Page/AniMeMatrixPage.axaml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 20 | 21 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Slate/View/Page/AniMeMatrixPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PropertyChanged; 3 | 4 | namespace Slate.View.Page 5 | { 6 | [DoNotNotify] 7 | public partial class AniMeMatrixPage : UserControl 8 | { 9 | public AniMeMatrixPage() 10 | { 11 | InitializeComponent(); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Slate/View/Page/ApplicationPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using PropertyChanged; 3 | 4 | namespace Slate.View.Page 5 | { 6 | [DoNotNotify] 7 | public partial class ApplicationPage : UserControl 8 | { 9 | public ApplicationPage() 10 | { 11 | InitializeComponent(); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Slate/View/Page/DebugPage.axaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | 14 | 15 | 16 | 19 |