Lenovo Legion Toolkit 源码拆解:自动化管道与CLI脚本
Lenovo Legion Toolkit 源码拆解自动化管道与CLI脚本【免费下载链接】LenovoLegionToolkitLightweight Lenovo Vantage and Hotkeys replacement for Lenovo Legion laptops.项目地址: https://gitcode.com/gh_mirrors/le/LenovoLegionToolkit官方 Vantage 臃肿、没有命令行入口想写游戏一启动就切性能模式的脚本基本无门。Lenovo Legion ToolkitLLT是一款 Windows 开源控制工具轻量、支持性能模式切换、混合显卡控制还自带完整 CLI。下面从源码和实操两个角度拆清楚它。核心设计监听器到自动化的完整链路WMI 事件怎么变成 C# 事件结论先说硬件不会主动通知你LLT 订阅 WMI 事件后把原生回调翻译成标准 C# 事件上层业务完全不用碰 WMI 细节。枢纽是AbstractWMIListener// 源码路径LenovoLegionToolkit.Lib/Listeners/AbstractWMIListener.cs public abstract class AbstractWMIListenerTEventArgs, TValue, TRawValue(FuncActionTRawValue, IDisposable listen) : IListenerTEventArgs where TEventArgs : EventArgs { public event EventHandlerTEventArgs? Changed; // 暴露给业务层的标准事件 public Task StartAsync() { _disposable listen(Handler); // 订阅底层 WMI 事件就这一句 return Task.CompletedTask; } private async void Handler(TRawValue properties) { var value GetValue(properties); // WMI 原始整数 → 业务枚举 await OnChangedAsync(value).ConfigureAwait(false); // ← 注意先执行联动副作用 RaiseChanged(value); // 再广播给 UI、自动化等订阅者 } }Handler是转换—副作用—广播三步流水。说人话就是小区广播硬件喊一嗓子所有关心的人都听得到彼此互不认识。如果每个模块各自订阅 WMIUI 弹通知、自动化跑管道、托盘改图标就得写三遍订阅逻辑稍有不齐就出现托盘显示性能模式、实际还是安静模式的错位。管道为什么不怕步骤失败一条自动化规则 一个触发器 一串步骤Step。步骤在AutomationPipeline.RunAsync()里顺序执行// 源码路径LenovoLegionToolkit.Lib.Automation/Pipeline/AutomationPipeline.cs internal async Task RunAsync(ListAutomationPipeline otherPipelines, CancellationToken token default) { var context new AutomationContext(); // 步骤间共享的数据 var environment new AutomationEnvironment(); // 系统状态快照 var stepExceptions new ListException(); foreach (var step in GetAllSteps(otherPipelines)) { if (token.IsCancellationRequested) // ← 注意新事件一到就取消旧管道 break; try { await step.RunAsync(context, environment, token).ConfigureAwait(false); } catch (Exception ex) { stepExceptions.Add(ex); // 收集异常不中断整条管道 } } if (stepExceptions.Count ! 0) throw new AggregateException(stepExceptions); // 全部跑完才统一抛 }三个细节CancellationToken贯穿全程新事件到了旧管道立即让位单步失败只记录、不中断切模式成功、改分辨率失败不会互相拖累QuickActionAutomationStep还能引用其他无触发器管道当子流程复用。反面场景若一步异常就抛出终止用户配了 6 个步骤第 2 步闪了一下光驱动没装好后面 5 步全白跑。只订阅你真正用到的监听器监听器不常驻。AutomationProcessor.UpdateListenersAsync()每次管道变更后重新算一遍哪些触发器存在有对应触发器才启动对应监听// 源码路径LenovoLegionToolkit.Lib.Automation/AutomationProcessor.cs节选 private async Task UpdateListenersAsync() { // 先全部退订避免残留旧订阅 await wifiAutoListener.UnsubscribeChangedAsync(WiFiAutoListener_Changed).ConfigureAwait(false); // ... 其余监听器同理 var triggers _pipelines.SelectMany(p p.AllTriggers).ToArray(); if (triggers.OfTypeIGameAutomationPipelineTrigger().Any()) await gameAutoListener.SubscribeChangedAsync(GameAutoListener_Changed); // ← 有游戏触发器才启游戏监听 if (triggers.OfTypeITimeAutomationPipelineTrigger().Any()) await timeAutoListener.SubscribeChangedAsync(TimeAutoListener_Changed); if (triggers.OfTypeIWiFiConnectedPipelineTrigger().Any()) await wifiAutoListener.SubscribeChangedAsync(WiFiAutoListener_Changed); }事件到达后还有一道预筛ProcessEvent先遍历所有触发器问IsMatchingEvent没人认领直接丢弃。整套是订阅筛选 → 匹配筛选 → 执行三级漏斗。若不这样做你哪怕只配了一条定时规则游戏进程轮询、WiFi 状态监听也会全天挂着白白耗电。硬件通信WMI、NVAPI、pnputil 三路分工一个基类管住所有 WMI 开关Features/目录下二十多个特性FnLock、OverDrive、PortsBacklight…全部继承自AbstractWmiFeatureT构造时注入取值函数和赋值函数两个委托基类统一负责枚举与整数的换算外加日志埋点。最巧的是offset参数——部分机型 WMI 返回的枚举从 1 开始部分从 0 开始换算时加个偏移量就能吸收 BIOS 版本差异业务代码一行不动。说人话差异进参数稳定逻辑留基类。反面场景没有这个基类每个特性自己手写 WMI 调用BIOS 一升级枚举错位你要挨个修二十个文件。FnQ 一次切换同步三处状态PowerModeListener是联动的最佳样本。用户按 FnQ 切模式WMI 事件进来后OnChangedAsync做两件事联动副作用 发桌面通知// 源码路径LenovoLegionToolkit.Lib/Listeners/PowerModeListener.cs protected override async Task OnChangedAsync(PowerModeState value) { await ChangeDependenciesAsync(value).ConfigureAwait(false); PublishNotification(value); // 通过 MessagingCenter 发桌面通知 } private async Task ChangeDependenciesAsync(PowerModeState value) { if (value is PowerModeState.GodMode) await godModeController.ApplyStateAsync().ConfigureAwait(false); // ① 应用自定义模式参数 await windowsPowerModeController.SetPowerModeAsync(value).ConfigureAwait(false); // ② Windows 现代电源模式 await windowsPowerPlanController.SetPowerPlanAsync(value).ConfigureAwait(false); // ③ Windows 电源计划 }一次事件、三路副作用自定义模式参数、Windows 电源模式、Windows 电源计划同时跟手。反面场景只切联想模式不动 Windows 计划会出现风扇转速按性能模式拉满CPU 功耗却被节能计划压着的分裂状态温度表现完全不符合预期。GPU 先判忙不忙再决定重启混合模式下切显卡工作模式前必须知道独显当前是否被占用。GPUController默认每 5 秒用 NVAPI 轮询一次状态需要重置独显时走pnputil设备级重启// 源码路径LenovoLegionToolkit.Lib/Controllers/GPUController.cs节选 public Task StartAsync(int delay 1_000, int interval 5_000) // ← 默认 5 秒轮询 { if (IsStarted) return Task.CompletedTask; _refreshCancellationTokenSource new CancellationTokenSource(); var token _refreshCancellationTokenSource.Token; _refreshTask Task.Run(() RefreshLoopAsync(delay, interval, token), token); return Task.CompletedTask; } public async Task RestartGPUAsync() { using (await _lock.LockAsync().ConfigureAwait(false)) // 异步锁跨 await 保持互斥 { if (_state is not GPUState.Active and not GPUState.Inactive) return; // GPU 未知或未找到时不碰它 // 按 PnP 设备实例ID重启独显等价于设备管理器里禁用再启用 await CMD.RunAsync(pnputil, $/restart-device \{_gpuInstanceId}\).ConfigureAwait(false); } }整条链路一句话NVAPI 判断在不在忙pnputil负责重启干活。若不先判忙游戏正在跑就重启 GPU轻则画面卡死重连重则直接蓝屏。实操把控制权交给脚本CLI 命令全集怎么跑llt.exe不直接碰硬件——它把请求序列化成 JSON经命名管道发给后台主程序执行。协议长这样// 源码路径LenovoLegionToolkit.CLI.Lib/IpcRequest.cs节选含部分枚举值 public class IpcRequest { public enum OperationType { Unknown, ListFeatures, // 列出所有可用功能 GetFeatureValue, // 读功能状态 SetFeatureValue, // 设功能状态 GetSpectrumProfile, // 读 Spectrum 灯效配置 SetSpectrumProfile, // 应用 Spectrum 灯效配置 GetRGBPreset, // 读 4 区 RGB 预设 SetRGBPreset, // 应用 4 区 RGB 预设 QuickAction, // 执行快捷操作 } public OperationType? Operation { get; init; } public string? Name { get; init; } public string? Value { get; init; } }主程序没运行或设置里没开 CLI 选项时CLI 抛IpcConnectException退出码为 -1脚本可据此判断故障原因。常用命令PowerShell / CMD 通用# 前提LLT 主程序在后台运行且设置中已开启 CLI llt feature --list # 列出本机所有可用功能 llt feature get PowerMode # 输出Quiet / Balance / Performance / GodMode llt feature set PowerMode --list # 查看该功能的全部可选值 llt feature set PowerMode Performance # 切到性能模式 llt rgb set 3 # 应用第 4 个 RGB 预设编号从 0 开始 llt spectrum profile set 2 # 应用第 3 套 Spectrum 配置 llt spectrum brightness set 75 # Spectrum 背光亮度 75% llt quickAction --list # 列出快捷操作 llt quickAction 游戏模式 # 执行指定快捷操作✅ 验证执行llt feature get PowerMode输出与你刚 set 的值一致即生效看到 Failed to connect退出码 -1说明主程序没跑或 CLI 未开启。args.txt 保存常用开关GUI 里没有的开关走启动参数。主程序启动时会逐行读取应用数据目录下的args.txt等价于命令行追加# 文件位置%LOCALAPPDATA%\LenovoLegionToolkit\args.txt每行一个参数 --trace --minimized --allow-all-power-modes-on-battery --experimental-gpu-working-mode --enable-hybrid-mode-automation --force-disable-rgbkb --disable-update-checker这些参数大多是救场用的升级 BIOS 后切混合模式失败先加--experimental-gpu-working-mode和官方 Vantage 共存抢灯光控制权用--force-disable-rgbkb这类参数让出控制权。✅ 验证写入--trace后重启主程序界面左上角出现[LOGGING ENABLED]%LOCALAPPDATA%\LenovoLegionToolkit\log目录开始生成日志文件即生效。脚本感知系统状态LLT_ 环境变量自动化管道执行运行程序步骤时会注入一批LLT_前缀的环境变量快照脚本据此做分支决策.bat 示例两个 GUID 换成powercfg /list查到的你自己的计划 GUIDecho off rem 由 LLT 自动化运行程序步骤启动时自动注入 LLT_ 环境变量 if %LLT_IS_AC_ADAPTER_CONNECTED%TRUE ( rem 接了电源切高性能计划 powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c ) else ( rem 用电池切节能计划 powercfg /setactive a1841308-3541-4fab-bc81-f71556f20b4a ) if %LLT_IS_GAME_RUNNING%TRUE ( echo [LLT] 检测到游戏运行当前模式 %LLT_POWER_MODE_NAME% )完整清单还有LLT_WIFI_CONNECTED、LLT_WIFI_SSID、LLT_SESSION_LOCKED、LLT_IS_DISPLAY_ON、LLT_PROCESSES等二十余个覆盖绝大多数自动化场景。比如连上公司 WiFi 切平衡、断网切安静一条if %LLT_WIFI_SSID%Office_5G就搞定。✅ 验证把脚本里加一行echo %LLT_POWER_MODE% %TEMP%\llt_env.txt配一条游戏启动触发 运行此脚本的自动化启动游戏后打开该文件能看到3Performance即注入成功。进阶加一个自己的功能实现 IFeature15 行出一个功能LLT 所有硬件特性都收敛到IFeatureT接口。以摄像头指示灯为例最小实现// 源码路径新文件放入 LenovoLegionToolkit.Lib/Features/ 目录示例代码 public class CameraIndicatorFeature : IFeaturebool { public string Name CameraIndicator; public Taskbool[] GetAllStatesAsync() Task.FromResult([false, true]); public Taskbool GetStateAsync() ReadFromRegistryAsync(CameraIndicatorEnabled); public Task SetStateAsync(bool state) { WriteToRegistryAsync(CameraIndicatorEnabled, state); // ← 注意硬件操作自己写 StateChanged?.Invoke(this, new FeatureStateChangedEventArgsbool(state)); return Task.CompletedTask; } public event EventHandlerFeatureStateChangedEventArgsbool? StateChanged; }GetStateAsync/SetStateAsync/GetAllStatesAsync三个方法对应 CLI 的 get、set、--list一个不能少。注册到 IoCModule三处自动识别在LenovoLegionToolkit.Lib/IoCModule.cs的Load方法里加一行builder.RegisterCameraIndicatorFeature().AsSelf().SingleInstance();编译运行后这个功能自动出现在 GUI 设置页、可被自动化步骤引用、可被llt feature get CameraIndicator控制。这就是依赖注入容器的红利扩展只加文件不改任何现有模块。想读源码对照着写克隆仓库即可git clone https://gitcode.com/gh_mirrors/le/LenovoLegionToolkit。下一步动作给args.txt加上--trace触发一次游戏启动 → 切性能模式的自动化然后在日志里按监听器 → 触发器 → 步骤把本文链路串一遍。【免费下载链接】LenovoLegionToolkitLightweight Lenovo Vantage and Hotkeys replacement for Lenovo Legion laptops.项目地址: https://gitcode.com/gh_mirrors/le/LenovoLegionToolkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考