LenovoLegionToolkit
213 строк · 7.5 Кб
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Runtime.InteropServices;
5using System.Threading.Tasks;
6using LenovoLegionToolkit.Lib.Extensions;
7using LenovoLegionToolkit.Lib.Settings;
8using LenovoLegionToolkit.Lib.SoftwareDisabler;
9using LenovoLegionToolkit.Lib.Utils;
10using Windows.Win32;
11using Windows.Win32.Foundation;
12using Windows.Win32.System.Power;
13
14namespace LenovoLegionToolkit.Lib.Controllers;
15
16public class PowerPlanController
17{
18private static readonly Dictionary<PowerModeState, Guid> DefaultPowerModes = new()
19{
20{ PowerModeState.Quiet , Guid.Parse("16edbccd-dee9-4ec4-ace5-2f0b5f2a8975")},
21{ PowerModeState.Balance , Guid.Parse("85d583c5-cf2e-4197-80fd-3789a227a72c")},
22{ PowerModeState.Performance , Guid.Parse("52521609-efc9-4268-b9ba-67dea73f18b2")},
23{ PowerModeState.GodMode , Guid.Parse("85d583c5-cf2e-4197-80fd-3789a227a72c")},
24};
25
26private readonly ApplicationSettings _settings;
27
28private readonly VantageDisabler _vantageDisabler;
29
30public PowerPlanController(ApplicationSettings settings, VantageDisabler vantageDisabler)
31{
32_settings = settings ?? throw new ArgumentNullException(nameof(settings));
33_vantageDisabler = vantageDisabler ?? throw new ArgumentNullException(nameof(vantageDisabler));
34}
35
36public IEnumerable<PowerPlan> GetPowerPlans()
37{
38var powerPlansGuid = GetPowerPlansGuid();
39var activePowerPlanGuid = GetActivePowerPlanGuid();
40
41foreach (var powerPlanGuid in powerPlansGuid)
42{
43var powerPlaneName = GetPowerPlanName(powerPlanGuid);
44yield return new PowerPlan(powerPlanGuid, powerPlaneName, powerPlanGuid == activePowerPlanGuid);
45}
46}
47
48public async Task ActivatePowerPlanAsync(PowerModeState powerModeState, bool alwaysActivateDefaults = false)
49{
50if (Log.Instance.IsTraceEnabled)
51Log.Instance.Trace($"Activating... [powerModeState={powerModeState}, alwaysActivateDefaults={alwaysActivateDefaults}]");
52
53var powerPlanId = _settings.Store.PowerPlans.GetValueOrDefault(powerModeState);
54var isDefault = false;
55
56if (powerPlanId == Guid.Empty)
57{
58if (Log.Instance.IsTraceEnabled)
59Log.Instance.Trace($"Power plan for power mode {powerModeState} was not found in settings");
60
61if (DefaultPowerModes.TryGetValue(powerModeState, out var defaultPowerPlanId))
62powerPlanId = defaultPowerPlanId;
63else
64throw new InvalidOperationException("Unknown state");
65
66isDefault = true;
67}
68
69if (Log.Instance.IsTraceEnabled)
70Log.Instance.Trace($"Power plan to be activated is {powerPlanId} [isDefault={isDefault}]");
71
72if (!await ShouldActivateAsync(alwaysActivateDefaults, isDefault).ConfigureAwait(false))
73{
74if (Log.Instance.IsTraceEnabled)
75Log.Instance.Trace($"Power plan {powerPlanId} will not be activated [isDefault={isDefault}]");
76
77return;
78}
79
80var powerPlans = GetPowerPlans().ToArray();
81
82if (Log.Instance.IsTraceEnabled)
83{
84Log.Instance.Trace($"Available power plans:");
85foreach (var powerPlan in powerPlans)
86Log.Instance.Trace($" - {powerPlan.Name} [guid={powerPlan.Guid}, isActive={powerPlan.IsActive}]");
87}
88
89var powerPlanToActivate = powerPlans.FirstOrDefault(pp => pp.Guid == powerPlanId);
90if (powerPlanToActivate.Equals(default(PowerPlan)))
91{
92if (Log.Instance.IsTraceEnabled)
93Log.Instance.Trace($"Power plan {powerPlanId} was not found");
94return;
95}
96
97if (powerPlanToActivate.IsActive)
98{
99if (Log.Instance.IsTraceEnabled)
100Log.Instance.Trace($"Power plan {powerPlanToActivate.Guid} is already active. [name={powerPlanToActivate.Name}]");
101return;
102}
103
104SetActivePowerPlan(powerPlanToActivate.Guid);
105
106if (Log.Instance.IsTraceEnabled)
107Log.Instance.Trace($"Power plan {powerPlanToActivate.Guid} activated. [name={powerPlanToActivate.Name}]");
108}
109
110public PowerModeState[] GetMatchingPowerModes(Guid powerPlanGuid)
111{
112var powerModes = new Dictionary<PowerModeState, Guid>(DefaultPowerModes);
113
114foreach (var kv in _settings.Store.PowerPlans)
115{
116powerModes[kv.Key] = kv.Value;
117}
118
119return powerModes.Where(kv => kv.Value == powerPlanGuid)
120.Select(kv => kv.Key)
121.ToArray();
122}
123
124private async Task<bool> ShouldActivateAsync(bool alwaysActivateDefaults, bool isDefault)
125{
126var activateWhenVantageEnabled = _settings.Store.ActivatePowerProfilesWithVantageEnabled;
127if (activateWhenVantageEnabled)
128{
129if (Log.Instance.IsTraceEnabled)
130Log.Instance.Trace($"Activate power profiles with Vantage is enabled");
131
132return true;
133}
134
135if (isDefault && alwaysActivateDefaults)
136{
137if (Log.Instance.IsTraceEnabled)
138Log.Instance.Trace($"Power plan is default and always active defaults is set");
139
140return true;
141}
142
143var status = await _vantageDisabler.GetStatusAsync().ConfigureAwait(false);
144if (status is SoftwareStatus.NotFound or SoftwareStatus.Disabled)
145{
146if (Log.Instance.IsTraceEnabled)
147Log.Instance.Trace($"Vantage is active [status={status}]");
148
149return true;
150}
151
152if (Log.Instance.IsTraceEnabled)
153Log.Instance.Trace($"Criteria for activation not met [activateWhenVantageEnabled={activateWhenVantageEnabled}, isDefault={isDefault}, alwaysActivateDefaults={alwaysActivateDefaults}, status={status}]");
154
155return false;
156}
157
158private static unsafe IEnumerable<Guid> GetPowerPlansGuid()
159{
160var list = new List<Guid>();
161
162var bufferSize = (uint)Marshal.SizeOf<Guid>();
163var buffer = new byte[bufferSize];
164
165fixed (byte* bufferPtr = buffer)
166{
167uint index = 0;
168while (PInvoke.PowerEnumerate(null, null, null, POWER_DATA_ACCESSOR.ACCESS_SCHEME, index, bufferPtr, ref bufferSize) == WIN32_ERROR.ERROR_SUCCESS)
169{
170list.Add(new Guid(buffer));
171index++;
172}
173}
174
175return list;
176}
177
178private static unsafe string GetPowerPlanName(Guid powerPlanGuid)
179{
180var nameSize = 2048u;
181var namePtr = Marshal.AllocHGlobal((int)nameSize);
182
183try
184{
185if (PInvoke.PowerReadFriendlyName(null, powerPlanGuid, null, null, (byte*)namePtr.ToPointer(), ref nameSize) != WIN32_ERROR.ERROR_SUCCESS)
186PInvokeExtensions.ThrowIfWin32Error("PowerReadFriendlyName");
187
188return Marshal.PtrToStringUni(namePtr) ?? string.Empty;
189}
190catch
191{
192return powerPlanGuid.ToString();
193}
194finally
195{
196Marshal.FreeHGlobal(namePtr);
197}
198}
199
200private static unsafe Guid GetActivePowerPlanGuid()
201{
202if (PInvoke.PowerGetActiveScheme(null, out var guid) != WIN32_ERROR.ERROR_SUCCESS)
203PInvokeExtensions.ThrowIfWin32Error("PowerGetActiveScheme");
204
205return Marshal.PtrToStructure<Guid>(new IntPtr(guid));
206}
207
208private static void SetActivePowerPlan(Guid powerPlanGuid)
209{
210if (PInvoke.PowerSetActiveScheme(null, powerPlanGuid) != WIN32_ERROR.ERROR_SUCCESS)
211PInvokeExtensions.ThrowIfWin32Error("PowerSetActiveScheme");
212}
213}
214