diff --git a/app/ASUSWmi.cs b/app/ASUSWmi.cs index a7dd9bc59..9cb097425 100644 --- a/app/ASUSWmi.cs +++ b/app/ASUSWmi.cs @@ -157,21 +157,31 @@ protected byte[] CallMethod(uint MethodID, byte[] args) } - public byte[] DeviceSet(uint DeviceID, int Status) + public int DeviceSet(uint DeviceID, int Status, string logName) { byte[] args = new byte[8]; BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0); BitConverter.GetBytes((uint)Status).CopyTo(args, 4); - return CallMethod(DEVS, args); + + byte[] status = CallMethod(DEVS, args); + int result = BitConverter.ToInt32(status, 0); + + Logger.WriteLine(logName + " = " + Status + " : " + (result == 1 ? "OK" : result)); + return result; } - public byte[] DeviceSet(uint DeviceID, byte[] Params) + public int DeviceSet(uint DeviceID, byte[] Params, string logName) { byte[] args = new byte[4 + Params.Length]; BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0); Params.CopyTo(args, 4); - return CallMethod(DEVS, args); + + byte[] status = CallMethod(DEVS, args); + int result = BitConverter.ToInt32(status, 0); + + Logger.WriteLine(logName + " = " + BitConverter.ToString(Params) + " : " + (result == 1 ? "OK" : result)); + return BitConverter.ToInt32(status, 0); } @@ -192,31 +202,28 @@ public byte[] DeviceGetBuffer(uint DeviceID, uint Status = 0) } - public void SetFanCurve(int device, byte[] curve) + public int SetFanCurve(int device, byte[] curve) { - if (curve.Length != 16) return; - if (curve.All(singleByte => singleByte == 0)) return; + if (curve.Length != 16) return -1; + if (curve.All(singleByte => singleByte == 0)) return -1; - string name; + int result; switch (device) { case 1: - DeviceSet(DevsGPUFanCurve, curve); - name = "GPU"; + result = DeviceSet(DevsGPUFanCurve, curve, "FanGPU"); break; case 2: - DeviceSet(DevsMidFanCurve, curve); - name = "Mid"; + result = DeviceSet(DevsMidFanCurve, curve, "FanMid"); break; default: - DeviceSet(DevsCPUFanCurve, curve); - name = "CPU"; + result = DeviceSet(DevsCPUFanCurve, curve, "FanCPU"); break; } - Logger.WriteLine("Fans" + name + " " + BitConverter.ToString(curve)); + return result; } public byte[] GetFanCurve(int device, int mode = 0) @@ -254,7 +261,7 @@ public void TUFKeyboardRGB(int mode, Color color, int speed) setting[4] = color.B; setting[5] = (byte)speed; - DeviceSet(TUF_KB, setting); + DeviceSet(TUF_KB, setting, "TUF RGB"); //Debug.WriteLine(BitConverter.ToString(setting)); } @@ -274,7 +281,7 @@ public void TUFKeyboardPower(bool awake = true, bool boot = false, bool sleep = state = state | 0x01 << 8; - DeviceSet(TUF_KB_STATE, state); + DeviceSet(TUF_KB_STATE, state, "TUF_KB"); } public void SubscribeToEvents(Action EventHandler) diff --git a/app/AnimeMatrix/AnimeMatrixDevice.cs b/app/AnimeMatrix/AnimeMatrixDevice.cs index 2f3d8f0dc..ba1c9e2d5 100644 --- a/app/AnimeMatrix/AnimeMatrixDevice.cs +++ b/app/AnimeMatrix/AnimeMatrixDevice.cs @@ -390,7 +390,7 @@ public void PresentText(string text1, string text2 = "") } - public void GenerateFrame(Image image, InterpolationMode interpolation = InterpolationMode.HighQualityBicubic) + public void GenerateFrame(Image image, InterpolationMode interpolation = InterpolationMode.High) { int width = MaxColumns/2 * 6; diff --git a/app/ControlHelper.cs b/app/ControlHelper.cs index d873547a4..79e1f028d 100644 --- a/app/ControlHelper.cs +++ b/app/ControlHelper.cs @@ -106,7 +106,8 @@ private static void AdjustControls(Control.ControlCollection controls) combo.BackColor = backMain; combo.ForeColor = foreMain; combo.BorderColor = backMain; - combo.ButtonColor = buttonMain; + combo.ButtonColor = backMain; + combo.ArrowColor = foreMain; } var gb = control as GroupBox; diff --git a/app/CustomControls.cs b/app/CustomControls.cs index 8d6fa7186..71e6c0232 100644 --- a/app/CustomControls.cs +++ b/app/CustomControls.cs @@ -71,8 +71,8 @@ public Color BorderColor } - private Color buttonColor = Color.FromArgb(255,230, 230, 230); - [DefaultValue(typeof(Color), "230, 230, 230")] + private Color buttonColor = Color.FromArgb(255, 255, 255, 255); + [DefaultValue(typeof(Color), "255, 255, 255")] public Color ButtonColor { get { return buttonColor; } diff --git a/app/Fans.cs b/app/Fans.cs index 2efd55c39..ef0184f32 100644 --- a/app/Fans.cs +++ b/app/Fans.cs @@ -334,7 +334,7 @@ void LoadProfile(Series series, int device, int def = 0) } - void ApplyProfile(Series series, int device) + void SaveProfile(Series series, int device) { byte[] curve = new byte[16]; int i = 0; @@ -346,17 +346,19 @@ void ApplyProfile(Series series, int device) } Program.config.setFanConfig(device, curve); - Program.wmi.SetFanCurve(device, curve); + //Program.wmi.SetFanCurve(device, curve); } private void ButtonApply_Click(object? sender, EventArgs e) { - ApplyProfile(seriesCPU, 0); - ApplyProfile(seriesGPU, 1); + SaveProfile(seriesCPU, 0); + SaveProfile(seriesGPU, 1); if (Program.config.getConfig("mid_fan") == 1) - ApplyProfile(seriesMid, 2); + SaveProfile(seriesMid, 2); + + Program.settingsForm.AutoFans(true); } private void ButtonReset_Click(object? sender, EventArgs e) @@ -373,7 +375,7 @@ private void ButtonReset_Click(object? sender, EventArgs e) Program.config.setConfigPerf("auto_apply", 0); Program.config.setConfigPerf("auto_apply_power", 0); - Program.wmi.DeviceSet(ASUSWmi.PerformanceMode, Program.config.getConfig("performance_mode")); + Program.wmi.DeviceSet(ASUSWmi.PerformanceMode, Program.config.getConfig("performance_mode"), "PerfMode"); ApplyLabel(false); } diff --git a/app/GHelper.csproj b/app/GHelper.csproj index a65b604f5..fd5750f63 100644 --- a/app/GHelper.csproj +++ b/app/GHelper.csproj @@ -16,7 +16,7 @@ x64 False True - 0.43 + 0.44 diff --git a/app/HardwareMonitor.cs b/app/HardwareMonitor.cs index 1efb90668..52ef76955 100644 --- a/app/HardwareMonitor.cs +++ b/app/HardwareMonitor.cs @@ -19,7 +19,6 @@ public static int GetFanMax() int max = 58; if (Program.config.ContainsModel("401")) max = 72; else if (Program.config.ContainsModel("503")) max = 68; - return Math.Max(max, Program.config.getConfig("fan_max")); } diff --git a/app/NativeMethods.cs b/app/NativeMethods.cs index 13c14858c..3abc8aeca 100644 --- a/app/NativeMethods.cs +++ b/app/NativeMethods.cs @@ -632,6 +632,7 @@ public static int SetRefreshRate(int frequency = 120) { dm.dmDisplayFrequency = frequency; int iRet = NativeMethods.ChangeDisplaySettingsEx(laptopScreen, ref dm, IntPtr.Zero, DisplaySettingsFlags.CDS_UPDATEREGISTRY, IntPtr.Zero); + Logger.WriteLine("Screen = " + frequency.ToString() + "Hz : " + (iRet == 0 ? "OK" : iRet)); return iRet; } diff --git a/app/Program.cs b/app/Program.cs index 65e0f3402..7562c3849 100644 --- a/app/Program.cs +++ b/app/Program.cs @@ -154,7 +154,7 @@ static void LaunchProcess(string fileName = "") } catch { - Logger.WriteLine("Failed to run " + fileName); + Logger.WriteLine("Failed to run " + fileName); } diff --git a/app/Settings.Designer.cs b/app/Settings.Designer.cs index 6f9f24612..2ef1cfc28 100644 --- a/app/Settings.Designer.cs +++ b/app/Settings.Designer.cs @@ -163,7 +163,6 @@ private void InitializeComponent() // comboMatrix // comboMatrix.BorderColor = Color.White; - comboMatrix.ButtonColor = SystemColors.ControlLight; comboMatrix.Dock = DockStyle.Top; comboMatrix.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point); comboMatrix.FormattingEnabled = true; @@ -179,7 +178,6 @@ private void InitializeComponent() // comboMatrixRunning // comboMatrixRunning.BorderColor = Color.White; - comboMatrixRunning.ButtonColor = SystemColors.ControlLight; comboMatrixRunning.Dock = DockStyle.Top; comboMatrixRunning.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point); comboMatrixRunning.FormattingEnabled = true; @@ -890,7 +888,6 @@ private void InitializeComponent() // comboKeyboard // comboKeyboard.BorderColor = Color.White; - comboKeyboard.ButtonColor = SystemColors.ControlLight; comboKeyboard.Dock = DockStyle.Top; comboKeyboard.FlatStyle = FlatStyle.Flat; comboKeyboard.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point); diff --git a/app/Settings.cs b/app/Settings.cs index 3f1787895..b57cd493c 100644 --- a/app/Settings.cs +++ b/app/Settings.cs @@ -716,19 +716,18 @@ public void SetScreen(int frequency = -1, int overdrive = -1, int miniled = -1) if (frequency > 0) { NativeMethods.SetRefreshRate(frequency); - Logger.WriteLine("Screen " + frequency.ToString() + "Hz"); } if (overdrive >= 0) { if (Program.config.getConfig("no_overdrive") == 1) overdrive = 0; - Program.wmi.DeviceSet(ASUSWmi.ScreenOverdrive, overdrive); + Program.wmi.DeviceSet(ASUSWmi.ScreenOverdrive, overdrive, "ScreenOverdrive"); } if (miniled >= 0) { - Program.wmi.DeviceSet(ASUSWmi.ScreenMiniled, miniled); + Program.wmi.DeviceSet(ASUSWmi.ScreenMiniled, miniled, "Miniled"); Debug.WriteLine("Miniled " + miniled); } @@ -855,13 +854,13 @@ private static void RefreshSensors(bool force = false) { Program.settingsForm.labelCPUFan.Text = "CPU" + cpuTemp + HardwareMonitor.cpuFan; Program.settingsForm.labelGPUFan.Text = "GPU" + gpuTemp + HardwareMonitor.gpuFan; - if (HardwareMonitor.midFan is not null) + if (HardwareMonitor.midFan is not null) Program.settingsForm.labelMidFan.Text = "Mid" + HardwareMonitor.midFan; - + Program.settingsForm.labelBattery.Text = battery; - Program.trayIcon.Text = "CPU" + cpuTemp + HardwareMonitor.cpuFan + "\n" - + "GPU" + gpuTemp + HardwareMonitor.gpuFan + + Program.trayIcon.Text = "CPU" + cpuTemp + HardwareMonitor.cpuFan + "\n" + + "GPU" + gpuTemp + HardwareMonitor.gpuFan + ((battery.Length > 0) ? ("\n" + battery) : ""); }); @@ -901,37 +900,45 @@ public void SetPower() if (limit_cpu < ASUSWmi.MinCPU) return; if (Program.wmi.DeviceGet(ASUSWmi.PPT_TotalA0) >= 0) - Program.wmi.DeviceSet(ASUSWmi.PPT_TotalA0, limit_total); + Program.wmi.DeviceSet(ASUSWmi.PPT_TotalA0, limit_total, "PowerLimit A"); if (Program.wmi.DeviceGet(ASUSWmi.PPT_CPUB0) >= 0) - Program.wmi.DeviceSet(ASUSWmi.PPT_CPUB0, limit_cpu); + Program.wmi.DeviceSet(ASUSWmi.PPT_CPUB0, limit_cpu, "PowerLimit B"); + - Logger.WriteLine("PowerLimits " + limit_total.ToString() + ", " + limit_cpu.ToString()); } - public void AutoFansAndPower() + public void AutoFans(bool force = false) { - if (Program.config.getConfigPerf("auto_apply") == 1) + if (force || Program.config.getConfigPerf("auto_apply") == 1) { - Program.wmi.SetFanCurve(0, Program.config.getFanConfig(0)); - Program.wmi.SetFanCurve(1, Program.config.getFanConfig(1)); + int cpuResult = Program.wmi.SetFanCurve(0, Program.config.getFanConfig(0)); + int gpuResult = Program.wmi.SetFanCurve(1, Program.config.getFanConfig(1)); if (Program.config.getConfig("mid_fan") == 1) Program.wmi.SetFanCurve(2, Program.config.getFanConfig(2)); - labelPerf.Text = "Performans Modu +"; - + if (cpuResult != 1 || gpuResult != 1) // something went wrong, resetting to default profile + { + int mode = Program.config.getConfig("performance_mode"); + Logger.WriteLine("Bios rejected fan curve, resetting mode to " + mode); + Program.wmi.DeviceSet(ASUSWmi.PerformanceMode, mode, "PerformanceMode"); + } + else + labelPerf.Text = "Performans Modu +"; } else { labelPerf.Text = "Performans Modu"; } - if (Program.config.getConfigPerf("auto_apply_power") == 1) + public void AutoPower(bool force = false) + { + if (force || Program.config.getConfigPerf("auto_apply_power") == 1) { var timer = new System.Timers.Timer(1000); timer.Elapsed += delegate @@ -943,12 +950,9 @@ public void AutoFansAndPower() timer.Start(); } - if (Program.config.getConfigPerf("auto_boost") != -1) - { - NativeMethods.SetCPUBoost(Program.config.getConfigPerf("auto_boost")); - } } + public void SetPerformanceMode(int PerformanceMode = ASUSWmi.PerformanceBalanced, bool notify = false) { @@ -978,8 +982,7 @@ public void SetPerformanceMode(int PerformanceMode = ASUSWmi.PerformanceBalanced Program.config.setConfig("performance_" + (int)SystemInformation.PowerStatus.PowerLineStatus, PerformanceMode); Program.config.setConfig("performance_mode", PerformanceMode); - Program.wmi.DeviceSet(ASUSWmi.PerformanceMode, PerformanceMode); - Logger.WriteLine("PerfMode " + perfName + " " + PerformanceMode); + Program.wmi.DeviceSet(ASUSWmi.PerformanceMode, PerformanceMode, "PerformanceMode"); if (notify && (oldMode != PerformanceMode)) { @@ -993,7 +996,13 @@ public void SetPerformanceMode(int PerformanceMode = ASUSWmi.PerformanceBalanced } } - AutoFansAndPower(); + AutoFans(); + AutoPower(); + + if (Program.config.getConfigPerf("auto_boost") != -1) + { + NativeMethods.SetCPUBoost(Program.config.getConfigPerf("auto_boost")); + } NativeMethods.SetPowerScheme(PerformanceMode); @@ -1026,10 +1035,10 @@ public void AutoKeyboard() if (SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online) Aura.ApplyBrightness(3); - //Program.wmi.DeviceSet(ASUSWmi.UniversalControl, ASUSWmi.KB_Light_Up); + //Program.wmi.DeviceSet(ASUSWmi.UniversalControl, ASUSWmi.KB_Light_Up); else Aura.ApplyBrightness(0); - //Program.wmi.DeviceSet(ASUSWmi.UniversalControl, ASUSWmi.KB_Light_Down); + //Program.wmi.DeviceSet(ASUSWmi.UniversalControl, ASUSWmi.KB_Light_Down); } @@ -1164,8 +1173,7 @@ public void SetEcoGPU(int eco) foreach (var process in Process.GetProcessesByName(kill)) process.Kill(); } - Program.wmi.DeviceSet(ASUSWmi.GPUEco, eco); - Logger.WriteLine("Setting Eco mode: " + eco); + Program.wmi.DeviceSet(ASUSWmi.GPUEco, eco, "GPUEco"); Program.settingsForm.BeginInvoke(delegate { @@ -1199,7 +1207,7 @@ public void SetGPUMode(int GPUMode) DialogResult dialogResult = MessageBox.Show("Switching off Ultimate Mode requires restart", "Reboot now?", MessageBoxButtons.YesNo); if (dialogResult == DialogResult.Yes) { - Program.wmi.DeviceSet(ASUSWmi.GPUMux, 1); + Program.wmi.DeviceSet(ASUSWmi.GPUMux, 1, "GPUMux"); restart = true; changed = true; } @@ -1209,7 +1217,7 @@ public void SetGPUMode(int GPUMode) DialogResult dialogResult = MessageBox.Show("Ultimate Mode requires restart", "Reboot now?", MessageBoxButtons.YesNo); if (dialogResult == DialogResult.Yes) { - Program.wmi.DeviceSet(ASUSWmi.GPUMux, 0); + Program.wmi.DeviceSet(ASUSWmi.GPUMux, 0, "GPUMux"); restart = true; changed = true; } @@ -1325,7 +1333,7 @@ public void SetBatteryChargeLimit(int limit) labelBatteryTitle.Text = "Batarya Şarj Sınırı: " + limit.ToString() + "%"; sliderBattery.Value = limit; - Program.wmi.DeviceSet(ASUSWmi.BatteryLimit, limit); + Program.wmi.DeviceSet(ASUSWmi.BatteryLimit, limit, "BatteryLimit"); Program.config.setConfig("charge_limit", limit); } diff --git a/docs/README.md b/docs/README.md index 853d599e1..960b534b9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,15 +1,17 @@ + # [G-Helper](https://github.com/seerge/g-helper) [![Github all releases](https://img.shields.io/github/downloads/seerge/g-helper/total.svg)](https://GitHub.com/seerge/g-helper/releases/) [![GitHub release](https://img.shields.io/github/release/seerge/g-helper.svg)](https://GitHub.com/seerge/g-helper/releases/) [![GitHub stars](https://img.shields.io/github/stars/seerge/g-helper.svg?style=social&label=Star)](https://GitHub.com/seerge/g-helper/stargazers/) -## Open source Armoury Crate alternative for Asus laptops such as ROG Zephyrus G14, G15, Flow X13, Flow X16, TUF and other models +## Lightweight Armoury Crate alternative for Asus laptops +### Control tool for ROG Zephyrus G14, G15, Flow X13, Flow X16, TUF, Strix, Scar and other models A small utility that allows you to do almost everything you could do with Armoury Crate but without extra bloat and unnecessary services. ### :gift: Main advantages 1. Seamless and automatic GPU switching (without asking you to close all apps, etc) -2. All performance modes can be fully customized (with fan curves and PPTs) +2. All performance modes can be fully customised (with fan curves and PPTs) 3. Very lightweight and consumes almost no resources, doesn't install any services. Just a single exe to run 4. Simple and clean native UI with easy access to all settings @@ -19,7 +21,7 @@ If you like this app, please [star :star: it on Github](https://github.com/seerg If you post about app - please include a link. Thanks. -![Screenshot 2023-03-29 122524](https://user-images.githubusercontent.com/5920850/228505505-c3682509-a9e4-4cac-a5fd-e10d30c477cd.png) +![Screenshot 2023-03-30 115149](https://user-images.githubusercontent.com/5920850/228799078-bc93148f-6580-4319-b9e6-fbde4d246cd2.png) ### :zap: Main features @@ -36,7 +38,7 @@ If you post about app - please include a link. Thanks. 11. Battery charge limit to preserve battery health 12. Monitor CPU / GPU temperature, fan speeds and battery discharge rate -### :apple: Automatic switching of modes when on battery or plugged in +### :gear: Automatic switching of modes when on battery or plugged in - Performance modes (app remembers last mode used on battery or when plugged) - Optimized GPU mode - disables dGPU on battery and enables when plugged - Auto Screen refresh rate (60hz on battery, 120+ hz when plugged) @@ -45,7 +47,7 @@ To keep auto switching and hotkeys working the app needs to stay in running in t ### :rocket: Performance Modes -Modes are **same** as in Armory Crate (as they are stored in bios), including default fan curves +Modes are **same** as in Armoury Crate (as they are stored in bios), including default fan curves ![Screenshot 2023-03-29 122534](https://user-images.githubusercontent.com/5920850/228505581-4e7d087c-bd0a-4a48-b572-de2c01192830.png) @@ -64,11 +66,11 @@ PPTs are shown for G14 2022, for other models PPTs will be different as they are ## :question: FAQ -### How do I stop Armory Crate install popup appearing every time I press M4 / Rog key? +### How do I stop the Armory Crate install popup appearing every time I press the M4 / Rog key? Go to BIOS (F2 on boot), open Advanced Settings and disable "Armory Control Interface". -If it still appears - delete or move somwhere following file ``C:\Windows\System32\ASUSACCI\ArmouryCrateKeyControl.exe`` +If it still appears - delete or move somewhere following file ``C:\Windows\System32\ASUSACCI\ArmouryCrateKeyControl.exe`` -### Why Ultimate GPU mode is not available on my laptop? +### Why is Ultimate GPU mode not available on my laptop? Ultimate mode is supported (by hardware) only on G14 2022 (and possibly other models from 2022+) ### I can't set Eco mode (disable dGPU) on my G14 2020 @@ -84,11 +86,17 @@ It doesn't. Your bios does (same as in case with armoury). What G-helper can do Click on them ### I don't see a GPU temperature in G-helper -Most probably either you are using Eco / Optimized mode and your dGPU is simply off, or your windows has put dGPU into sleep (to preserve power). In this situations G-helper won't be able to reach your GPU and get readings +Most probably either you are using Eco / Optimized mode and your dGPU is simply off, or your windows has put the dGPU into sleep (to preserve power). In this situations G-helper won't be able to reach your GPU and get readings + +### It says, that app is already running +Please check system tray for a (G) icon. By default windows is keen to hide all icons, so you may need to click ^ to see them all. I would advise to right click on Task Bar select Task Bar Settings -> Other System Tray icons -> Mark G-Helper to be always ON. ### App doesn't start / or crashes, what should I do ? Open "Event Viewer" from start menu, go to Windows Logs -> Application and check for recent Errors mentioning G-Helper. If you see one - please post a [new issue](https://github.com/seerge/g-helper/issues) with all details from this error. +### Can I use MyASUS app along with G-Helper? +Sure, you can! The only problem is that MyASUS may override battery charge limit that you set before. My advice in such case would be to set same limit (i.e. 80%) in both MyASUS and G-Helper. + ### How do I uninstall G-helper? G-helper is a single exe, and it doesn't install anything in the system. To remove it - you can simply delete exe :) If you have applied any custom fan profiles or PPTs - before removing I would recommend selecting your favorite performance mode (for example balanced) and clicking "Factory defaults" under Fans + Power. @@ -100,13 +108,15 @@ G-helper is a single exe, and it doesn't install anything in the system. To remo 2. Unzip to a folder of your choice 3. Run **GHelper.exe** -### Dependencies +### Dependencies & Requirements + +- Microsoft [.NET7](https://dotnet.microsoft.com/en-us/download). Most probably you already have it. Otherwise you can [download it](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-7.0.202-windows-x64-installer) from the official website. -- App requires [.NET7](https://dotnet.microsoft.com/en-us/download) to be installed. Most probably you already have it. Otherwise you can [download it](https://dotnet.microsoft.com/en-us/download). +- [Asus System Control Interface](https://dlcdnets.asus.com/pub/ASUS/nb/Image/CustomComponent/ASUSSystemControlInterfaceV3/ASUSSystemControlInterfaceV3.exe). If you have or had MyASUS app installed this "driver" probably still in place (even after MyASUS uninstalls). Alternatively - you can download and install it, and later disable / remove unnecessary services by running [this bat file](https://raw.githubusercontent.com/seerge/g-helper/main/debloat.bat) as admin. -- I recommend keeping "Asus Optimization Service" running, as it keeps basic laptop hotkeys such as screen or keyboard brightness adjustment working. If you have (or had) MyASUS app installed, that service is most probably still up and running even after MyASUS uninstalls. It's part of [Asus System Control Interface](https://www.asus.com/support/FAQ/1047338/). You can install it, and later disable / remove unnecessary services by running [this bat file](https://raw.githubusercontent.com/seerge/g-helper/main/debloat.bat) as admin. +- I recommend keeping "Asus Optimization Service" running, as it keeps basic laptop hotkeys such as screen or keyboard brightness adjustment working. -- It's not recommended to use an app in combination with Armoury Crate, cause they adjust the same settings. You can [uninstall it using it's own uninstall tool](https://dlcdnets.asus.com/pub/ASUS/mb/14Utilities/Armoury_Crate_Uninstall_Tool.zip?model=armoury%20crate). Just in case, you can always install it back later. +- It's not recommended to use an app in combination with Armoury Crate services, cause they adjust the same settings. You can [uninstall it using it's own uninstall tool](https://dlcdnets.asus.com/pub/ASUS/mb/14Utilities/Armoury_Crate_Uninstall_Tool.zip?model=armoury%20crate). Just in case, you can always install it back later. Note: Doesn't need administrator privileges to run!