Repository: BartoszCichecki/LenovoLegionToolkit
Branch: master
Commit: 63c173024495
Files: 761
Total size: 5.4 MB
Directory structure:
gitextract_7y507dhv/
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── 1_feature_request.yml
│ │ ├── 2_bug_report.yml
│ │ ├── 3_compatibility_request.yml
│ │ └── config.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── build.yml
│ └── release.yml
├── .gitignore
├── CONTRIBUTING.md
├── CONTRIBUTING_ja-JP.md
├── CONTRIBUTING_zh-hans.md
├── InnoDependencies/
│ ├── Arabic.isl
│ ├── ChineseSimplified.isl
│ ├── ChineseTraditional.isl
│ ├── Greek.isl
│ ├── Latvian.isl
│ ├── Romanian.isl
│ ├── Vietnamese.isl
│ └── install_dotnet.iss
├── LICENSE
├── LenovoLegionToolkit.CLI/
│ ├── Flags.cs
│ ├── IpcClient.cs
│ ├── LenovoLegionToolkit.CLI.csproj
│ └── Program.cs
├── LenovoLegionToolkit.CLI.Lib/
│ ├── Constants.cs
│ ├── Extensions/
│ │ └── PipeStreamExtensions.cs
│ ├── IpcConnectException.cs
│ ├── IpcException.cs
│ ├── IpcRequest.cs
│ ├── IpcResponse.cs
│ └── LenovoLegionToolkit.CLI.Lib.csproj
├── LenovoLegionToolkit.Lib/
│ ├── AutoListeners/
│ │ ├── AbstractAutoListener.cs
│ │ ├── GameAutoListener.cs
│ │ ├── IAutoListener.cs
│ │ ├── InstanceStartedEventAutoAutoListener.cs
│ │ ├── InstanceStoppedEventAutoAutoListener.cs
│ │ ├── ProcessAutoListener.cs
│ │ ├── TimeAutoListener.cs
│ │ ├── UserInactivityAutoListener.cs
│ │ └── WiFiAutoListener.cs
│ ├── Controllers/
│ │ ├── AIController.cs
│ │ ├── DisplayBrightnessController.cs
│ │ ├── GPUController.cs
│ │ ├── GPUOverclockController.cs
│ │ ├── GodMode/
│ │ │ ├── AbstractGodModeController.cs
│ │ │ ├── GodModeController.cs
│ │ │ ├── GodModeControllerV1.cs
│ │ │ ├── GodModeControllerV2.cs
│ │ │ └── IGodModeController.cs
│ │ ├── RGBKeyboardBacklightController.cs
│ │ ├── Sensors/
│ │ │ ├── AbstractSensorsController.cs
│ │ │ ├── ISensorsController.cs
│ │ │ ├── SensorsController.cs
│ │ │ ├── SensorsControllerV1.cs
│ │ │ ├── SensorsControllerV2.cs
│ │ │ └── SensorsControllerV3.cs
│ │ ├── SmartFnLockController.cs
│ │ ├── SpectrumKeyboardBacklightController.cs
│ │ ├── WindowsPowerModeController.cs
│ │ └── WindowsPowerPlanController.cs
│ ├── Enums.cs
│ ├── Extensions/
│ │ ├── AssemblyExtensions.cs
│ │ ├── ContainerBuilderExtensions.cs
│ │ ├── DateTimeExtensions.cs
│ │ ├── DictionaryExtensions.cs
│ │ ├── DisplayExtensions.cs
│ │ ├── DisplayPossibleSettingExtensions.cs
│ │ ├── DisplaySettingExtensions.cs
│ │ ├── EnumExtensions.cs
│ │ ├── EnumerableExtensions.cs
│ │ ├── HttpClientExtensions.cs
│ │ ├── IntExtensions.cs
│ │ ├── ListExtensions.cs
│ │ ├── LogoInfoFormatExtensions.cs
│ │ ├── ManagementObjectSearcherExtensions.cs
│ │ ├── MathExtensions.cs
│ │ ├── OSExtensions.cs
│ │ ├── PInvokeExtensions.cs
│ │ ├── PhyscialGPUExtensions.cs
│ │ ├── ProcessExtensions.cs
│ │ ├── PropertyDataCollectionExtensions.cs
│ │ ├── RGBKeyboardBacklightPresetExtensions.cs
│ │ ├── RegistrationBuilderExtensions.cs
│ │ ├── ServiceControllerExtension.cs
│ │ ├── SpectrumKeyboardBacklightEffectTypeExtensions.cs
│ │ ├── StreamExtensions.cs
│ │ ├── StringExtensions.cs
│ │ ├── TaskExtensions.cs
│ │ ├── TimeExtensions.cs
│ │ ├── UintExtensions.cs
│ │ └── VersionExtensions.cs
│ ├── Features/
│ │ ├── AbstractCapabilityFeature.cs
│ │ ├── AbstractCompositeFeature.cs
│ │ ├── AbstractDriverFeature.cs
│ │ ├── AbstractLenovoLightingFeature.cs
│ │ ├── AbstractUEFIFeature.cs
│ │ ├── AbstractWmiFeature.cs
│ │ ├── AlwaysOnUsbFeature.cs
│ │ ├── BatteryFeature.cs
│ │ ├── BatteryNightChargeFeature.cs
│ │ ├── DpiScaleFeature.cs
│ │ ├── FlipToStart/
│ │ │ ├── FlipToStartCapabilityFeature.cs
│ │ │ ├── FlipToStartFeature.cs
│ │ │ └── FlipToStartUEFIFeature.cs
│ │ ├── FnLockFeature.cs
│ │ ├── HDRFeature.cs
│ │ ├── Hybrid/
│ │ │ ├── GSyncFeature.cs
│ │ │ ├── HybridModeFeature.cs
│ │ │ ├── IGPUModeCapabilityFeature.cs
│ │ │ ├── IGPUModeChangeException.cs
│ │ │ ├── IGPUModeFeature.cs
│ │ │ ├── IGPUModeFeatureFlagsFeature.cs
│ │ │ ├── IGPUModeGamezoneFeature.cs
│ │ │ └── Notify/
│ │ │ ├── AbstractDGPUNotify.cs
│ │ │ ├── DGPUCapabilityNotify.cs
│ │ │ ├── DGPUFeatureFlagsNotify.cs
│ │ │ ├── DGPUGamezoneNotify.cs
│ │ │ ├── DGPUNotify.cs
│ │ │ └── IDGPUNotify.cs
│ │ ├── IFeature.cs
│ │ ├── InstantBoot/
│ │ │ ├── InstantBootCapabilityFeature.cs
│ │ │ ├── InstantBootFeature.cs
│ │ │ └── InstantBootFeatureFlagsFeature.cs
│ │ ├── MicrophoneFeature.cs
│ │ ├── OneLevelWhiteKeyboardBacklightFeature.cs
│ │ ├── OverDrive/
│ │ │ ├── OverDriveCapabilityFeature.cs
│ │ │ ├── OverDriveFeature.cs
│ │ │ └── OverDriveGameZoneFeature.cs
│ │ ├── PanelLogo/
│ │ │ ├── PanelLogoBacklightFeature.cs
│ │ │ ├── PanelLogoLenovoLightingBacklightFeature.cs
│ │ │ └── PanelLogoSpectrumBacklightFeature.cs
│ │ ├── PortsBacklightFeature.cs
│ │ ├── PowerModeFeature.cs
│ │ ├── RefreshRateFeature.cs
│ │ ├── ResolutionFeature.cs
│ │ ├── SpeakerFeature.cs
│ │ ├── TouchpadLockFeature.cs
│ │ ├── WhiteKeyboardBacklight/
│ │ │ ├── WhiteKeyboardBacklightFeature.cs
│ │ │ ├── WhiteKeyboardDriverBacklightFeature.cs
│ │ │ └── WhiteKeyboardLenovoLightingBacklightFeature.cs
│ │ └── WinKeyFeature.cs
│ ├── GameDetection/
│ │ ├── EffectiveGameModeDetector.cs
│ │ └── GameConfigStoreDetector.cs
│ ├── GlobalSuppressions.cs
│ ├── HttpClientFactory.cs
│ ├── Integrations/
│ │ └── HWiNFOIntegration.cs
│ ├── Interfaces.cs
│ ├── IoCContainer.cs
│ ├── IoCModule.cs
│ ├── LenovoLegionToolkit.Lib.csproj
│ ├── LenovoLegionToolkit.Lib.csproj.DotSettings
│ ├── Listeners/
│ │ ├── AbstractEventLogListener.cs
│ │ ├── AbstractWMIListener.cs
│ │ ├── DisplayBrightnessListener.cs
│ │ ├── DisplayConfigurationListener.cs
│ │ ├── DriverKeyListener.cs
│ │ ├── IListener.cs
│ │ ├── INotifyingListener.cs
│ │ ├── LightingChangeListener.cs
│ │ ├── NativeWindowsMessageListener.cs
│ │ ├── PowerModeListener.cs
│ │ ├── PowerStateListener.cs
│ │ ├── RGBKeyboardBacklightListener.cs
│ │ ├── SessionLockUnlockListener.cs
│ │ ├── SpecialKeyListener.cs
│ │ ├── SystemThemeListener.cs
│ │ ├── ThermalModeListener.cs
│ │ └── WinKeyListener.cs
│ ├── Messaging/
│ │ ├── Messages/
│ │ │ ├── FeatureStateMessage.cs
│ │ │ ├── IMessage.cs
│ │ │ ├── NotificationMessage.cs
│ │ │ ├── RGBKeyboardBacklightChangedMessage.cs
│ │ │ └── SpectrumBacklightChangedMessage.cs
│ │ └── MessagingCenter.cs
│ ├── Native.cs
│ ├── NativeMethods.json
│ ├── NativeMethods.txt
│ ├── PackageDownloader/
│ │ ├── AbstractPackageDownloader.cs
│ │ ├── Detectors/
│ │ │ ├── Rules/
│ │ │ │ ├── AndPackageRule.cs
│ │ │ │ ├── BiosPackageRule.cs
│ │ │ │ ├── CpuAddressWidthPackageRule.cs
│ │ │ │ ├── DriverPackageRule.cs
│ │ │ │ ├── ExternalDetectionRule.cs
│ │ │ │ ├── IPackageRule.cs
│ │ │ │ ├── NotPackageRule.cs
│ │ │ │ ├── OrPackageRule.cs
│ │ │ │ ├── OsPackageRule.cs
│ │ │ │ ├── PnPIdPackageRule.cs
│ │ │ │ ├── RegistryKeyPackageRule.cs
│ │ │ │ ├── RegistryKeyValuePackageRule.cs
│ │ │ │ └── WindowsBuildVersionPackageRule.cs
│ │ │ └── VantagePackageUpdateDetector.cs
│ │ ├── IPackageDownloader.cs
│ │ ├── PCSupportPackageDownloader.cs
│ │ ├── PackageDownloaderFactory.cs
│ │ ├── UpdateCatalogNotFoundException.cs
│ │ └── VantagePackageDownloader.cs
│ ├── Resources/
│ │ ├── Resource.Designer.cs
│ │ ├── Resource.ar.resx
│ │ ├── Resource.bg.resx
│ │ ├── Resource.bs.resx
│ │ ├── Resource.ca.resx
│ │ ├── Resource.cs.resx
│ │ ├── Resource.de.resx
│ │ ├── Resource.el.resx
│ │ ├── Resource.es.resx
│ │ ├── Resource.fr.resx
│ │ ├── Resource.hu.resx
│ │ ├── Resource.it.resx
│ │ ├── Resource.ja.resx
│ │ ├── Resource.ko.resx
│ │ ├── Resource.lv.resx
│ │ ├── Resource.nl-nl.resx
│ │ ├── Resource.pl.resx
│ │ ├── Resource.pt-br.resx
│ │ ├── Resource.pt.resx
│ │ ├── Resource.resx
│ │ ├── Resource.ro.resx
│ │ ├── Resource.ru.resx
│ │ ├── Resource.sk.resx
│ │ ├── Resource.tr.resx
│ │ ├── Resource.uk.resx
│ │ ├── Resource.uz-latn-uz.resx
│ │ ├── Resource.vi.resx
│ │ ├── Resource.zh-hans.resx
│ │ └── Resource.zh-hant.resx
│ ├── Services/
│ │ └── BatteryDischargeRateMonitorService.cs
│ ├── Settings/
│ │ ├── AbstractSettings.cs
│ │ ├── ApplicationSettings.cs
│ │ ├── BalanceModeSettings.cs
│ │ ├── GPUOverclockSettings.cs
│ │ ├── GodModeSettings.cs
│ │ ├── IntegrationsSettings.cs
│ │ ├── PackageDownloaderSettings.cs
│ │ ├── RGBKeyboardSettings.cs
│ │ ├── SpectrumKeyboardSettings.cs
│ │ ├── SunriseSunsetSettings.cs
│ │ └── UpdateCheckSettings.cs
│ ├── SoftwareDisabler/
│ │ ├── AbstractSoftwareDisabler.cs
│ │ ├── FnKeysDisabler.cs
│ │ ├── LegionZoneDisabler.cs
│ │ └── VantageDisabler.cs
│ ├── Structs.cs
│ ├── System/
│ │ ├── AirplaneMode.cs
│ │ ├── Autorun.cs
│ │ ├── Battery.cs
│ │ ├── BootLogo.cs
│ │ ├── CMD.cs
│ │ ├── Devices.cs
│ │ ├── Displays.cs
│ │ ├── Drivers.cs
│ │ ├── ExternalDisplays.cs
│ │ ├── InternalDisplay.cs
│ │ ├── KnownFolders.cs
│ │ ├── Management/
│ │ │ ├── WMI.LenovoCapabilityData00.cs
│ │ │ ├── WMI.LenovoCapabilityData01.cs
│ │ │ ├── WMI.LenovoCpuMethod.cs
│ │ │ ├── WMI.LenovoDefaultValueInDifferentModeData.cs
│ │ │ ├── WMI.LenovoDiscreteData.cs
│ │ │ ├── WMI.LenovoFanMethod.cs
│ │ │ ├── WMI.LenovoFanTableData.cs
│ │ │ ├── WMI.LenovoGameZoneData.cs
│ │ │ ├── WMI.LenovoGameZoneKeyLockStatusEvent.cs
│ │ │ ├── WMI.LenovoGameZoneLightProfileChangeEvent.cs
│ │ │ ├── WMI.LenovoGameZoneSmartFanModeEvent.cs
│ │ │ ├── WMI.LenovoGameZoneThermalModeEvent.cs
│ │ │ ├── WMI.LenovoGpuMethod.cs
│ │ │ ├── WMI.LenovoIntelligentOPList.cs
│ │ │ ├── WMI.LenovoLightingData.cs
│ │ │ ├── WMI.LenovoLightingEvent.cs
│ │ │ ├── WMI.LenovoLightingMethod.cs
│ │ │ ├── WMI.LenovoOtherMethod.cs
│ │ │ ├── WMI.LenovoUtilityEvent.cs
│ │ │ ├── WMI.Win32.cs
│ │ │ ├── WMI.WmiMonitorBrightnessEvent.cs
│ │ │ ├── WMI.WmiMonitorBrightnessMethods.cs
│ │ │ └── WMI.cs
│ │ ├── NVAPI.cs
│ │ ├── Power.cs
│ │ ├── Registry.cs
│ │ ├── SystemPath.cs
│ │ ├── SystemTheme.cs
│ │ └── WiFi.cs
│ └── Utils/
│ ├── Compatibility.cs
│ ├── Crc32Adler.cs
│ ├── Folders.cs
│ ├── IMainThreadDispatcher.cs
│ ├── LambdaAsyncDisposable.cs
│ ├── LambdaDisposable.cs
│ ├── Log.cs
│ ├── NullSafeHandle.cs
│ ├── RetryHelper.cs
│ ├── SafePerformanceCounter.cs
│ ├── StructSafeHandle.cs
│ ├── SunriseSunset.cs
│ ├── ThreadSafeBool.cs
│ ├── ThreadSafeCounter.cs
│ ├── ThrottleFirstDispatcher.cs
│ ├── ThrottleLastDispatcher.cs
│ ├── TokenManipulator.cs
│ ├── UpdateChecker.cs
│ └── WarrantyChecker.cs
├── LenovoLegionToolkit.Lib.Automation/
│ ├── AutomationContext.cs
│ ├── AutomationEnvironment.cs
│ ├── AutomationProcessor.cs
│ ├── Enums.cs
│ ├── GlobalSuppressions.cs
│ ├── IAutomationEvent.cs
│ ├── IoCModule.cs
│ ├── LenovoLegionToolkit.Lib.Automation.csproj
│ ├── LenovoLegionToolkit.Lib.Automation.csproj.DotSettings
│ ├── Pipeline/
│ │ ├── AutomationPipeline.cs
│ │ └── Triggers/
│ │ ├── ACAdapterConnectedAutomationPipelineTrigger.cs
│ │ ├── ACAdapterDisconnectedAutomationPipelineTrigger.cs
│ │ ├── AndAutomationPipelineTrigger.cs
│ │ ├── DeviceConnectedAutomationPipelineTrigger.cs
│ │ ├── DeviceDisconnectedAutomationPipelineTrigger.cs
│ │ ├── DisplayOffAutomationPipelineTrigger.cs
│ │ ├── DisplayOnAutomationPipelineTrigger.cs
│ │ ├── ExternalDisplayConnectedAutomationPipelineTrigger.cs
│ │ ├── ExternalDisplayDisconnectedAutomationPipelineTrigger.cs
│ │ ├── GamesAreRunningAutomationPipelineTrigger.cs
│ │ ├── GamesStopAutomationPipelineTrigger.cs
│ │ ├── GodModePresetChangedAutomationPipelineTrigger.cs
│ │ ├── HDROffAutomationPipelineTrigger.cs
│ │ ├── HDROnAutomationPipelineTrigger.cs
│ │ ├── IAutomationPipelineTrigger.cs
│ │ ├── LidClosedAutomationPipelineTrigger.cs
│ │ ├── LidOpenedAutomationPipelineTrigger.cs
│ │ ├── LowWattageACAdapterConnectedAutomationPipelineTrigger.cs
│ │ ├── OnResumeAutomationPipelineTrigger.cs
│ │ ├── OnStartupAutomationPipelineTrigger.cs
│ │ ├── PeriodicAutomationPipelineTrigger.cs
│ │ ├── PowerModeAutomationPipelineTrigger.cs
│ │ ├── ProcessesAreRunningAutomationPipelineTrigger.cs
│ │ ├── ProcessesStopRunningAutomationPipelineTrigger.cs
│ │ ├── SessionLockAutomationPipelineTrigger.cs
│ │ ├── SessionUnlockAutomationPipelineTrigger.cs
│ │ ├── TimeAutomationPipelineTrigger.cs
│ │ ├── UserInactivityAutomationPipelineTrigger.cs
│ │ ├── WiFiConnectedAutomationPipelineTrigger.cs
│ │ └── WiFiDisconnectedAutomationPipelineTrigger.cs
│ ├── Resources/
│ │ ├── Resource.Designer.cs
│ │ ├── Resource.ar.resx
│ │ ├── Resource.bg.resx
│ │ ├── Resource.bs.resx
│ │ ├── Resource.ca.resx
│ │ ├── Resource.cs.resx
│ │ ├── Resource.de.resx
│ │ ├── Resource.el.resx
│ │ ├── Resource.es.resx
│ │ ├── Resource.fr.resx
│ │ ├── Resource.hu.resx
│ │ ├── Resource.it.resx
│ │ ├── Resource.ja.resx
│ │ ├── Resource.ko.resx
│ │ ├── Resource.lv.resx
│ │ ├── Resource.nl-nl.resx
│ │ ├── Resource.pl.resx
│ │ ├── Resource.pt-br.resx
│ │ ├── Resource.pt.resx
│ │ ├── Resource.resx
│ │ ├── Resource.ro.resx
│ │ ├── Resource.ru.resx
│ │ ├── Resource.sk.resx
│ │ ├── Resource.tr.resx
│ │ ├── Resource.uk.resx
│ │ ├── Resource.uz-latn-uz.resx
│ │ ├── Resource.vi.resx
│ │ ├── Resource.zh-hans.resx
│ │ └── Resource.zh-hant.resx
│ ├── Steps/
│ │ ├── AbstractFeatureAutomationStep.cs
│ │ ├── AlwaysOnUsbAutomationStep.cs
│ │ ├── BatteryAutomationStep.cs
│ │ ├── BatteryNightChargeAutomationStep.cs
│ │ ├── DeactivateGPUAutomationStep.cs
│ │ ├── DelayAutomationStep.cs
│ │ ├── DisplayBrightnessAutomationStep.cs
│ │ ├── DpiScaleAutomationStep.cs
│ │ ├── FlipToStartAutomationStep.cs
│ │ ├── FnLockAutomationStep.cs
│ │ ├── GodModePresetAutomationStep.cs
│ │ ├── HDRAutomationStep.cs
│ │ ├── HybridModeAutomationStep.cs
│ │ ├── IAutomationStep.cs
│ │ ├── InstantBootAutomationStep.cs
│ │ ├── MacroAutomationStep.cs
│ │ ├── MicrophoneAutomationStep.cs
│ │ ├── NotificationAutomationStep.cs
│ │ ├── OneLevelWhiteKeyboardBacklightAutomationStep.cs
│ │ ├── OverDriveAutomationStep.cs
│ │ ├── OverclockDiscreteGPUAutomationStep.cs
│ │ ├── PanelLogoBacklightAutomationStep.cs
│ │ ├── PlaySoundAutomationStep.cs
│ │ ├── PortsBacklightAutomationStep.cs
│ │ ├── PowerModeAutomationStep.cs
│ │ ├── QuickActionAutomationStep.cs
│ │ ├── RGBKeyboardBacklightAutomationStep.cs
│ │ ├── RefreshRateAutomationStep.cs
│ │ ├── ResolutionAutomationStep.cs
│ │ ├── RunAutomationStep.cs
│ │ ├── SpeakerAutomationStep.cs
│ │ ├── SpectrumKeyboardBacklightBrightnessAutomationStep.cs
│ │ ├── SpectrumKeyboardBacklightImportProfileAutomationStep.cs
│ │ ├── SpectrumKeyboardBacklightProfileAutomationStep.cs
│ │ ├── TouchpadLockAutomationStep.cs
│ │ ├── TurnOffMonitorsAutomationStep.cs
│ │ ├── TurnOffWiFiAutomationStep.cs
│ │ ├── TurnOnWiFiAutomationStep.cs
│ │ ├── WhiteKeyboardBacklightAutomationStep.cs
│ │ └── WinKeyAutomationStep.cs
│ ├── Structs.cs
│ └── Utils/
│ └── AutomationSettings.cs
├── LenovoLegionToolkit.Lib.Macro/
│ ├── Enums.cs
│ ├── IoCModule.cs
│ ├── LenovoLegionToolkit.Lib.Macro.csproj
│ ├── MacroController.cs
│ ├── Resources/
│ │ ├── Resource.Designer.cs
│ │ ├── Resource.ar.resx
│ │ ├── Resource.bg.resx
│ │ ├── Resource.bs.resx
│ │ ├── Resource.cs.resx
│ │ ├── Resource.de.resx
│ │ ├── Resource.el.resx
│ │ ├── Resource.es.resx
│ │ ├── Resource.fr.resx
│ │ ├── Resource.hu.resx
│ │ ├── Resource.it.resx
│ │ ├── Resource.ja.resx
│ │ ├── Resource.ko.resx
│ │ ├── Resource.lv.resx
│ │ ├── Resource.nl-nl.resx
│ │ ├── Resource.pl.resx
│ │ ├── Resource.pt-br.resx
│ │ ├── Resource.pt.resx
│ │ ├── Resource.resx
│ │ ├── Resource.ro.resx
│ │ ├── Resource.ru.resx
│ │ ├── Resource.sk.resx
│ │ ├── Resource.tr.resx
│ │ ├── Resource.uk.resx
│ │ ├── Resource.uz-latn-uz.resx
│ │ ├── Resource.vi.resx
│ │ ├── Resource.zh-hans.resx
│ │ └── Resource.zh-hant.resx
│ ├── Structs.cs
│ └── Utils/
│ ├── MacroPlayer.cs
│ ├── MacroRecorder.cs
│ ├── MacroSettings.cs
│ └── TypeConverters/
│ └── MacroIdentifierTypeConverter.cs
├── LenovoLegionToolkit.SpectrumTester/
│ ├── LenovoLegionToolkit.SpectrumTester.csproj
│ └── Program.cs
├── LenovoLegionToolkit.WPF/
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── Assets/
│ │ ├── AssetResources.Designer.cs
│ │ └── AssetResources.resx
│ ├── Behaviors/
│ │ └── ProgressBarAnimateBehavior.cs
│ ├── CLI/
│ │ ├── Features/
│ │ │ ├── FeatureRegistration.cs
│ │ │ ├── FeatureRegistry.cs
│ │ │ └── IFeatureRegistration.cs
│ │ └── IpcServer.cs
│ ├── Constants.cs
│ ├── Controls/
│ │ ├── AbstractComboBoxFeatureCardControl.cs
│ │ ├── AbstractRefreshingControl.cs
│ │ ├── AbstractToggleFeatureCardControl.cs
│ │ ├── Automation/
│ │ │ ├── AbstractAutomationStepControl.cs
│ │ │ ├── AbstractComboBoxAutomationStepControl.cs
│ │ │ ├── AutomationPipelineControl.cs
│ │ │ └── Steps/
│ │ │ ├── AlwaysOnUsbAutomationStepControl.cs
│ │ │ ├── BatteryAutomationStepControl.cs
│ │ │ ├── BatteryNightChargeAutomationStepControl.cs
│ │ │ ├── DeactivateGPUAutomationStepControl.cs
│ │ │ ├── DelayAutomationStepControl.cs
│ │ │ ├── DisplayBrightnessAutomationStepControl.cs
│ │ │ ├── DpiScaleAutomationStepControl.cs
│ │ │ ├── FlipToStartAutomationStepControl.cs
│ │ │ ├── FnLockAutomationStepControl.cs
│ │ │ ├── GodModePresetAutomationStepControl.cs
│ │ │ ├── HDRAutomationStepControl.cs
│ │ │ ├── HybridModeAutomationStepControl.cs
│ │ │ ├── InstantBootAutomationStepControl.cs
│ │ │ ├── MacroAutomationStepControl.cs
│ │ │ ├── MicrophoneAutomationStepControl.cs
│ │ │ ├── NotificationAutomationStepControl.cs
│ │ │ ├── OneLevelWhiteKeyboardBacklightAutomationStepControl.cs
│ │ │ ├── OverDriveAutomationStepControl.cs
│ │ │ ├── OverclockDiscreteGPUAutomationStepControl.cs
│ │ │ ├── PanelLogoBacklightAutomationStepControl.cs
│ │ │ ├── PlaySoundAutomationStepControl.cs
│ │ │ ├── PortsBacklightAutomationStepControl.cs
│ │ │ ├── PowerModeAutomationStepControl.cs
│ │ │ ├── QuickActionAutomationStepControl.cs
│ │ │ ├── RGBKeyboardBacklightAutomationStepControl.cs
│ │ │ ├── RefreshRateAutomationStepControl.cs
│ │ │ ├── ResolutionAutomationStepControl.cs
│ │ │ ├── RunAutomationStepControl.cs
│ │ │ ├── SpeakerAutomationStepControl.cs
│ │ │ ├── SpectrumKeyboardBacklightBrightnessAutomationStepControl.cs
│ │ │ ├── SpectrumKeyboardBacklightImportProfileAutomationStepControl.cs
│ │ │ ├── SpectrumKeyboardBacklightProfileAutomationStepControl.cs
│ │ │ ├── TouchpadLockAutomationStepControl.cs
│ │ │ ├── TurnOffMonitorsAutomationStepControl.cs
│ │ │ ├── TurnOffWiFiAutomationStepControl.cs
│ │ │ ├── TurnOnWiFiAutomationStepControl.cs
│ │ │ ├── WhiteKeyboardBacklightAutomationStepControl.cs
│ │ │ └── WinKeyAutomationStepControl.cs
│ │ ├── CardHeaderControl.cs
│ │ ├── ColorPickerControl.xaml
│ │ ├── ColorPickerControl.xaml.cs
│ │ ├── Custom/
│ │ │ ├── Badge.cs
│ │ │ ├── CardAction.cs
│ │ │ ├── CardControl.cs
│ │ │ ├── CardExpander.cs
│ │ │ ├── InfoBar.cs
│ │ │ └── NavigationItem.cs
│ │ ├── Dashboard/
│ │ │ ├── AlwaysOnUSBControl.cs
│ │ │ ├── BatteryModeControl.cs
│ │ │ ├── BatteryNightChargeModeControl.cs
│ │ │ ├── DashboardGroupControl.cs
│ │ │ ├── DiscreteGPUControl.xaml
│ │ │ ├── DiscreteGPUControl.xaml.cs
│ │ │ ├── DpiScaleControl.cs
│ │ │ ├── Edit/
│ │ │ │ ├── EditDashboardGroupControl.cs
│ │ │ │ └── EditDashboardItemControl.cs
│ │ │ ├── FlipToStartControl.cs
│ │ │ ├── FnLockControl.cs
│ │ │ ├── GodMode/
│ │ │ │ ├── GodModeValueControl.xaml
│ │ │ │ └── GodModeValueControl.xaml.cs
│ │ │ ├── HDRControl.cs
│ │ │ ├── HybridModeControlFactory.cs
│ │ │ ├── InstantBootControl.cs
│ │ │ ├── MicrophoneControl.cs
│ │ │ ├── OneLevelWhiteKeyboardBacklightControl.cs
│ │ │ ├── OverDriveControl.cs
│ │ │ ├── OverclockDiscreteGPUControl.cs
│ │ │ ├── PanelLogoBacklightControl.cs
│ │ │ ├── PortsBacklightControl.cs
│ │ │ ├── PowerModeControl.cs
│ │ │ ├── RefreshRateControl.cs
│ │ │ ├── ResolutionControl.cs
│ │ │ ├── SensorsControl.xaml
│ │ │ ├── SensorsControl.xaml.cs
│ │ │ ├── TouchpadLockControl.cs
│ │ │ ├── TurnOffMonitorsControl.xaml
│ │ │ ├── TurnOffMonitorsControl.xaml.cs
│ │ │ ├── WhiteKeyboardBacklightControl.cs
│ │ │ └── WinKeyControl.cs
│ │ ├── FanCurveControl.xaml
│ │ ├── FanCurveControl.xaml.cs
│ │ ├── KeyboardBacklight/
│ │ │ ├── RGB/
│ │ │ │ ├── AbstractComboBoxRGBKeyboardCardControl.cs
│ │ │ │ ├── RGBKeyboardBacklightBrightnessCardControl.cs
│ │ │ │ ├── RGBKeyboardBacklightControl.xaml
│ │ │ │ ├── RGBKeyboardBacklightControl.xaml.cs
│ │ │ │ ├── RGBKeyboardBacklightEffectCardControl.cs
│ │ │ │ └── RGBKeyboardBacklightSpeedCardControl.cs
│ │ │ └── Spectrum/
│ │ │ ├── Device/
│ │ │ │ ├── SpectrumDeviceControl.cs
│ │ │ │ ├── SpectrumDeviceFullAlternativeControl.xaml
│ │ │ │ ├── SpectrumDeviceFullAlternativeControl.xaml.cs
│ │ │ │ ├── SpectrumDeviceFullControl.xaml
│ │ │ │ ├── SpectrumDeviceFullControl.xaml.cs
│ │ │ │ ├── SpectrumDeviceKeyboardAndFrontControl.xaml
│ │ │ │ ├── SpectrumDeviceKeyboardAndFrontControl.xaml.cs
│ │ │ │ ├── SpectrumDeviceKeyboardOnlyControl.xaml
│ │ │ │ ├── SpectrumDeviceKeyboardOnlyControl.xaml.cs
│ │ │ │ ├── SpectrumKeyboardANSIControl.xaml
│ │ │ │ ├── SpectrumKeyboardANSIControl.xaml.cs
│ │ │ │ ├── SpectrumKeyboardControl.cs
│ │ │ │ ├── SpectrumKeyboardISOControl.xaml
│ │ │ │ ├── SpectrumKeyboardISOControl.xaml.cs
│ │ │ │ ├── SpectrumKeyboardJisControl.xaml
│ │ │ │ ├── SpectrumKeyboardJisControl.xaml.cs
│ │ │ │ ├── SpectrumZoneControl.xaml
│ │ │ │ └── SpectrumZoneControl.xaml.cs
│ │ │ ├── SpectrumKeyboardBacklightControl.xaml
│ │ │ ├── SpectrumKeyboardBacklightControl.xaml.cs
│ │ │ ├── SpectrumKeyboardEffectControl.xaml
│ │ │ └── SpectrumKeyboardEffectControl.xaml.cs
│ │ ├── LoadableControl.cs
│ │ ├── Macro/
│ │ │ ├── AbstractMacroEventControl.xaml
│ │ │ ├── AbstractMacroEventControl.xaml.cs
│ │ │ ├── MacroSequenceControl.xaml
│ │ │ ├── MacroSequenceControl.xaml.cs
│ │ │ ├── MultiAbstractMacroEventControl.cs
│ │ │ └── SingleAbstractMacroEventControl.cs
│ │ ├── MultiColorPickerControl.xaml
│ │ ├── MultiColorPickerControl.xaml.cs
│ │ ├── MultiColorPickerItemControl.xaml
│ │ ├── MultiColorPickerItemControl.xaml.cs
│ │ ├── Packages/
│ │ │ ├── PackageControl.xaml
│ │ │ └── PackageControl.xaml.cs
│ │ └── SelectableControl.cs
│ ├── Enums.cs
│ ├── Extensions/
│ │ ├── AutomationPipelineTriggerExtensions.cs
│ │ ├── ClipboardExtensions.cs
│ │ ├── ColorExtensions.cs
│ │ ├── ComboBoxExtensions.cs
│ │ ├── DashboardItemExtensions.cs
│ │ ├── DispatcherExtensions.cs
│ │ ├── ImageSourceExtensions.cs
│ │ ├── ItemCollectionExtensions.cs
│ │ ├── NavigationStoreExtensions.cs
│ │ ├── PowerModeStateExtensions.cs
│ │ ├── RGBColorExtensions.cs
│ │ ├── UIElementExtensions.cs
│ │ ├── UriExtensions.cs
│ │ └── WindowExtensions.cs
│ ├── Flags.cs
│ ├── GlobalSuppressions.cs
│ ├── IoCModule.cs
│ ├── LenovoLegionToolkit.WPF.csproj
│ ├── LenovoLegionToolkit.WPF.csproj.DotSettings
│ ├── Pages/
│ │ ├── AboutPage.xaml
│ │ ├── AboutPage.xaml.cs
│ │ ├── AutomationPage.xaml
│ │ ├── AutomationPage.xaml.cs
│ │ ├── BatteryPage.xaml
│ │ ├── BatteryPage.xaml.cs
│ │ ├── DashboardPage.xaml
│ │ ├── DashboardPage.xaml.cs
│ │ ├── DonatePage.xaml
│ │ ├── DonatePage.xaml.cs
│ │ ├── KeyboardBacklightPage.xaml
│ │ ├── KeyboardBacklightPage.xaml.cs
│ │ ├── MacroPage.xaml
│ │ ├── MacroPage.xaml.cs
│ │ ├── PackagesPage.xaml
│ │ ├── PackagesPage.xaml.cs
│ │ ├── SettingsPage.xaml
│ │ └── SettingsPage.xaml.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── Resources/
│ │ ├── Resource.Designer.cs
│ │ ├── Resource.ar.resx
│ │ ├── Resource.bg.resx
│ │ ├── Resource.bs.resx
│ │ ├── Resource.ca.resx
│ │ ├── Resource.cs.resx
│ │ ├── Resource.de.resx
│ │ ├── Resource.el.resx
│ │ ├── Resource.es.resx
│ │ ├── Resource.fr.resx
│ │ ├── Resource.hu.resx
│ │ ├── Resource.it.resx
│ │ ├── Resource.ja.resx
│ │ ├── Resource.ko.resx
│ │ ├── Resource.lv.resx
│ │ ├── Resource.nl-nl.resx
│ │ ├── Resource.pl.resx
│ │ ├── Resource.pt-br.resx
│ │ ├── Resource.pt.resx
│ │ ├── Resource.resx
│ │ ├── Resource.ro.resx
│ │ ├── Resource.ru.resx
│ │ ├── Resource.sk.resx
│ │ ├── Resource.tr.resx
│ │ ├── Resource.uk.resx
│ │ ├── Resource.uz-latn-uz.resx
│ │ ├── Resource.vi.resx
│ │ ├── Resource.zh-hans.resx
│ │ └── Resource.zh-hant.resx
│ ├── Settings/
│ │ └── DashboardSettings.cs
│ ├── Structs.cs
│ ├── Styles/
│ │ ├── Badge.xaml
│ │ ├── CardAction.xaml
│ │ ├── CardControl.xaml
│ │ ├── CardExpander.xaml
│ │ ├── DynamicScrollBar.xaml
│ │ ├── InfoBar.xaml
│ │ └── NavigationStore.xaml
│ ├── Utils/
│ │ ├── FullscreenHelper.cs
│ │ ├── LocalizationHelper.cs
│ │ ├── MainThreadDispatcher.cs
│ │ ├── MesageBoxHelper.cs
│ │ ├── NotificationsManager.cs
│ │ ├── NotifyIcon.cs
│ │ ├── ScreenHelper.cs
│ │ ├── SmartKeyHelper.cs
│ │ ├── SnackbarHelper.cs
│ │ ├── SpectrumScreenCapture.cs
│ │ ├── ThemeManager.cs
│ │ └── TrayHelper.cs
│ ├── Windows/
│ │ ├── Automation/
│ │ │ ├── AddAutomationStepWindow.xaml
│ │ │ ├── AddAutomationStepWindow.xaml.cs
│ │ │ ├── AutomationPipelineTriggerConfigurationWindow.xaml
│ │ │ ├── AutomationPipelineTriggerConfigurationWindow.xaml.cs
│ │ │ ├── CreateAutomationPipelineWindow.xaml
│ │ │ ├── CreateAutomationPipelineWindow.xaml.cs
│ │ │ └── TabItemContent/
│ │ │ ├── DeviceAutomationPipelineTriggerTabItemContent.xaml
│ │ │ ├── DeviceAutomationPipelineTriggerTabItemContent.xaml.cs
│ │ │ ├── GodModePresetPipelineTriggerTabItemContent.xaml
│ │ │ ├── GodModePresetPipelineTriggerTabItemContent.xaml.cs
│ │ │ ├── IAutomationPipelineTriggerTabItemContent.cs
│ │ │ ├── PeriodicActionPipelineTriggerTabItemContent.xaml
│ │ │ ├── PeriodicActionPipelineTriggerTabItemContent.xaml.cs
│ │ │ ├── PowerModeAutomationPipelineTriggerTabItemContent.xaml
│ │ │ ├── PowerModeAutomationPipelineTriggerTabItemContent.xaml.cs
│ │ │ ├── ProcessAutomationPipelineTriggerTabItemControl.xaml
│ │ │ ├── ProcessAutomationPipelineTriggerTabItemControl.xaml.cs
│ │ │ ├── TimeAutomationPipelineTriggerTabItemContent.xaml
│ │ │ ├── TimeAutomationPipelineTriggerTabItemContent.xaml.cs
│ │ │ ├── UserInactivityPipelineTriggerTabItemContent.xaml
│ │ │ ├── UserInactivityPipelineTriggerTabItemContent.xaml.cs
│ │ │ ├── WiFiConnectedPipelineTriggerTabItemContent.xaml
│ │ │ └── WiFiConnectedPipelineTriggerTabItemContent.xaml.cs
│ │ ├── BaseWindow.cs
│ │ ├── Dashboard/
│ │ │ ├── AddDashboardItemWindow.xaml
│ │ │ ├── AddDashboardItemWindow.xaml.cs
│ │ │ ├── BalanceModeSettingsWindow.xaml
│ │ │ ├── BalanceModeSettingsWindow.xaml.cs
│ │ │ ├── EditDashboardWindow.xaml
│ │ │ ├── EditDashboardWindow.xaml.cs
│ │ │ ├── ExtendedHybridModeInfoWindow.xaml
│ │ │ ├── ExtendedHybridModeInfoWindow.xaml.cs
│ │ │ ├── GodModeSettingsWindow.xaml
│ │ │ ├── GodModeSettingsWindow.xaml.cs
│ │ │ ├── OverclockDiscreteGPUSettingsWindow.xaml
│ │ │ └── OverclockDiscreteGPUSettingsWindow.xaml.cs
│ │ ├── KeyboardBacklight/
│ │ │ └── Spectrum/
│ │ │ ├── SpectrumKeyboardBacklightEditEffectWindow.xaml
│ │ │ └── SpectrumKeyboardBacklightEditEffectWindow.xaml.cs
│ │ ├── Macro/
│ │ │ └── MacroRecordingWindow.cs
│ │ ├── MainWindow.xaml
│ │ ├── MainWindow.xaml.cs
│ │ ├── Settings/
│ │ │ ├── BootLogoWindow.xaml
│ │ │ ├── BootLogoWindow.xaml.cs
│ │ │ ├── ExcludeRefreshRatesWindow.xaml
│ │ │ ├── ExcludeRefreshRatesWindow.xaml.cs
│ │ │ ├── NotificationsSettingsWindow.xaml
│ │ │ ├── NotificationsSettingsWindow.xaml.cs
│ │ │ ├── SelectSmartKeyPipelinesWindow.xaml
│ │ │ ├── SelectSmartKeyPipelinesWindow.xaml.cs
│ │ │ ├── WindowsPowerModesWindow.xaml
│ │ │ ├── WindowsPowerModesWindow.xaml.cs
│ │ │ ├── WindowsPowerPlansWindow.xaml
│ │ │ └── WindowsPowerPlansWindow.xaml.cs
│ │ └── Utils/
│ │ ├── DeviceInformationWindow.xaml
│ │ ├── DeviceInformationWindow.xaml.cs
│ │ ├── INotificationWindow.cs
│ │ ├── LanguageSelectorWindow.xaml
│ │ ├── LanguageSelectorWindow.xaml.cs
│ │ ├── NativeLayeredWindow.cs
│ │ ├── NotificationAoTWindow.cs
│ │ ├── NotificationWindow.cs
│ │ ├── StatusWindow.xaml
│ │ ├── StatusWindow.xaml.cs
│ │ ├── SymbolRegularPicker.xaml
│ │ ├── SymbolRegularPicker.xaml.cs
│ │ ├── UnsupportedWindow.xaml
│ │ ├── UnsupportedWindow.xaml.cs
│ │ ├── UpdateWindow.xaml
│ │ └── UpdateWindow.xaml.cs
│ └── app.manifest
├── LenovoLegionToolkit.sln
├── LenovoLegionToolkit.sln.DotSettings
├── README.md
├── README_ja-JP.md
├── README_zh-hans.md
├── clean.bat
├── crowdin.yml
├── make.bat
└── make_installer.iss
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
================================================
FILE: .github/FUNDING.yml
================================================
github: [BartoszCichecki]
custom: ["https://paypal.me/bartoszcichecki"]
================================================
FILE: .github/ISSUE_TEMPLATE/1_feature_request.yml
================================================
name: Feature Request
description: Suggest an idea for this project
labels: ["feature"]
body:
- type: markdown
attributes:
value: |
> [!IMPORTANT]
> Before you start, read [the rules](https://github.com/BartoszCichecki/LenovoLegionToolkit/blob/master/CONTRIBUTING.md) for contributing.
- type: input
id: version
attributes:
label: Version
description: Which Lenovo Legion Toolkit version do you use?
placeholder: e.g. 2.14.0
validations:
required: true
- type: input
id: os
attributes:
label: OS
description: Which operating system do you use?
placeholder: e.g. Windows 11 21H2 build 22000
validations:
required: true
- type: input
id: device
attributes:
label: Device
description: Which laptop do you use?
placeholder: e.g. Legion 5 Pro 16ACH6
validations:
required: true
- type: textarea
id: problem
attributes:
label: Is your feature request related to a problem?
description: A clear and concise description of what the problem is.
placeholder: A clear and concise description of what the problem is.
validations:
required: true
- type: textarea
id: solution
attributes:
label: How would you like the problem to be solved?
description: A clear and concise description of what you would like to happen.
placeholder: A clear and concise description of what you would like to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: What alternatives have you considered?
description: A clear and concise description of any alternative solutions or features you have considered.
placeholder: A clear and concise description of any alternative solutions or features you have considered.
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional information
description: If applicable, add screenshots or other relevant information to help explain your problem.
================================================
FILE: .github/ISSUE_TEMPLATE/2_bug_report.yml
================================================
name: Bug Report
description: Something isn't working correctly
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
> [!IMPORTANT]
> Before you start, read [the rules](https://github.com/BartoszCichecki/LenovoLegionToolkit/blob/master/CONTRIBUTING.md) for contributing.
- type: input
id: version
attributes:
label: Version
description: Which Lenovo Legion Toolkit version do you use?
placeholder: e.g. 2.14.0
validations:
required: true
- type: input
id: os
attributes:
label: OS
description: Which operating system do you use?
placeholder: e.g. Windows 11 21H2 build 22000
validations:
required: true
- type: input
id: device
attributes:
label: Device
description: Which laptop do you use?
placeholder: e.g. Legion 5 Pro 16ACH6
validations:
required: true
- type: input
id: bios
attributes:
label: BIOS version
description: Which BIOS version do you have?
placeholder: e.g. GKCN57WW
validations:
required: true
- type: textarea
id: troubleshoot
attributes:
label: What is wrong?
description: Provide detailed description of what is wrong or does not work as expected.
placeholder: Provide detailed description of what is wrong or does not work as expected.
validations:
required: true
- type: textarea
id: description
attributes:
label: What did you try already?
description: Provide detailed description of how did you troubleshoot the issue and what have you tried already.
placeholder: Provide detailed description of how did you troubleshoot the issue and what have you tried already.
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: How to reproduce the bug?
description: Describe how to reproduce the behavior. Be as specific as possible and provide as many details as possible.
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
- type: textarea
id: expected-behaviour
attributes:
label: What is the behavior that you expected?
description: Describe what did you expect would happen.
placeholder: Describe what did you expect would happen.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Logs
placeholder: Please drag and drop log files here. You can check README for instructions on how to collect logs.
description: Please drag and drop log files here. You can check README for instructions on how to collect logs.
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional information
description: If applicable, add screenshots or other relevant information to help explain your problem.
================================================
FILE: .github/ISSUE_TEMPLATE/3_compatibility_request.yml
================================================
name: Compatibility Request
description: Request support for a device that is not supported
labels: ["compatibility"]
body:
- type: markdown
attributes:
value: |
> [!IMPORTANT]
> Before you start, read [the rules](https://github.com/BartoszCichecki/LenovoLegionToolkit/blob/master/CONTRIBUTING.md) for contributing.
- type: input
id: version
attributes:
label: Version
description: Which Lenovo Legion Toolkit version do you use?
placeholder: e.g. 2.14.0
validations:
required: true
- type: input
id: os
attributes:
label: OS
description: Which operating system do you use?
placeholder: e.g. Windows 11 21H2 build 22000
validations:
required: true
- type: input
id: device
attributes:
label: Device
description: Which laptop do you use?
placeholder: e.g. Legion 5 Pro 16ACH6
validations:
required: true
- type: input
id: bios
attributes:
label: BIOS version
description: Which BIOS version do you have?
placeholder: e.g. GKCN57WW
validations:
required: true
- type: textarea
id: what-was-test
attributes:
label: Which features of the application did you test?
description: A clear and concise description of features that were tested.
placeholder: Type here...
validations:
required: true
- type: textarea
id: what-is-broken
attributes:
label: Which features of the application do not work as expected?
description: A clear and concise description of features that do not work as expected.
placeholder: Type here...
validations:
required: true
- type: textarea
id: logs
attributes:
label: Logs
description: If you encountered problems, please drag and drop log files here. You can check README for instructions on how to collect logs.
- type: textarea
id: additional
attributes:
label: Additional information
description: If applicable, add screenshots or other relevant information to help explain your problem.
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: General questions
url: https://github.com/BartoszCichecki/LenovoLegionToolkit/discussions/new?category=q-a
about: Please ask questions here.
================================================
FILE: .github/pull_request_template.md
================================================
================================================
FILE: .github/workflows/build.yml
================================================
name: Build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: windows-2022
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
- name: Restore
run: dotnet restore
- name: Build
run: .\make.bat
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: installer
path: build_installer\LenovoLegionToolkitSetup.exe
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
tags:
- "[0-9]*.[0-9]*.[0-9]*"
jobs:
build:
runs-on: windows-2022
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
- name: Restore
run: dotnet restore
- name: Build
run: .\make.bat ${{ github.ref_name }}
- name: Release
uses: softprops/action-gh-release@v0.1.13
with:
draft: true
files: build_installer/LenovoLegionToolkitSetup.exe
fail_on_unmatched_files: true
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: installer
path: build_installer/LenovoLegionToolkitSetup.exe
================================================
FILE: .gitignore
================================================
# Created by https://www.toptal.com/developers/gitignore/api/visualstudio,dotnetcore,csharp
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio,dotnetcore,csharp
### Csharp ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
build/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Nuget personal access tokens and Credentials
nuget.config
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
.idea/
*.sln.iml
### DotnetCore ###
# .NET Core build folders
bin/
obj/
# Common node modules locations
/node_modules
/wwwroot/node_modules
### VisualStudio ###
# User-specific files
# User-specific files (MonoDevelop/Xamarin Studio)
# Mono auto generated files
# Build results
# Visual Studio 2015/2017 cache/options directory
# Uncomment if you have tasks that create the project's static files in wwwroot
# Visual Studio 2017 auto generated files
# MSTest test Results
# NUnit
# Build Results of an ATL Project
# Benchmark Results
# .NET Core
# ASP.NET Scaffolding
# StyleCop
# Files built by Visual Studio
# Chutzpah Test files
# Visual C++ cache files
# Visual Studio profiler
# Visual Studio Trace Files
# TFS 2012 Local Workspace
# Guidance Automation Toolkit
# ReSharper is a .NET coding add-in
# TeamCity is a build add-in
# DotCover is a Code Coverage Tool
# AxoCover is a Code Coverage Tool
# Coverlet is a free, cross platform Code Coverage Tool
# Visual Studio code coverage results
# NCrunch
# MightyMoose
# Web workbench (sass)
# Installshield output folder
# DocProject is a documentation generator add-in
# Click-Once directory
# Publish Web Output
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
# NuGet Packages
# NuGet Symbol Packages
# The packages folder can be ignored because of Package Restore
# except build/, which is used as an MSBuild target.
# Uncomment if necessary however generally it will be regenerated when needed
# NuGet v3's project.json files produces more ignorable files
# Nuget personal access tokens and Credentials
# Microsoft Azure Build Output
# Microsoft Azure Emulator
# Windows Store app package directories and files
# Visual Studio cache files
# files ending in .cache can be ignored
# but keep track of directories ending in .cache
# Others
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
# RIA/Silverlight projects
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
# SQL Server files
# Business Intelligence projects
# Microsoft Fakes
# GhostDoc plugin setting file
# Node.js Tools for Visual Studio
# Visual Studio 6 build log
# Visual Studio 6 workspace options file
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
# Visual Studio LightSwitch build output
# Paket dependency manager
# FAKE - F# Make
# CodeRush personal settings
# Python Tools for Visual Studio (PTVS)
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
# Telerik's JustMock configuration file
# BizTalk build output
# OpenCover UI analysis results
# Azure Stream Analytics local run output
# MSBuild Binary and Structured Log
# NVidia Nsight GPU debugger configuration file
# MFractors (Xamarin productivity tool) working folder
# Local History for Visual Studio
# BeatPulse healthcheck temp database
# Backup folder for Package Reference Convert tool in Visual Studio 2017
# Ionide (cross platform F# VS Code tools) working folder
# Fody - auto-generated XML schema
# VS Code files for those working on multiple tools
# Local History for Visual Studio Code
# Windows Installer files from build outputs
# JetBrains Rider
### VisualStudio Patch ###
# Additional files built by Visual Studio
# End of https://www.toptal.com/developers/gitignore/api/visualstudio,dotnetcore,csharp
build_installer
================================================
FILE: CONTRIBUTING.md
================================================
## Welcome to Lenvo Legion Toolkit contributing guide!
### Other language versions of this contributing guide:
* [简体中文版开发者指南](CONTRIBUTING_zh-hans.md)
* [日本語版の貢献ガイド](CONTRIBUTING_ja-JP.md)
Thanks for investing your time in contributing to this project! Giving the growing popularity of LLT, here are a few rules to follow to ensure that your contribution goes smoothly.
_Due to large number of issues created, those that do not meet the criteria will be deleted without warning. Repeating offenders will be banned._
**1. Before reporting an issue make yourself familiar with the README**
[README](https://github.com/BartoszCichecki/LenovoLegionToolkit/blob/master/README.md) is regularly updated to include answers to frequently asked questions as well as information about most common issues. Take your time to go through what is there before creating an issue or starting a discussion.
**2. Check already reported issues**
Go through [issues](https://github.com/BartoszCichecki/LenovoLegionToolkit/issues?q=is%3Aissue) that were already reported, as well as [discussions](https://github.com/BartoszCichecki/LenovoLegionToolkit/discussions?discussions_q=). Do not create duplicate issues or discussions. Even if the issue is marked as closed, you can still leave a comment there.
**3. Use English**
This makes it easier for everyone to follow the conversation.
**4. Respect scope of the project**
This is not meant to be a do-it-all type of application. The vision for the project is clear: provide a replacement of Vantage for Legion laptops. Do not request support for other types/models/etc devices.
**5. Verify your problem before creating an issue**
Make sure that a bug is really a bug in LLT - this isn't a free system troubleshooting forum. If you use modified version of Windows or your Windows is acting funny, that's on you.
**6. Describe your problem as best as you can**
Providing good description is key. Fill out all the fields of the form when creating an issue, including logs. The better the description, the higher the chance that we will understand each other correctly.
**7. Give a good title to issues and discussions**
It is a lot easier to browse the list and follow issues and discussions. "Error when using LLT" is not a good title.
**8. Stay on topic**
Do not leave unnecessary comments or spam.
**9. One problem per issue**
Do not report many problems or request many features withing one issue. Make one issue or discussion per problem/topic/idea. This makes it easier to follow.
**10. Translations**
Translation contributions are done using [Crowdin](https://crowdin.com/project/llt), so please request access to the project there if you want to contribute.
**11. Pull requests**
Pull requests are welcome (of course). Unless you create a very simple and understandable PR, make an issue first and describe the problem you are solving. It doesn't make sense to spend time working on an idea that will be rejected, because it doesn't fit the project vision. Follow the code style and architecture of the project.
Once again, thanks for investing your time in helping LLT get better!
================================================
FILE: CONTRIBUTING_ja-JP.md
================================================
## Lenovo Legion Toolkit への貢献ガイドへようこそ!
### この貢献ガイドの他の言語バージョン:
* [英語版の貢献ガイド](CONTRIBUTING.md)
* [簡体字中国語版の貢献ガイド](CONTRIBUTING_zh-hans.md)
このプロジェクトに貢献するために時間を割いていただきありがとうございます! LLTの人気が高まっているため、貢献がスムーズに進むようにするために、いくつかのルールに従ってください。
_作成された問題の数が多いため、基準を満たさないものは警告なしに削除されます。繰り返し違反する者は禁止されます。_
**1. 問題を報告する前にREADMEをよく読んでください**
[README](https://github.com/BartoszCichecki/LenovoLegionToolkit/blob/master/README.md)は、よくある質問への回答や最も一般的な問題に関する情報を���むように定期的に更新されます。問題を作成する前に、そこにある内容を確認してください。
**2. 既に報告されている問題を確認してください**
既に報告されている[問題](https://github.com/BartoszCichecki/LenovoLegionToolkit/issues?q=is%3Aissue)や[ディスカッション](https://github.com/BartoszCichecki/LenovoLegionToolkit/discussions?discussions_q=)を確認してください。重複する問題やディスカッションを作成しないでください。問題がクローズされていても、コメントを残すことができます。
**3. 英語を使用してください**
これにより、すべての人が会話を追跡しやすくなります。
**4. プロジェクトの範囲を尊重してください**
これは万能のアプリケーションを目指しているわけではありません。プロジェクトのビジョンは明確です:LegionノートパソコンのためのVantageの代替品を提供すること。他のタイプ/モデル/デバイスのサポートを要求しないでください。
**5. 問題を作成する前に問題を確認してください**
バグが本当にLLTのバグであることを確認してください - これは無料のシステムトラブルシューティングフォーラムではありません。Windowsの改造版を使用している場合や、Windowsが正常に動作していない場合、それはあなたの責任です。
**6. 問題をできるだけ詳しく説明してください**
良い説明を提供することが重要です。問題を作成する際には、フォームのすべてのフィールドを記入し、ログを含めてください。説明が良ければ良いほど、私たちが正しく理解する可能性が高くなります。
**7. 問題やディスカッションに良いタイトルを付けてください**
リストを閲覧し、問題やディスカッションを追跡するのがはるかに簡単です。「LLTを使用中にエラーが発生しました」は良いタイトルではありません。
**8. トピックに集中してください**
不要なコメントやスパムを残さないでください。
**9. 1つの問題につき1つの問題**
1つの問題で多くの問題を報告したり、多くの機能を要求したりしないでください。問題/トピック/アイデアごとに1つの問題やディスカッションを作成してください。これにより、追跡が容易になります。
**10. 翻訳**
翻訳の貢献は[Crowdin](https://crowdin.com/project/llt)を使用して行われるため、貢献したい場合はそこでプロジェクトへのアクセスをリクエストしてください。
**11. プルリクエスト**
プルリクエストは歓迎されます(もちろんです)。非常にシンプルで理解しやすいPRを作成しない限り、最初に問題を作成し、解決している問題を説明してください。プロジェクトのビジョンに合わないアイデアに時間を費やすのは意味がありません。プロジェクトのコードスタイルとアーキテクチャに従ってください。
もう一度、LLTをより良くするために時間を割いていただきありがとうございます!
================================================
FILE: CONTRIBUTING_zh-hans.md
================================================
## 欢迎来到拯救者工具箱开发者指南
首先感谢你花时间为此项目做出贡献!随着拯救者工具箱的热度越来越高,为了确保你的贡献能够被迅速采纳,你应该遵守一定的格式和规则。
_由于 Issues 总量的增加,不符合标准的 Issue 会在无预先警告的情况下被关闭或删除。屡次违反者将被本项目封禁。_
**1. 在报告 Issue 前请仔细阅读 README**
绝大多数常见问题的解决方法和重要信息都已在 [README](https://github.com/BartoszCichecki/LenovoLegionToolkit/blob/master/README_zh-hans.md) 内阐明。请务必在报告 Issue 或发起讨论前通读其中的内容。
**2. 检查已被报告的 Issues**
请检查项目仓库下的 [Issues](https://github.com/BartoszCichecki/LenovoLegionToolkit/issues?q=is%3Aissue) 和 [Discussions](https://github.com/BartoszCichecki/LenovoLegionToolkit/discussions?discussions_q=) 栏目。请不要报告重复的 Issue 或发起重复的讨论。即使你找到的 Issue 已经被关闭,你一样可以在那里留言。
**3. 使用英语**
这会让所有人之间的交流都更加便利。
译者提示:若你无法流畅地使用英语表达,你可以在使用中文完成草稿后使用百度翻译或 [DeepL](https://www.deepl.com/zh/translator) 等翻译网站或软件将草稿翻译为英语后提交。
**4. 尊重项目目标**
这不是一个万能的应用。项目的愿景很明确:为拯救者笔记本提供一个 Legion Zone(海外版则为 Vantage)的替代品。请勿要求支持其它类型或型号的设备。
**5. 在新建 Issue 前审查你的问题**
请确保 Bug 确实是 LLT 的 Bug。这不是一个免费的系统故障排除论坛,如果你在使用被修改过的 Windows 版本或你的系统本身已经出现问题,请自行解决。
**6. 尽所能详细描述你的问题**
详细的描述是解决问题的关键所在。请在新建 Issue 时填写表单内的所有项目并提供日志文件。只有提供良好的描述我们才能更快地解决问题。
**7. 为你的 Issue 或条论起一个好的标题**
这样可以极大方便浏览 Issue 和讨论列表。“使用 LLT 时出现问题”并不是一个好的标题。
**8. 围绕主题**
不要发表与主题无关或无意义的留言。
**9. 一个 Issue 一个问题**
请不要在一个 Issue 内同时报告多个问题或请求添加多个功能。请为每一个问题、主题或想法新建一个单独的 Issue 或讨论,这会让后期跟进更加容易。
**10. 翻译**
我们使用 [Crowdin](https://crowdin.com/project/llt) 作为软件翻译平台。如果你想为翻译做出贡献,请在那里申请访问项目的权限。
**11. Pull requests**
我们欢迎你提交 PR(当然了)。除非你提交了一个非常简单易懂的 PR,请先创建一个 Issue 并描述你正在解决的问题。为一个会被拒绝的点子花时间并没有什么意义,因为这不符合本项目的愿景。同时请遵循现有的代码风格和项目组织。
再次感谢你花时间帮助 LLT 变得更好!
================================================
FILE: InnoDependencies/Arabic.isl
================================================
; *** Inno Setup version 6.1.0+ arabic messages ***
;
; Translated by nacer baaziz (nacerstile@gmail.com)
; http://www.jrsoftware.org/files/istrans/
;
; Note: When translating this text, do not add periods (.) to the end of
; messages that didn't have them already, because on those messages Inno
; Setup adds the periods automatically (appending a period would result in
; two periods being displayed).
[LangOptions]
; The following three entries are very important. Be sure to read and
; understand the '[LangOptions] section' topic in the help file.
LanguageName=arabic
LanguageID=$0401
LanguageCodePage=0
RightToLeft=yes
; If the language you are translating to requires special font faces or
; sizes, uncomment any of the following entries and change them accordingly.
;DialogFontName=
;DialogFontSize=8
;WelcomeFontName=Verdana
;WelcomeFontSize=12
;TitleFontName=Arial
;TitleFontSize=29
;CopyrightFontName=Arial
;CopyrightFontSize=8
[Messages]
; *** Application titles
SetupAppTitle=إعداد
SetupWindowTitle=إعداد - %1
UninstallAppTitle=إزالة التثبيت
UninstallAppFullTitle=إزالة تثبيت %1
; *** Misc. common
InformationTitle=معلومات
ConfirmTitle=تأكيد
ErrorTitle=خطأ
; *** SetupLdr messages
SetupLdrStartupMessage=هذا المعالج سيقوم بتثبيت %1. هل تريد المتابعة?
LdrCannotCreateTemp=تعذر إنشاء الملفات المؤقتة, تم فشل معالج التثبيت.
LdrCannotExecTemp=تعذر تشغيل الملفات من المجلد المؤقت. فشل معالج التثبيت.
HelpTextNote=
; *** Startup error messages
LastErrorMessage=%1.%n%n خطأ %2: %3
SetupFileMissing=الملف %1 مفقود من دليل التثبيت. الرجاء تصحيح المشكلة أو الحصول على نسخة جديدة من البرنامج.
SetupFileCorrupt=ملفات الإعداد تالفة. الرجاء الحصول على نسخة جديدة من البرنامج.
SetupFileCorruptOrWrongVer=ملفات الإعداد تالفة أو غير متوافقة مع هذا الإصدار من برنامج الإعداد. الرجاء تصحيح المشكلة أو الحصول على نسخة جديدة من البرنامج.
InvalidParameter=تم تمرير أوامر غير صالحة على سطر الأوامر : %n%n%1
SetupAlreadyRunning=برنامج الإعداد قيد التشغيل بالفعل.
WindowsVersionNotSupported=لا يدعم هذا البرنامج إصدار Windows الذي يعمل به الكمبيوتر.
WindowsServicePackRequired=هذا البرنامج يتطلب %1 حزمة الخدمة %2 أو أعلى.
NotOnThisPlatform=لن يتم تشغيل هذا البرنامج على %1.
OnlyOnThisPlatform=يجب تشغيل هذا البرنامج على %1.
OnlyOnTheseArchitectures=يمكن تثبيت هذا البرنامج فقط على إصدارات Windows المصممة لهندسة المعالج التالية : %n%n%1
WinVersionTooLowError=هذا البرنامج يتطلب %1 الإصدار %2 أو أعلى.
WinVersionTooHighError=لا يمكن تثبيت هذا البرنامج على %1 الإصدار %2 أو أعلى.
AdminPrivilegesRequired=يجب أن يتم تسجيل دخولك كمسؤول عند تثبيت هذا البرنامج.
PowerUserPrivilegesRequired=يجب أن يتم تسجيل دخولك كمسؤول أو كعضو في مجموعة Power Users عند تثبيت هذا البرنامج.
SetupAppRunningError=لقد كشف معالج الإعداد أن %1 يعمل بالفعل. %n%n يرجى إغلاق كل أجزائه الآن , ثم إضغط حسنا للمتابعة أو إلغاء الأمر للخروج.
UninstallAppRunningError=كشف معالج إلغاء التثبيت بأن %1 يعمل بالفعل.%n%n يرجى إغلاق كل أجزائه الآن , ثم إضغط حسنا للمتابعة أو إلغاء الأمر للخروج.
; *** Startup questions
PrivilegesRequiredOverrideTitle=تحديد وضع تثبيت الإعداد
PrivilegesRequiredOverrideInstruction=تحديد وضع التثبيت
PrivilegesRequiredOverrideText1=يمكن ل %1 أن يُثَبَّت على جميع المستخدمين (يتطلب إمتيازات المسؤول), أو لك فقط..
PrivilegesRequiredOverrideText2=.يمكن ل %1 أن يُثَبَّت لك فقط, أو أن يُثَبَّت على جميع المستخدمين (يتطلب إمتيازات المسؤول).
PrivilegesRequiredOverrideAllUsers=التثبيت ل&كافة المستخدمين
PrivilegesRequiredOverrideAllUsersRecommended=تثبيت ل&كافة المستخدمين (مستحسن)
PrivilegesRequiredOverrideCurrentUser=تثبيت لي &فقط
PrivilegesRequiredOverrideCurrentUserRecommended=تثبيت بالنسبة لي &فقط (مستحسن)
; *** Misc. errors
ErrorCreatingDir=تعذر على برنامج الإعداد إنشاء الدليل "%1"
ErrorTooManyFilesInDir=تعذر إنشاء ملف في الدليل "%1" لأنه يحتوي على ملفات كثيرة جداً
; *** Setup common messages
ExitSetupTitle=الخروج من معالج التثبيت
ExitSetupMessage=لم يكتمل الإعداد. إذا قمت بالخروج الآن، لن يتم تثبيت البرنامج.%n%nYou يمكنك تشغيل برنامج الإعداد مرة أخرى في وقت آخر لإكمال التثبيت.%n%n إنهاء الإعداد؟
AboutSetupMenuItem=&حول الإعداد...
AboutSetupTitle=حول برنامج الإعداد
AboutSetupMessage=%1 الإصدار %2%n%3%n%n%1 صفحة الأنترنت:%n%4
AboutSetupNote=
TranslatorNote=تم ترجمة المعالج إلى اللغة العربية بواسطة ناصر بعزيز
; *** Buttons
ButtonBack=< ال&سابق
ButtonNext=ال&تالي >
ButtonInstall=&تثبيت
ButtonOK=&حسنا
ButtonCancel=إل&غاء الأمر
ButtonYes=&نعم
ButtonYesToAll=نعم لل&كل
ButtonNo=&لا
ButtonNoToAll=لا &للكل
ButtonFinish=إ&نهاء
ButtonBrowse=اس&تعراض...
ButtonWizardBrowse=اس&تعراض...
ButtonNewFolder=إن&شاء مجلد جديد
; *** "Select Language" dialog messages
SelectLanguageTitle=إختر لغة معالج الإعداد
SelectLanguageLabel=حدد اللغة التي يجب استخدامها أثناء التثبيت.
; *** Common wizard text
ClickNext=انقر فوق التالي للمتابعة، أو إلغاء الأمر لإنهاء الإعداد.
BeveledLabel=
BrowseDialogTitle=تصفح لاختيار مجلد
BrowseDialogLabel=حدد مجلدًا في القائمة أدناه، ثم انقر فوق حسنا.
NewFolderName=مجلد جديد
; *** "Welcome" wizard page
WelcomeLabel1=مرحبا بكم في معالج تثبيت [name]
WelcomeLabel2=هذا المعالج سيقوم بتثبيت [name/ver] على جهازك. %n%nمن المستحسن أن تقوم بإغلاق كافة التطبيقات الأخرى قبل المتابعة.
; *** "Password" wizard page
WizardPassword=كلمة السر
PasswordLabel1=هذا التثبيت محمي بكلمة سر.
PasswordLabel3=الرجاء تقديم كلمة المرور، ثم انقر فوق التالي للمتابعة. كلمات المرور حساسة لحالة الأحرف.
PasswordEditLabel=&كلمة السر:
IncorrectPassword=كلمة السر التي أدخلتها غير صحيحة. يرجى إعادة المحاولة.
; *** "License Agreement" wizard page
WizardLicense=اتفاقية الترخيص
LicenseLabel=يرجى قراءة المعلومات الهامة التالية قبل المتابعة.
LicenseLabel3=الرجاء قراءة اتفاقية الترخيص التالية. يجب قبول شروط هذه الاتفاقية قبل متابعة التثبيت.
LicenseAccepted=أنا أواف&ق على هذه الإتفاقية
LicenseNotAccepted=أنا &لا أوافق على الإتفاقية
; *** "Information" wizard pages
WizardInfoBefore=معلومات
InfoBeforeLabel=يرجى قراءة المعلومات الهامة التالية قبل المتابعة.
InfoBeforeClickLabel=عندما تكون جاهزًا للمتابعة مع الإعداد، انقر فوق التالي.
WizardInfoAfter=معلومات
InfoAfterLabel=يرجى قراءة المعلومات الهامة التالية قبل المتابعة.
InfoAfterClickLabel=عندما تكون جاهزًا للمتابعة مع الإعداد، انقر فوق التالي.
; *** "User Information" wizard page
WizardUserInfo=معلومات المستخدم
UserInfoDesc=يرجى إدخال معلوماتك.
UserInfoName=إسم ال&مستخدم :
UserInfoOrg=المن&ظمة:
UserInfoSerial=&الرقم التسلسلي:
UserInfoNameRequired=يجب إدخال إسم.
; *** "Select Destination Location" wizard page
WizardSelectDir=تحديد موقع الوِجْهة
SelectDirDesc=أين يجب تثبيت [name]؟
SelectDirLabel3=سيقوم معالج التثبيت بتثبيت [name] في المجلد التالي.
SelectDirBrowseLabel=للمتابعة، انقر فوق التالي. إذا كنت ترغب في تحديد مجلد آخر، انقر فوق استعراض.
DiskSpaceGBLabel=تحتاج على الأقل [gb] GB من المساحة لتثبيت البرنامج.
DiskSpaceMBLabel=تحتاج على الأقل [mb] MB من المساحة لتثبيت البرنامج.
CannotInstallToNetworkDrive=يتعذر على برنامج الإعداد التثبيت على محرك أقراص شبكة اتصال.
CannotInstallToUNCPath=يتعذر على برنامج الإعداد تثبيت مسار UNC.
InvalidPath=يجب إدخال مسار كامل مع حرف محرك الأقراص; على سبيل المثال: %n%nC:\APP%n%أو مسار UNC في النموذج:%n%n\\server\share
InvalidDrive=محرك الأقراص أو مشاركة UNC التي حددتها غير موجود أو غير قابل للوصول. الرجاء تحديد آخر.
DiskSpaceWarningTitle=مساحة القرص غير كافية
DiskSpaceWarning=Sيتطلب الإعداد على الأقل %1 KB من المساحة الفارغة للتثبيت، ولكن محرك الأقراص المحدد فيه فقط %2 KB متوفرة.%n%nهل تريد المتابعة على أية حال؟
DirNameTooLong=اسم المجلد أو المسار طويل جداً.
InvalidDirName=اسم المجلد غير صالح.
BadDirName32=لا يمكن لأسماء المجلدات تضمين أي من الأحرف التالية:%n%n%1
DirExistsTitle=المجلد موجود بالفعل
DirExists=المجلد:%n%n%1%n%n موجود بالفعل. هل ترغب في التثبيت على هذا المجلد على أي حال؟
DirDoesntExistTitle=المجلد غير موجود
DirDoesntExist=المجلد:%n%n%1%n%nغير موجود. هل تريد إنشاء المجلد؟
; *** "Select Components" wizard page
WizardSelectComponents=تحديد المكونات
SelectComponentsDesc=ما هي المكونات التي يجب تثبيتها؟
SelectComponentsLabel2=حدد المكونات التي تريد تثبيتها ؛ امسح المكونات التي لا تريد تثبيتها. انقر فوق "التالي" عندما تكون مستعدًا للمتابعة.
FullInstallation=تثبيت كامل
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
CompactInstallation=تثبيت مدمج
CustomInstallation=تثبيت مخصص
NoUninstallWarningTitle=مكونات موجودة
NoUninstallWarning=اكتشف برنامج الإعداد أن المكونات التالية مثبتة بالفعل على جهاز الكمبيوتر الخاص بك: %n%n%1%n%nلن يؤدي إلغاء تحديد هذه المكونات إلى إزالة تثبيتها.%n%nهل ترغب في الاستمرار على أي حال?
ComponentSize1=%1 KB
ComponentSize2=%1 MB
ComponentsDiskSpaceGBLabel=الاختيار الحالي يتطلب على الأقل [gb] GB من مساحة القرص.
ComponentsDiskSpaceMBLabel=الاختيار الحالي يتطلب على الأقل [mb] MB من مساحة القرص.
; *** "Select Additional Tasks" wizard page
WizardSelectTasks=حدد المهام الإضافية
SelectTasksDesc=ما المهام الإضافية التي ينبغي تنفيذها؟
SelectTasksLabel2=حدد المهام الإضافية التي ترغب في أن يقوم الإعداد بتنفيذها أثناء تثبيت [name], ثم إضغط التالي.
; *** "Select Start Menu Folder" wizard page
WizardSelectProgramGroup=حدد مجلد قائمة ابدأ
SelectStartMenuFolderDesc=أين يجب أن يضع الإعداد اختصارات البرنامج؟
SelectStartMenuFolderLabel3=سيقوم برنامج الإعداد بإنشاء اختصارات البرنامج في مجلد قائمة ابدأ التالية.
SelectStartMenuFolderBrowseLabel=للمتابعة، انقر فوق التالي. إذا كنت ترغب في تحديد مجلد آخر، انقر فوق استعراض.
MustEnterGroupName=يجب إدخال اسم مجلد.
GroupNameTooLong=اسم المجلد أو المسار طويل جداً.
InvalidGroupName=اسم المجلد غير صالح.
BadGroupName=لا يمكن أن يتضمن اسم المجلد أي من الأحرف التالية:%n%n%1
NoProgramGroupCheck2=&عدم إنشاء مجلد قائمة ابدأ
; *** "Ready to Install" wizard page
WizardReady=جاهز للتثبيت
ReadyLabel1=الإعداد جاهز الآن لبدء تثبيت [name] على جهازك.
ReadyLabel2a=انقر فوق تثبيت لمتابعة التثبيت، أو انقر فوق "السابق" إذا كنت ترغب في مراجعة أو تغيير أية إعدادات.
ReadyLabel2b=انقر فوق تثبيت لمتابعة التثبيت.
ReadyMemoUserInfo=معلومات المستخدم:
ReadyMemoDir=مسار الوِجْهة:
ReadyMemoType=نوع الإعداد:
ReadyMemoComponents=المكونات المحددة:
ReadyMemoGroup=مجلد قائمة ابدأ:
ReadyMemoTasks=مهام إضافية:
; *** TDownloadWizardPage wizard page and DownloadTemporaryFile
DownloadingLabel=تحميل الملفات الإضافية...
ButtonStopDownload=إي&قاف التحميل
StopDownload=هل أنت متأكد من أنك ترغب في إيقاف التحميل؟
ErrorDownloadAborted=تم إلغاء التحميل
ErrorDownloadFailed=فشل التحميل: %1 %2
ErrorDownloadSizeFailed=خطأ في قراءة الحجم: %1 %2
ErrorFileHash1=خطأ في قراءة الهاش الخاص بالملف: %1
ErrorFileHash2=خطأ في هاش الملف: كان من المتوقع أن يكن : %1, بينما تم إيجاد : %2
ErrorProgress=خطأ في الحصول على نسبة التقدم: %1 من %2
ErrorFileSize=خطأ في حجم الملف: المتوقع هو : %1, الحجم الذي وجدناه هو : %2
; *** "Preparing to Install" wizard page
WizardPreparing=التحضير للتثبيت
PreparingDesc=الإعداد يستعد لتثبيت [name] على جهازك.
PreviousInstallNotCompleted=لم يكتمل التثبيت / إزالة البرنامج السابق. ستحتاج إلى إعادة تشغيل الكمبيوتر لإكمال هذا التثبيت.%n%nبعد إعادة تشغيل جهاز الكمبيوتر الخاص بك ، شغّل برنامج الإعداد مرة أخرى لإكمال تثبيت [name].
CannotContinue=لا يمكن لبرنامج الإعداد المتابعة. يرجى النقر فوق "إلغاء" للخروج.
ApplicationsFound=تستخدم التطبيقات التالية الملفات التي تحتاج إلى تحديث بواسطة برنامج الإعداد. يوصى بالسماح لبرنامج الإعداد بإغلاق هذه التطبيقات تلقائيًا.
ApplicationsFound2=تستخدم التطبيقات التالية الملفات التي تحتاج إلى تحديث بواسطة برنامج الإعداد. يوصى بالسماح لبرنامج الإعداد بإغلاق هذه التطبيقات تلقائيًا. بعد اكتمال التثبيت ، سيحاول برنامج الإعداد إعادة تشغيل التطبيقات.
CloseApplications=أغلق التطبيقات &تلقائيًا
DontCloseApplications=&لا تغلق التطبيقات
ErrorCloseApplications=لم يتمكن الإعداد من إغلاق جميع التطبيقات تلقائيًا. يوصى بإغلاق جميع التطبيقات التي تستخدم الملفات التي تحتاج إلى تحديث بواسطة برنامج الإعداد قبل المتابعة.
PrepareToInstallNeedsRestart=برنامج الإعداد يجب أن يقوم بإعادة تشغيل الجهاز. بعد إعادة تشغيل جهازك, قم بتشغيل برنامج الإعداد مرة أخرى لإكمال تثبيت [name].%n%nهل تحب إعادة التشغيل الآن?
; *** "Installing" wizard page
WizardInstalling=جاري التثبيت
InstallingLabel=يرجى الانتظار حتى يقوم برنامج الإعداد بتثبي [name] على جهازك.
; *** "Setup Completed" wizard page
FinishedHeadingLabel=إنهاء معالج تثبيت [name]
FinishedLabelNoIcons=إكتمل معالج التثبيت من تثبيت [name] على جهازك.
FinishedLabel=اكتمل معالج التثبيت من تثبيت [name] على جهازك. قد يتم تشغيل التطبيق عن طريق تحديد الاختصارات المثبتة.
ClickFinish=إضغط إنهاء للخروج من معالج التثبيت
FinishedRestartLabel=لاستكمال تثبيت [name], يجب على برنامج الإعداد إعادة تشغيل جهاز الكمبيوتر الخاص بك. هل ترغب في إعادة التشغيل الآن؟
FinishedRestartMessage=لاستكمال تثبيت [name], يجب على برنامج الإعداد إعادة تشغيل جهاز الكمبيوتر الخاص بك.%n%nهل ترغب في إعادة التشغيل الآن؟
ShowReadmeCheck=نعم ، أرغب عرض ملف README
YesRadio=&نعم أعد تشغيل الكومبيوتر الان
NoRadio=&لا ، سأعيد تشغيل الكمبيوتر لاحقًا
; used for example as 'Run MyProg.exe'
RunEntryExec=تشغيل %1
; used for example as 'View Readme.txt'
RunEntryShellExec=عرض %1
; *** "Setup Needs the Next Disk" stuff
ChangeDiskTitle=يحتاج برنامج الإعداد إلى القرص التالي
SelectDiskLabel2=الرجاء إدراج القرص %1 وانقر فوق حسنا.%n%nإذا كان يمكن العثور على الملفات الموجودة على هذا القرص في مجلد غير الذي يظهر أدناه، أدخل المسار الصحيح أو انقر فوق استعراض.
PathLabel=&مسار :
FileNotInDir2=لم نتمكن من العثور على الملف "%1" في "%2". الرجاء إدراج القرص الصحيح أو تحديد مجلد آخر.
SelectDirectoryLabel=الرجاء تحديد موقع القرص التالي.
; *** Installation phase messages
SetupAborted=لم يتم إكمال الإعداد. %n%nالرجاء تصحيح المشكلة وتشغيل الإعداد مرة أخرى.
AbortRetryIgnoreSelectAction=حدد إجراء
AbortRetryIgnoreRetry=أ&عد مجددا
AbortRetryIgnoreIgnore=&تجاهل الخطأ والمتابعة
AbortRetryIgnoreCancel=إلغاء التثبيت
; *** Installation status messages
StatusClosingApplications=إغلاق التطبيقات...
StatusCreateDirs=إنشاء المجلدات...
StatusExtractFiles=استخراج الملفات...
StatusCreateIcons=إنشاء الإختصارات...
StatusCreateIniEntries=إنشاء مدخلات INI...
StatusCreateRegistryEntries=إنشاء مفاتيح السجل...
StatusRegisterFiles=تسجيل الملفات...
StatusSavingUninstall=تسجيل معلومات إزالة التثبيت...
StatusRunProgram=الإنتهاء من التثبيت...
StatusRestartingApplications=إعادة تشغيل التطبيقات...
StatusRollback=التراجع عن التغييرات...
; *** Misc. errors
ErrorInternal2=خطأ داخلي: %1
ErrorFunctionFailedNoCode=فشل %1
ErrorFunctionFailed=فشل %1; رقم الخطء %2
ErrorFunctionFailedWithMessage=فشل %1; رقم الخطء %2.%n%3
ErrorExecutingProgram=الإعداد غير قابل على تشغيل الملف:%n%1
; *** Registry errors
ErrorRegOpenKey=خطأ في فتح مفتاح التسجيل:%n%1\%2
ErrorRegCreateKey=خطأ في إنشاء مفتاح التسجيل:%n%1\%2
ErrorRegWriteKey=خطأ في الكتابة على مفتاح التسجيل:%n%1\%2
; *** INI errors
ErrorIniEntry=حدث خطأ في إنشاء إدخال INI في الملف "%1".
; *** File copying errors
FileAbortRetryIgnoreSkipNotRecommended=&تخطي هذا الملف (غير مستحسن)
FileAbortRetryIgnoreIgnoreNotRecommended=&تجاهل الخطأ والمتابعة (غير مستحسن)
SourceIsCorrupted=الملف المصدر تالف
SourceDoesntExist=الملف "%1"غير موجود
ExistingFileReadOnly2=تعذر استبدال الملف الموجود لأنه تم وضع علامة للقراءة فقط.
ExistingFileReadOnlyRetry=&أزل القراءة فقط عن الملفات ثم حاول مرة أخرى
ExistingFileReadOnlyKeepExisting=&إحتفظ بالملفات الموجودة
ErrorReadingExistingDest=حدث خطأ أثناء محاولة قراءة الملف الموجود:
FileExistsSelectAction=اختر إجراء
FileExists2=الملف موجود بالفعل.
FileExistsOverwriteExisting=&استبدال الملف الموجود
FileExistsKeepExisting=ا&بقاء الملف الموجود
FileExistsOverwriteOrKeepAll=ا&فعل هذا للنزاعات القادمة
ExistingFileNewerSelectAction=اختر إجراء
ExistingFileNewer2=الملف الموجود أحدث من الملف الذي سيقوم معالج الإعداد بتثبيته.
ExistingFileNewerOverwriteExisting=&&استبدال الملف الموجود
ExistingFileNewerKeepExisting=ال&ابقاء على الملف الموجود (مستحسن)
ExistingFileNewerOverwriteOrKeepAll=ا&فعل هذا مع النزاعات القادمة
ErrorChangingAttr=حدث خطأ أثناء محاولة تغيير سمات الملف الموجود:
ErrorCreatingTemp=حدث خطأ أثناء محاولة إنشاء ملف في الدليل الوجهة:
ErrorReadingSource=حدث خطأ أثناء محاولة قراءة ملف مصدر:
ErrorCopying=حدث خطأ أثناء محاولة نسخ ملف:
ErrorReplacingExistingFile=حدث خطأ أثناء محاولة استبدال الملف الموجود:
ErrorRestartReplace=فشل إعادة تشغيل "استبدال":
ErrorRenamingTemp=حدث خطأ أثناء محاولة إعادة تسمية ملف في الدليل الوجهة:
ErrorRegisterServer=تعذر تسجيل ملفات DLL/OCX: %1
ErrorRegSvr32Failed=فشل RegSvr32 مع رمز الخروج %1
ErrorRegisterTypeLib=الإعداد غير قادر على تسجيل مكتبة النوع: %1
; *** Uninstall display name markings
; used for example as 'My Program (32-bit)'
UninstallDisplayNameMark=%1 (%2)
; used for example as 'My Program (32-bit, All users)'
UninstallDisplayNameMarks=%1 (%2, %3)
UninstallDisplayNameMark32Bit=32-bit
UninstallDisplayNameMark64Bit=64-bit
UninstallDisplayNameMarkAllUsers=كافة المستخدمين
UninstallDisplayNameMarkCurrentUser=المستخدم الحالي
; *** Post-installation errors
ErrorOpeningReadme=حدث خطأ أثناء محاولة فتح ملف إقرأني.
ErrorRestartingComputer=لم يتمكن برنامج الإعداد من إعادة تشغيل الكمبيوتر. الرجاء القيام بذلك يدوياً.
; *** Uninstaller messages
UninstallNotFound=الملف "%1" غير موجود. لا يمكن إزالة التثبيت.
UninstallOpenError=تعذر فتح "%1". لا يمكن إزالة التثبيت.
UninstallUnsupportedVer=ملف سجل الإزالة "%1" في تنسيق غير معروف من قبل هذا الإصدار من برنامج إلغاء التثبيت. لا يمكن إزالة التثبيت
UninstallUnknownEntry=إدخال غير معروف (%1) تمت مصادفة في سجل إلغاء التثبيت
ConfirmUninstall=هل أنت متأكد من أنك تريد إزالة %1 تماما, وجميع مكوناته?
UninstallOnlyOnWin64=يمكن إلغاء تثبيت هذا التثبيت على Windows 64-بت فقط.
OnlyAdminCanUninstall=يمكن إلغاء تثبيت هذا التثبيت فقط من قبل مستخدم له امتيازات إدارية.
UninstallStatusLabel=يرجى الإنتظار ريت ما يتم إزالة تثبيت %1 من جهازك.
UninstalledAll=تم إزالة %1 تماما من جهازك بنجاح.
UninstalledMost=اكتمل إزالة %1.%n%nتعذر إزالة بعض العناصر. يمكن إزالة هذه يدوياً.
UninstalledAndNeedsRestart=لإكمال إلغاء تثبيت %1, يجب إعادة تشغيل الكمبيوتر.%n%nهل تريد إعادة تشغيل الآن؟
UninstallDataCorrupted=الملف "%1" تالف. لا يمكن إزالة التثبيت
; *** Uninstallation phase messages
ConfirmDeleteSharedFileTitle=إزالة ملف مشترك؟
ConfirmDeleteSharedFile2=يشير النظام إلى أن الملف المشترك التالي لم يعد في الاستخدام من قبل أي برامج. هل ترغب في أن يقوم إلغاء التثبيت بإزالة هذا الملف المشترك?%n%nإذا كانت أية برامج لا تزال تستخدم هذا الملف وتتم إزالته، قد لا تعمل هذه البرامج بشكل صحيح. إذا كنت غير متأكد، اختر لا. ترك الملف على النظام الخاص بك لن يسبب أي ضرر.
SharedFileNameLabel=اسم الملف:
SharedFileLocationLabel=الموقع :
WizardUninstalling=حالة إزالة التثبيت
StatusUninstalling=جاري إزالة تثبيت %1...
; *** Shutdown block reasons
ShutdownBlockReasonInstallingApp=جاري تثبيت %1.
ShutdownBlockReasonUninstallingApp=جاري تثبيت %1.
; The custom messages below aren't used by Setup itself, but if you make
; use of them in your scripts, you'll want to translate them.
[CustomMessages]
NameAndVersion=%1 الإصدار %2
AdditionalIcons=اختصارات إضافية:
CreateDesktopIcon=إنشاء اختصار في &سطح المكتب
CreateQuickLaunchIcon=إنشاء اختصار "الت&شغيل السريع"
ProgramOnTheWeb=%1 على الأنترنت
UninstallProgram=إزالة تثبيت %1
LaunchProgram=تشغيل %1
AssocFileExtension=اربط %1 مع صيغة ملف %2
AssocingFileExtension=جاري ربط %1 مع صيغة ملف %2
AutoStartProgramGroupDescription=بدأ التشغيل:
AutoStartProgram=تشغيل %1 تلقائيا
AddonHostProgramNotFound= تعذر العثور على %1 في الموقع الذي إخترته.%n%nهل تريد المتابعة على أية حال؟
================================================
FILE: InnoDependencies/ChineseSimplified.isl
================================================
; *** Inno Setup version 6.1.0+ Chinese Simplified messages ***
;
; To download user-contributed translations of this file, go to:
; https://jrsoftware.org/files/istrans/
;
; Note: When translating this text, do not add periods (.) to the end of
; messages that didn't have them already, because on those messages Inno
; Setup adds the periods automatically (appending a period would result in
; two periods being displayed).
;
; Maintained by Zhenghan Yang
; Email: 847320916@QQ.com
; Translation based on network resource
; The latest Translation is on https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation
;
[LangOptions]
; The following three entries are very important. Be sure to read and
; understand the '[LangOptions] section' topic in the help file.
LanguageName=简体中文
; If Language Name display incorrect, uncomment next line
; LanguageName=<7B80><4F53><4E2D><6587>
; About LanguageID, to reference link:
; https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
LanguageID=$0804
LanguageCodePage=936
; If the language you are translating to requires special font faces or
; sizes, uncomment any of the following entries and change them accordingly.
;DialogFontName=
;DialogFontSize=8
;WelcomeFontName=Verdana
;WelcomeFontSize=12
;TitleFontName=Arial
;TitleFontSize=29
;CopyrightFontName=Arial
;CopyrightFontSize=8
[Messages]
; *** 应用程序标题
SetupAppTitle=安装
SetupWindowTitle=安装 - %1
UninstallAppTitle=卸载
UninstallAppFullTitle=%1 卸载
; *** Misc. common
InformationTitle=信息
ConfirmTitle=确认
ErrorTitle=错误
; *** SetupLdr messages
SetupLdrStartupMessage=现在将安装 %1。您想要继续吗?
LdrCannotCreateTemp=不能创建临时文件。安装中断。
LdrCannotExecTemp=不能执行临时目录中的文件。安装中断。
HelpTextNote=
; *** 启动错误消息
LastErrorMessage=%1.%n%n错误 %2: %3
SetupFileMissing=安装目录中的文件 %1 丢失。请修正这个问题或者获取程序的新副本。
SetupFileCorrupt=安装文件已损坏。请获取程序的新副本。
SetupFileCorruptOrWrongVer=安装文件已损坏,或是与这个安装程序的版本不兼容。请修正这个问题或获取新的程序副本。
InvalidParameter=无效的命令行参数:%n%n%1
SetupAlreadyRunning=安装程序正在运行。
WindowsVersionNotSupported=这个程序不支持当前计算机运行的Windows版本。
WindowsServicePackRequired=这个程序需要 %1 服务包 %2 或更高。
NotOnThisPlatform=这个程序将不能运行于 %1。
OnlyOnThisPlatform=这个程序必须运行于 %1。
OnlyOnTheseArchitectures=这个程序只能在为下列处理器结构设计的Windows版本中进行安装:%n%n%1
WinVersionTooLowError=这个程序需要 %1 版本 %2 或更高。
WinVersionTooHighError=这个程序不能安装于 %1 版本 %2 或更高。
AdminPrivilegesRequired=在安装这个程序时您必须以管理员身份登录。
PowerUserPrivilegesRequired=在安装这个程序时您必须以管理员身份或有权限的用户组身份登录。
SetupAppRunningError=安装程序发现 %1 当前正在运行。%n%n请先关闭所有运行的窗口,然后点击“确定”继续,或按“取消”退出。
UninstallAppRunningError=卸载程序发现 %1 当前正在运行。%n%n请先关闭所有运行的窗口,然后点击“确定”继续,或按“取消”退出。
; *** 启动问题
PrivilegesRequiredOverrideTitle=选择安装程序模式
PrivilegesRequiredOverrideInstruction=选择安装模式
PrivilegesRequiredOverrideText1=%1 可以为所有用户安装(需要管理员权限),或仅为您安装。
PrivilegesRequiredOverrideText2=%1 只能为您安装,或为所有用户安装(需要管理员权限)。
PrivilegesRequiredOverrideAllUsers=为所有用户安装(&A)
PrivilegesRequiredOverrideAllUsersRecommended=为所有用户安装(&A) (建议选项)
PrivilegesRequiredOverrideCurrentUser=只为我安装(&M)
PrivilegesRequiredOverrideCurrentUserRecommended=只为我安装(&M) (建议选项)
; *** 其它错误
ErrorCreatingDir=安装程序不能创建目录“%1”。
ErrorTooManyFilesInDir=不能在目录“%1”中创建文件,因为里面的文件太多
; *** 安装程序公共消息
ExitSetupTitle=退出安装程序
ExitSetupMessage=安装程序还未完成安装。如果您现在退出,程序将不能安装。%n%n您可以以后再运行安装程序完成安装。%n%n现在退出安装程序吗?
AboutSetupMenuItem=关于安装程序(&A)...
AboutSetupTitle=关于安装程序
AboutSetupMessage=%1 版本 %2%n%3%n%n%1 主页:%n%4
AboutSetupNote=
TranslatorNote=
; *** 按钮
ButtonBack=< 上一步(&B)
ButtonNext=下一步(&N) >
ButtonInstall=安装(&I)
ButtonOK=确定
ButtonCancel=取消
ButtonYes=是(&Y)
ButtonYesToAll=全是(&A)
ButtonNo=否(&N)
ButtonNoToAll=全否(&O)
ButtonFinish=完成(&F)
ButtonBrowse=浏览(&B)...
ButtonWizardBrowse=浏览(&R)...
ButtonNewFolder=新建文件夹(&M)
; *** “选择语言”对话框消息
SelectLanguageTitle=选择安装语言
SelectLanguageLabel=选择安装时要使用的语言。
; *** 公共向导文字
ClickNext=点击“下一步”继续,或点击“取消”退出安装程序。
BeveledLabel=
BrowseDialogTitle=浏览文件夹
BrowseDialogLabel=在下列列表中选择一个文件夹,然后点击“确定”。
NewFolderName=新建文件夹
; *** “欢迎”向导页
WelcomeLabel1=欢迎使用 [name] 安装向导
WelcomeLabel2=现在将安装 [name/ver] 到您的电脑中。%n%n推荐您在继续安装前关闭所有其它应用程序。
; *** “密码”向导页
WizardPassword=密码
PasswordLabel1=这个安装程序有密码保护。
PasswordLabel3=请输入密码,然后点击“下一步”继续。密码区分大小写。
PasswordEditLabel=密码(&P):
IncorrectPassword=您所输入的密码不正确,请重试。
; *** “许可协议”向导页
WizardLicense=许可协议
LicenseLabel=继续安装前请阅读下列重要信息。
LicenseLabel3=请仔细阅读下列许可协议。您在继续安装前必须同意这些协议条款。
LicenseAccepted=我同意此协议(&A)
LicenseNotAccepted=我不同意此协议(&D)
; *** “信息”向导页
WizardInfoBefore=信息
InfoBeforeLabel=请在继续安装前阅读下列重要信息。
InfoBeforeClickLabel=如果您想继续安装,点击“下一步”。
WizardInfoAfter=信息
InfoAfterLabel=请在继续安装前阅读下列重要信息。
InfoAfterClickLabel=如果您想继续安装,点击“下一步”。
; *** “用户信息”向导页
WizardUserInfo=用户信息
UserInfoDesc=请输入您的信息。
UserInfoName=用户名(&U):
UserInfoOrg=组织(&O):
UserInfoSerial=序列号(&S):
UserInfoNameRequired=您必须输入用户名。
; *** “选择目标目录”向导页
WizardSelectDir=选择目标位置
SelectDirDesc=您想将 [name] 安装在哪里?
SelectDirLabel3=安装程序将安装 [name] 到下列文件夹中。
SelectDirBrowseLabel=点击“下一步”继续。如果您想选择其它文件夹,点击“浏览”。
DiskSpaceGBLabel=至少需要有 [gb] GB 的可用磁盘空间。
DiskSpaceMBLabel=至少需要有 [mb] MB 的可用磁盘空间。
CannotInstallToNetworkDrive=安装程序无法安装到一个网络驱动器。
CannotInstallToUNCPath=安装程序无法安装到一个UNC路径。
InvalidPath=您必须输入一个带驱动器卷标的完整路径,例如:%n%nC:\APP%n%n或下列形式的UNC路径:%n%n\\server\share
InvalidDrive=您选定的驱动器或 UNC 共享不存在或不能访问。请选选择其它位置。
DiskSpaceWarningTitle=没有足够的磁盘空间
DiskSpaceWarning=安装程序至少需要 %1 KB 的可用空间才能安装,但选定驱动器只有 %2 KB 的可用空间。%n%n您一定要继续吗?
DirNameTooLong=文件夹名称或路径太长。
InvalidDirName=文件夹名称无效。
BadDirName32=文件夹名称不能包含下列任何字符:%n%n%1
DirExistsTitle=文件夹已存在
DirExists=文件夹:%n%n%1%n%n已经存在。您一定要安装到这个文件夹中吗?
DirDoesntExistTitle=文件夹不存在
DirDoesntExist=文件夹:%n%n%1%n%n不存在。您想要创建此文件夹吗?
; *** “选择组件”向导页
WizardSelectComponents=选择组件
SelectComponentsDesc=您想安装哪些程序的组件?
SelectComponentsLabel2=选择您想要安装的组件;清除您不想安装的组件。然后点击“下一步”继续。
FullInstallation=完全安装
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
CompactInstallation=简洁安装
CustomInstallation=自定义安装
NoUninstallWarningTitle=组件已存在
NoUninstallWarning=安装程序检测到下列组件已在您的电脑中安装:%n%n%1%n%n取消选定这些组件将不能卸载它们。%n%n您一定要继续吗?
ComponentSize1=%1 KB
ComponentSize2=%1 MB
ComponentsDiskSpaceGBLabel=当前选择的组件至少需要 [gb] GB 的磁盘空间。
ComponentsDiskSpaceMBLabel=当前选择的组件至少需要 [mb] MB 的磁盘空间。
; *** “选择附加任务”向导页
WizardSelectTasks=选择附加任务
SelectTasksDesc=您想要安装程序执行哪些附加任务?
SelectTasksLabel2=选择您想要安装程序在安装 [name] 时执行的附加任务,然后点击“下一步”。
; *** “选择开始菜单文件夹”向导页
WizardSelectProgramGroup=选择开始菜单文件夹
SelectStartMenuFolderDesc=安装程序应该在哪里放置程序的快捷方式?
SelectStartMenuFolderLabel3=安装程序现在将在下列开始菜单文件夹中创建程序的快捷方式。
SelectStartMenuFolderBrowseLabel=点击“下一步”继续。如果您想选择其它文件夹,点击“浏览”。
MustEnterGroupName=您必须输入一个文件夹名。
GroupNameTooLong=文件夹名或路径太长。
InvalidGroupName=文件夹名是无效的。
BadGroupName=文件夹名不能包含下列任何字符:%n%n%1
NoProgramGroupCheck2=不创建开始菜单文件夹(&D)
; *** “准备安装”向导页
WizardReady=准备安装
ReadyLabel1=安装程序现在准备开始安装 [name] 到您的电脑中。
ReadyLabel2a=点击“安装”继续此安装程序。如果您想要回顾或修改设置,请点击“上一步”。
ReadyLabel2b=点击“安装”继续此安装程序?
ReadyMemoUserInfo=用户信息:
ReadyMemoDir=目标位置:
ReadyMemoType=安装类型:
ReadyMemoComponents=选定组件:
ReadyMemoGroup=开始菜单文件夹:
ReadyMemoTasks=附加任务:
; *** TDownloadWizardPage wizard page and DownloadTemporaryFile
DownloadingLabel=正在下载附加文件...
ButtonStopDownload=停止下载(&S)
StopDownload=您确定要停止下载吗?
ErrorDownloadAborted=下载已中止
ErrorDownloadFailed=下载失败:%1 %2
ErrorDownloadSizeFailed=获取下载大小失败:%1 %2
ErrorFileHash1=校验文件哈希失败:%1
ErrorFileHash2=无效的文件哈希:预期 %1,实际 %2
ErrorProgress=无效的进度:%1,总共%2
ErrorFileSize=文件大小错误:预期 %1,实际 %2
; *** “正在准备安装”向导页
WizardPreparing=正在准备安装
PreparingDesc=安装程序正在准备安装 [name] 到您的电脑中。
PreviousInstallNotCompleted=先前程序的安装/卸载未完成。您需要重新启动您的电脑才能完成安装。%n%n在重新启动电脑后,再运行安装完成 [name] 的安装。
CannotContinue=安装程序不能继续。请点击“取消”退出。
ApplicationsFound=下列应用程序正在使用的文件需要更新设置。它是建议您允许安装程序自动关闭这些应用程序。
ApplicationsFound2=下列应用程序正在使用的文件需要更新设置。它是建议您允许安装程序自动关闭这些应用程序。安装完成后,安装程序将尝试重新启动应用程序。
CloseApplications=自动关闭该应用程序(&A)
DontCloseApplications=不要关闭该应用程序(&D)
ErrorCloseApplications=安装程序无法自动关闭所有应用程序。在继续之前,我们建议您关闭所有使用需要更新的安装程序文件。
PrepareToInstallNeedsRestart=安装程序必须重新启动计算机。重新启动计算机后,请再次运行安装程序以完成 [name] 的安装。%n%n是否立即重新启动?
; *** “正在安装”向导页
WizardInstalling=正在安装
InstallingLabel=安装程序正在安装 [name] 到您的电脑中,请稍等。
; *** “安装完成”向导页
FinishedHeadingLabel=[name] 安装完成
FinishedLabelNoIcons=安装程序已在您的电脑中安装了 [name]。
FinishedLabel=安装程序已在您的电脑中安装了 [name]。此应用程序可以通过选择安装的快捷方式运行。
ClickFinish=点击“完成”退出安装程序。
FinishedRestartLabel=要完成 [name] 的安装,安装程序必须重新启动您的电脑。您想要立即重新启动吗?
FinishedRestartMessage=要完成 [name] 的安装,安装程序必须重新启动您的电脑。%n%n您想要立即重新启动吗?
ShowReadmeCheck=是,我想查阅自述文件
YesRadio=是,立即重新启动电脑(&Y)
NoRadio=否,稍后重新启动电脑(&N)
; used for example as 'Run MyProg.exe'
RunEntryExec=运行 %1
; used for example as 'View Readme.txt'
RunEntryShellExec=查阅 %1
; *** “安装程序需要下一张磁盘”提示
ChangeDiskTitle=安装程序需要下一张磁盘
SelectDiskLabel2=请插入磁盘 %1 并点击“确定”。%n%n如果这个磁盘中的文件可以在下列文件夹之外的文件夹中找到,请输入正确的路径或点击“浏览”。
PathLabel=路径(&P):
FileNotInDir2=文件“%1”不能在“%2”定位。请插入正确的磁盘或选择其它文件夹。
SelectDirectoryLabel=请指定下一张磁盘的位置。
; *** 安装状态消息
SetupAborted=安装程序未完成安装。%n%n请修正这个问题并重新运行安装程序。
AbortRetryIgnoreSelectAction=选择操作
AbortRetryIgnoreRetry=重试(&T)
AbortRetryIgnoreIgnore=忽略错误并继续(&I)
AbortRetryIgnoreCancel=关闭安装程序
; *** 安装状态消息
StatusClosingApplications=正在关闭应用程序...
StatusCreateDirs=正在创建目录...
StatusExtractFiles=正在解压缩文件...
StatusCreateIcons=正在创建快捷方式...
StatusCreateIniEntries=正在创建 INI 条目...
StatusCreateRegistryEntries=正在创建注册表条目...
StatusRegisterFiles=正在注册文件...
StatusSavingUninstall=正在保存卸载信息...
StatusRunProgram=正在完成安装...
StatusRestartingApplications=正在重启应用程序...
StatusRollback=正在撤销更改...
; *** 其它错误
ErrorInternal2=内部错误:%1
ErrorFunctionFailedNoCode=%1 失败
ErrorFunctionFailed=%1 失败;错误代码 %2
ErrorFunctionFailedWithMessage=%1 失败;错误代码 %2.%n%3
ErrorExecutingProgram=不能执行文件:%n%1
; *** 注册表错误
ErrorRegOpenKey=打开注册表项时出错:%n%1\%2
ErrorRegCreateKey=创建注册表项时出错:%n%1\%2
ErrorRegWriteKey=写入注册表项时出错:%n%1\%2
; *** INI 错误
ErrorIniEntry=在文件“%1”中创建INI条目时出错。
; *** 文件复制错误
FileAbortRetryIgnoreSkipNotRecommended=跳过这个文件(&S) (不推荐)
FileAbortRetryIgnoreIgnoreNotRecommended=忽略错误并继续(&I) (不推荐)
SourceIsCorrupted=源文件已损坏
SourceDoesntExist=源文件“%1”不存在
ExistingFileReadOnly2=无法替换现有文件,因为它是只读的。
ExistingFileReadOnlyRetry=移除只读属性并重试(&R)
ExistingFileReadOnlyKeepExisting=保留现有文件(&K)
ErrorReadingExistingDest=尝试读取现有文件时出错:
FileExistsSelectAction=选择操作
FileExists2=文件已经存在。
FileExistsOverwriteExisting=覆盖已经存在的文件(&O)
FileExistsKeepExisting=保留现有的文件(&K)
FileExistsOverwriteOrKeepAll=为所有的冲突文件执行此操作(&D)
ExistingFileNewerSelectAction=选择操作
ExistingFileNewer2=现有的文件比安装程序将要安装的文件更新。
ExistingFileNewerOverwriteExisting=覆盖已经存在的文件(&O)
ExistingFileNewerKeepExisting=保留现有的文件(&K) (推荐)
ExistingFileNewerOverwriteOrKeepAll=为所有的冲突文件执行此操作(&D)
ErrorChangingAttr=尝试改变下列现有的文件的属性时出错:
ErrorCreatingTemp=尝试在目标目录创建文件时出错:
ErrorReadingSource=尝试读取下列源文件时出错:
ErrorCopying=尝试复制下列文件时出错:
ErrorReplacingExistingFile=尝试替换现有的文件时出错:
ErrorRestartReplace=重新启动替换失败:
ErrorRenamingTemp=尝试重新命名以下目标目录中的一个文件时出错:
ErrorRegisterServer=无法注册 DLL/OCX:%1
ErrorRegSvr32Failed=RegSvr32 失败;退出代码 %1
ErrorRegisterTypeLib=无法注册类型库:%1
; *** 卸载显示名字标记
; used for example as 'My Program (32-bit)'
UninstallDisplayNameMark=%1 (%2)
; used for example as 'My Program (32-bit, All users)'
UninstallDisplayNameMarks=%1 (%2, %3)
UninstallDisplayNameMark32Bit=32位
UninstallDisplayNameMark64Bit=64位
UninstallDisplayNameMarkAllUsers=所有用户
UninstallDisplayNameMarkCurrentUser=当前用户
; *** 安装后错误
ErrorOpeningReadme=尝试打开自述文件时出错。
ErrorRestartingComputer=安装程序不能重新启动电脑,请手动重启。
; *** 卸载消息
UninstallNotFound=文件“%1”不存在。无法卸载。
UninstallOpenError=文件“%1”不能打开。无法卸载。
UninstallUnsupportedVer=此版本的卸载程序无法识别卸载日志文件“%1”的格式。无法卸载
UninstallUnknownEntry=在卸载日志中遇到一个未知的条目 (%1)
ConfirmUninstall=您确认想要完全删除 %1 及它的所有组件吗?
UninstallOnlyOnWin64=这个安装程序只能在64位Windows中进行卸载。
OnlyAdminCanUninstall=这个安装的程序需要有管理员权限的用户才能卸载。
UninstallStatusLabel=正在从您的电脑中删除 %1,请稍等。
UninstalledAll=%1 已顺利地从您的电脑中删除。
UninstalledMost=%1 卸载完成。%n%n有一些内容无法被删除。您可以手动删除它们。
UninstalledAndNeedsRestart=要完成 %1 的卸载,您的电脑必须重新启动。%n%n您想立即重新启动电脑吗?
UninstallDataCorrupted=文件“%1”已损坏,无法卸载
; *** 卸载状态消息
ConfirmDeleteSharedFileTitle=删除共享文件吗?
ConfirmDeleteSharedFile2=系统中包含的下列共享文件已经不再被其它程序使用。您想要卸载程序删除这些共享文件吗?%n%n如果这些文件被删除,但还有程序正在使用这些文件,这些程序可能不能正确执行。如果您不能确定,选择“否”。把这些文件保留在系统中以免引起问题。
SharedFileNameLabel=文件名:
SharedFileLocationLabel=位置:
WizardUninstalling=卸载状态
StatusUninstalling=正在卸载 %1...
; *** Shutdown block reasons
ShutdownBlockReasonInstallingApp=正在安装 %1。
ShutdownBlockReasonUninstallingApp=正在卸载 %1。
; The custom messages below aren't used by Setup itself, but if you make
; use of them in your scripts, you'll want to translate them.
[CustomMessages]
NameAndVersion=%1 版本 %2
AdditionalIcons=附加快捷方式:
CreateDesktopIcon=创建桌面快捷方式(&D)
CreateQuickLaunchIcon=创建快速运行栏快捷方式(&Q)
ProgramOnTheWeb=%1 网站
UninstallProgram=卸载 %1
LaunchProgram=运行 %1
AssocFileExtension=将 %2 文件扩展名与 %1 建立关联(&A)
AssocingFileExtension=正在将 %2 文件扩展名与 %1 建立关联...
AutoStartProgramGroupDescription=启动组:
AutoStartProgram=自动启动 %1
AddonHostProgramNotFound=%1无法找到您所选择的文件夹。%n%n您想要继续吗?
================================================
FILE: InnoDependencies/ChineseTraditional.isl
================================================
; *** Inno Setup version 6.1.0+ Chinese (Traditional) messages ***
; Name: Enfeng Tsao, nelson22768384@gmail.com
; Based on 5.5.3+ translations by Samuel Lee, Email: 751555749@qq.com
; Translation based on network resource
;
; Note: When translating this text, do not add periods (.) to the end of
; messages that didn't have them already, because on those messages Inno
; Setup adds the periods automatically (appending a period would result in
; two periods being displayed).
[LangOptions]
; The following three entries are very important. Be sure to read and
; understand the '[LangOptions] section' topic in the help file.
LanguageName=<7e41><9ad4><4e2d><6587>
LanguageID=$0404
LanguageCodepage=950
; If the language you are translating to requires special font faces or
; sizes, uncomment any of the following entries and change them accordingly.
;DialogFontName=
;DialogFontSize=8
;TitleFontName=Arial
;TitleFontSize=29
;WelcomeFontName=Verdana
;WelcomeFontSize=12
;CopyrightFontName=Arial
;CopyrightFontSize=8
[Messages]
; *** Application titles
SetupAppTitle=安裝程式
SetupWindowTitle=%1 安裝程式
UninstallAppTitle=解除安裝
UninstallAppFullTitle=解除安裝 %1
; *** Misc. common
InformationTitle=訊息
ConfirmTitle=確認
ErrorTitle=錯誤
; *** SetupLdr messages
SetupLdrStartupMessage=這將會安裝 %1。您想要繼續嗎?
LdrCannotCreateTemp=無法建立暫存檔案。安裝程式將會結束。
LdrCannotExecTemp=無法執行暫存檔案。安裝程式將會結束。
HelpTextNote=
; *** Startup error messages
LastErrorMessage=%1%n%n錯誤 %2: %3
SetupFileMissing=安裝資料夾中遺失檔案 %1。請修正此問題或重新取得此軟體。
SetupFileCorrupt=安裝檔案已經損毀。請重新取得此軟體。
SetupFileCorruptOrWrongVer=安裝檔案已經損毀,或與安裝程式的版本不符。請重新取得此軟體。
InvalidParameter=某個無效的變量已被傳遞到了命令列:%n%n%1
SetupAlreadyRunning=安裝程式已經在執行。
WindowsVersionNotSupported=本安裝程式並不支援目前在電腦所運行的 Windows 版本。
WindowsServicePackRequired=本安裝程式需要 %1 Service Pack %2 或更新。
NotOnThisPlatform=這個程式無法在 %1 執行。
OnlyOnThisPlatform=這個程式必須在 %1 執行。
OnlyOnTheseArchitectures=這個程式只能在專門為以下處理器架構而設計的 Windows 上安裝:%n%n%1
WinVersionTooLowError=這個程式必須在 %1 版本 %2 或以上的系統執行。
WinVersionTooHighError=這個程式無法安裝在 %1 版本 %2 或以上的系統。
AdminPrivilegesRequired=您必須登入成系統管理員以安裝這個程式。
PowerUserPrivilegesRequired=您必須登入成具有系統管理員或 Power User 權限的使用者以安裝這個程式。
SetupAppRunningError=安裝程式偵測到 %1 正在執行。%n%n請關閉該程式後按 「確定」 繼續,或按 「取消」 離開。
UninstallAppRunningError=解除安裝程式偵測到 %1 正在執行。%n%n請關閉該程式後按 「確定」 繼續,或按 「取消」 離開。
; *** Startup questions
PrivilegesRequiredOverrideTitle=選擇安裝程式安裝模式
PrivilegesRequiredOverrideInstruction=選擇安裝模式
PrivilegesRequiredOverrideText1=可以為所有使用者安裝 %1 (需要系統管理權限),或是僅為您安裝。
PrivilegesRequiredOverrideText2=可以僅為您安裝 %1,或是為所有使用者安裝 (需要系統管理權限)。
PrivilegesRequiredOverrideAllUsers=為所有使用者安裝 (&A)
PrivilegesRequiredOverrideAllUsersRecommended=為所有使用者安裝 (建議選項) (&A)
PrivilegesRequiredOverrideCurrentUser=僅為我安裝 (&M)
PrivilegesRequiredOverrideCurrentUserRecommended=僅為我安裝 (建議選項) (&M)
; *** Misc. errors
ErrorCreatingDir=安裝程式無法建立資料夾“%1”。
ErrorTooManyFilesInDir=無法在資料夾“%1”內建立檔案,因為資料夾內有太多的檔案。
; *** Setup common messages
ExitSetupTitle=結束安裝程式
ExitSetupMessage=安裝尚未完成。如果您現在結束安裝程式,這個程式將不會被安裝。%n%n您可以稍後再執行安裝程式以完成安裝程序。您現在要結束安裝程式嗎?
AboutSetupMenuItem=關於安裝程式 (&A)...
AboutSetupTitle=關於安裝程式
AboutSetupMessage=%1 版本 %2%n%3%n%n%1 網址:%n%4
AboutSetupNote=
TranslatorNote=
; *** Buttons
ButtonBack=< 上一步(&B)
ButtonInstall=安裝(&I)
ButtonNext=下一步(&N) >
ButtonOK=確定
ButtonCancel=取消
ButtonYes=是(&Y)
ButtonYesToAll=全部皆是 (&A)
ButtonNo=否(&N)
ButtonNoToAll=全部皆否 (&O)
ButtonFinish=完成 (&F)
ButtonBrowse=瀏覽 (&B)...
ButtonWizardBrowse=瀏覽 (&R)...
ButtonNewFolder=建立新資料夾 (&M)
; *** "Select Language" dialog messages
SelectLanguageTitle=選擇安裝語言
SelectLanguageLabel=選擇在安裝過程中使用的語言:
; *** Common wizard text
ClickNext=按 「下一步」 繼續安裝,或按 「取消」 結束安裝程式。
BeveledLabel=
BrowseDialogTitle=瀏覽資料夾
BrowseDialogLabel=在下面的資料夾列表中選擇一個資料夾,然後按 「確定」。
NewFolderName=新資料夾
; *** "Welcome" wizard page
WelcomeLabel1=歡迎使用 [name] 安裝程式
WelcomeLabel2=這個安裝程式將會安裝 [name/ver] 到您的電腦。%n%n我們強烈建議您在安裝過程中關閉其它的應用程式,以避免與安裝程式發生沖突。
; *** "Password" wizard page
WizardPassword=密碼
PasswordLabel1=這個安裝程式具有密碼保護。
PasswordLabel3=請輸入密碼,然後按 「下一步」 繼續。密碼是區分大小寫的。
PasswordEditLabel=密碼 (&P):
IncorrectPassword=您輸入的密碼不正確,請重新輸入。
; *** "License Agreement" wizard page
WizardLicense=授權合約
LicenseLabel=請閱讀以下授權合約。
LicenseLabel3=請閱讀以下授權合約,您必須接受合約的各項條款才能繼續安裝。
LicenseAccepted=我同意 (&A)
LicenseNotAccepted=我不同意 (&D)
; *** "Information" wizard pages
WizardInfoBefore=訊息
InfoBeforeLabel=在繼續安裝之前請閱讀以下重要資訊。
InfoBeforeClickLabel=當您準備好繼續安裝,請按 「下一步」。
WizardInfoAfter=訊息
InfoAfterLabel=在繼續安裝之前請閱讀以下重要資訊。
InfoAfterClickLabel=當您準備好繼續安裝,請按 「下一步」。
; *** "User Information" wizard page
WizardUserInfo=使用者資訊
UserInfoDesc=請輸入您的資料。
UserInfoName=使用者名稱(&U):
UserInfoOrg=組織(&O):
UserInfoSerial=序號(&S):
UserInfoNameRequired=您必須輸入您的名稱。
; *** "Select Destination Location" wizard page
WizardSelectDir=選擇目的資料夾
SelectDirDesc=選擇安裝程式安裝 [name] 的位置。
SelectDirLabel3=安裝程式將會把 [name] 安裝到下面的資料夾。
SelectDirBrowseLabel=按 「下一步」 繼續,如果您想選擇另一個資料夾,請按 「瀏覽」。
DiskSpaceGBLabel=最少需要 [gb] GB 磁碟空間。
DiskSpaceMBLabel=最少需要 [mb] MB 磁碟空間。
CannotInstallToNetworkDrive=安裝程式無法安裝於網絡磁碟機。
CannotInstallToUNCPath=安裝程式無法安裝於 UNC 路徑。
InvalidPath=您必須輸入完整的路徑名稱及磁碟機代碼。%n%n例如 C:\App 或 UNC 路徑格式 \\伺服器\共用資料夾。
InvalidDrive=您選取的磁碟機或 UNC 名稱不存在或無法存取,請選擇其他的目的地。
DiskSpaceWarningTitle=磁碟空間不足
DiskSpaceWarning=安裝程式需要至少 %1 KB 的磁碟空間,您所選取的磁碟只有 %2 KB 可用空間。%n%n您要繼續安裝嗎?
DirNameTooLong=資料夾名稱或路徑太長。
InvalidDirName=資料夾名稱不正確。
BadDirName32=資料夾名稱不得包含以下特殊字元:%n%n%1
DirExistsTitle=資料夾已經存在
DirExists=資料夾:%n%n%1%n%n 已經存在。仍要安裝到該資料夾嗎?
DirDoesntExistTitle=資料夾不存在
DirDoesntExist=資料夾:%n%n%1%n%n 不存在。要建立該資料夾嗎?
; *** "Select Components" wizard page
WizardSelectComponents=選擇元件
SelectComponentsDesc=選擇將會被安裝的元件。
SelectComponentsLabel2=選擇您想要安裝的元件;清除您不想安裝的元件。然後按 「下一步」 繼續安裝。
FullInstallation=完整安裝
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
CompactInstallation=最小安裝
CustomInstallation=自訂安裝
NoUninstallWarningTitle=元件已存在
NoUninstallWarning=安裝程式偵測到以下元件已經安裝在您的電腦上:%n%n%1%n%n取消選擇這些元件將不會移除它們。%n%n您仍然要繼續嗎?
ComponentSize1=%1 KB
ComponentSize2=%1 MB
ComponentsDiskSpaceGBLabel=目前的選擇需要至少 [gb] GB 磁碟空間。
ComponentsDiskSpaceMBLabel=目前的選擇需要至少 [mb] MB 磁碟空間。
; *** "Select Additional Tasks" wizard page
WizardSelectTasks=選擇附加的工作
SelectTasksDesc=選擇要執行的附加工作。
SelectTasksLabel2=選擇安裝程式在安裝 [name] 時要執行的附加工作,然後按 「下一步」。
; *** "Select Start Menu Folder" wizard page
WizardSelectProgramGroup=選擇「開始」功能表的資料夾
SelectStartMenuFolderDesc=選擇安裝程式建立程式的捷徑的位置。
SelectStartMenuFolderLabel3=安裝程式將會把程式的捷徑建立在下面的「開始」功能表資料夾。
SelectStartMenuFolderBrowseLabel=按 「下一步」 繼續,如果您想選擇另一個資料夾,請按 「瀏覽」。
MustEnterGroupName=您必須輸入一個資料夾的名稱。
GroupNameTooLong=資料夾名稱或路徑太長。
InvalidGroupName=資料夾名稱不正確。
BadGroupName=資料夾名稱不得包含下列字元:%n%n%1
NoProgramGroupCheck2=不要在「開始」功能表中建立資料夾 (&D)
; *** "Ready to Install" wizard page
WizardReady=準備安裝
ReadyLabel1=安裝程式將開始安裝 [name] 到您的電腦中。
ReadyLabel2a=按下 「安裝」 繼續安裝,或按 「上一步」 重新檢視或設定各選項的內容。
ReadyLabel2b=按下 「安裝」 繼續安裝。
ReadyMemoUserInfo=使用者資訊
ReadyMemoDir=目的資料夾:
ReadyMemoType=安裝型態:
ReadyMemoComponents=選擇的元件:
ReadyMemoGroup=「開始」功能表資料夾:
ReadyMemoTasks=附加工作:
; *** TDownloadWizardPage wizard page and DownloadTemporaryFile
DownloadingLabel=正在下載額外檔案...
ButtonStopDownload=停止下載 (&S)
StopDownload=您確定要停止下載嗎?
ErrorDownloadAborted=已停止下載
ErrorDownloadFailed=下載失敗: %1 %2
ErrorDownloadSizeFailed=取得檔案大小失敗: %1 %2
ErrorFileHash1=檔案雜湊失敗: %1
ErrorFileHash2=檔案雜湊無效: 必須為 %1,收到 %2
ErrorProgress=進度無效: %1 之 %2
ErrorFileSize=檔案大小無效: 必須為 %1,收到 %2
; *** "Preparing to Install" wizard page
WizardPreparing=準備安裝程式
PreparingDesc=安裝程式準備將 [name] 安裝到您的電腦上。
PreviousInstallNotCompleted=先前的安裝/ 解除安裝尚未完成,您必須重新啟動電腦以完成該安裝。%n%n在重新啟動電腦之後,請再執行這個程式來安裝 [name]。
CannotContinue=安裝程式無法繼續。請按 「取消」 離開。
ApplicationsFound=下面的應用程式正在使用安裝程式所需要更新的檔案。建議您允許安裝程式自動關閉這些應用程式。
ApplicationsFound2=下面的應用程式正在使用安裝程式所需要更新的檔案。建議您允許安裝程式自動關閉這些應用程式。當安裝過程結束後,本安裝程式將會嘗試重新開啟該應用程式。
CloseApplications=關閉應用程式 (&A)
DontCloseApplications=不要關閉應用程式 (&D)
ErrorCloseApplications=安裝程式無法自動關閉所有應用程式。建議您在繼續前先關閉所有應用程式使用的檔案。
PrepareToInstallNeedsRestart=安裝程式必須重新啟動您的電腦。重新啟動後,請再次執行安裝程式以完成 [name] 的安裝。%n%n您想要現在重新啟動電腦嗎?
; *** "Installing" wizard page
WizardInstalling=正在安裝
InstallingLabel=請稍候,安裝程式正在將 [name] 安裝到您的電腦上
; *** "Setup Completed" wizard page
FinishedHeadingLabel=安裝完成
FinishedLabelNoIcons=安裝程式已經將 [name] 安裝在您的電腦上。
FinishedLabel=安裝程式已經將 [name] 安裝在您的電腦中,您可以選擇程式的圖示來執行該應用程式。
ClickFinish=按 「完成」 以結束安裝程式。
FinishedRestartLabel=要完成 [name] 的安裝,安裝程式必須重新啟動您的電腦。您想要現在重新啟動電腦嗎?
FinishedRestartMessage=要完成 [name] 的安裝,安裝程式必須重新啟動您的電腦。%n%n您想要現在重新啟動電腦嗎?
ShowReadmeCheck=是,我要閱讀讀我檔案。
YesRadio=是,立即重新啟動電腦(&Y)
NoRadio=否,我稍後重新啟動電腦(&N)
; used for example as 'Run MyProg.exe'
RunEntryExec=執行 %1
; used for example as 'View Readme.txt'
RunEntryShellExec=檢視 %1
; *** "Setup Needs the Next Disk"
ChangeDiskTitle=安裝程式需要下一張磁片
SelectDiskLabel2=請插入磁片 %1,然後按 「確定」。%n%n如果檔案不在以下所顯示的資料夾之中,請輸入正確的資料夾名稱或按 [瀏覽] 選取。
PathLabel=路徑(&P):
FileNotInDir2=檔案“%1”無法在“%2”找到。請插入正確的磁片或選擇其它的資料夾。
SelectDirectoryLabel=請指定下一張磁片的位置。
; *** Installation phase messages
SetupAborted=安裝沒有完成。%n%n請更正問題後重新安裝一次。
AbortRetryIgnoreSelectAction=選取動作
AbortRetryIgnoreRetry=請再試一次 (&T)
AbortRetryIgnoreIgnore=略過錯誤並繼續 (&I)
AbortRetryIgnoreCancel=取消安裝
; *** Installation status messages
StatusClosingApplications=正在關閉應用程式...
StatusCreateDirs=正在建立資料夾...
StatusExtractFiles=正在解壓縮檔案...
StatusCreateIcons=正在建立程式集圖示...
StatusCreateIniEntries=寫入 INI 檔案的項目...
StatusCreateRegistryEntries=正在更新系統登錄...
StatusRegisterFiles=正在登錄檔案...
StatusSavingUninstall=儲存解除安裝資訊...
StatusRunProgram=正在完成安裝...
StatusRestartingApplications=正在重新開啟應用程式...
StatusRollback=正在復原變更...
; *** Misc. errors
ErrorInternal2=內部錯誤: %1
ErrorFunctionFailedNoCode=%1 失敗
ErrorFunctionFailed=%1 失敗;代碼 %2
ErrorFunctionFailedWithMessage=%1 失敗;代碼 %2.%n%3
ErrorExecutingProgram=無法執行檔案:%n%1
; *** Registry errors
ErrorRegOpenKey=無法開啟登錄鍵:%n%1\%2
ErrorRegCreateKey=無法建立登錄項目:%n%1\%2
ErrorRegWriteKey=無法變更登錄項目:%n%1\%2
; *** INI errors
ErrorIniEntry=在檔案“%1”建立 INI 項目錯誤。
; *** File copying errors
FileAbortRetryIgnoreSkipNotRecommended=略過這個檔案 (不建議) (&S)
FileAbortRetryIgnoreIgnoreNotRecommended=略過錯誤並繼續 (不建議) (&I)
SourceDoesntExist=來源檔案“%1”不存在。
SourceIsCorrupted=來源檔案已經損毀。
ExistingFileReadOnly2=無法取代現有檔案,因為檔案已標示為唯讀。
ExistingFileReadOnlyRetry=移除唯讀屬性並重試 (&R)
ExistingFileReadOnlyKeepExisting=保留現有檔案 (&K)
ErrorReadingExistingDest=讀取一個已存在的檔案時發生錯誤:
FileExistsSelectAction=選擇操作
FileExists2=檔案已存在。
FileExistsOverwriteExisting=覆寫現有檔案
FileExistsKeepExisting=保留現有檔案 (&O)
FileExistsOverwriteOrKeepAll=對下次衝突執行相同操作 (&D)
ExistingFileNewerSelectAction=選擇操作
ExistingFileNewer2=現有檔案比安裝程式嘗試安裝的檔案還新。
ExistingFileNewerOverwriteExisting=覆寫現有檔案 (&O)
ExistingFileNewerKeepExisting=保留現有檔案 (&K) (建議選項)
ExistingFileNewerOverwriteOrKeepAll=對下次衝突執行相同操作 (&D)
ErrorChangingAttr=在變更檔案屬性時發生錯誤:
ErrorCreatingTemp=在目的資料夾中建立檔案時發生錯誤:
ErrorReadingSource=讀取原始檔案時發生錯誤:
ErrorCopying=複製檔案時發生錯誤:
ErrorReplacingExistingFile=取代檔案時發生錯誤:
ErrorRestartReplace=重新啟動電腦後取代檔案失敗:
ErrorRenamingTemp=在目的資料夾變更檔案名稱時發生錯誤:
ErrorRegisterServer=無法注冊 DLL/OCX 檔案: %1。
ErrorRegSvr32Failed=RegSvr32 失敗;退出代碼 %1
ErrorRegisterTypeLib=無法注冊類型庫: %1。
; *** Uninstall display name markings
; used for example as 'My Program (32-bit)'
UninstallDisplayNameMark=%1 (%2)
; used for example as 'My Program (32-bit, All users)'
UninstallDisplayNameMarks=%1 (%2, %3)
UninstallDisplayNameMark32Bit=32 位元
UninstallDisplayNameMark64Bit=64 位元
UninstallDisplayNameMarkAllUsers=所有使用者
UninstallDisplayNameMarkCurrentUser=目前使用者
; *** Post-installation errors
ErrorOpeningReadme=開啟讀我檔案時發生錯誤。
ErrorRestartingComputer=安裝程式無法重新啟動電腦,請自行重新啟動。
; *** Uninstaller messages
UninstallNotFound=檔案“%1”不存在,無法解除安裝。
UninstallOpenError=無法開啟檔案“%1”,無法解除安裝
UninstallUnsupportedVer=這個版本的解除安裝程式無法辨識記錄檔 “%1” 之格式,無法解除安裝。
UninstallUnknownEntry=解除安裝記錄檔中發現未知的記錄 (%1)。
ConfirmUninstall=您確定要完全移除 %1 及其相關的檔案嗎?
UninstallOnlyOnWin64=這個程式只能在 64 位元的 Windows 上解除安裝。
OnlyAdminCanUninstall=這個程式要具備系統管理員權限的使用者方可解除安裝。
UninstallStatusLabel=正在從您的電腦移除 %1 中,請稍候...
UninstalledAll=%1 已經成功從您的電腦中移除。
UninstalledMost=%1 解除安裝完成。%n%n某些檔案及元件無法移除,您可以自行刪除這些檔案。
UninstalledAndNeedsRestart=要完成 %1 的解除安裝程序,您必須重新啟動電腦。%n%n您想要現在重新啟動電腦嗎?
UninstallDataCorrupted=檔案“%1”已經損毀,無法解除安裝
; *** Uninstallation phase messages
ConfirmDeleteSharedFileTitle=移除共用檔案
ConfirmDeleteSharedFile2=系統顯示下列共用檔案已不再被任何程式所使用,您要移除這些檔案嗎?%n%n%1%n%n倘若您移除了以上檔案但仍有程式需要使用它們,將造成這些程式無法正常執行,因此您若無法確定請選擇 [否]。保留這些檔案在您的系統中不會造成任何損害。
SharedFileNameLabel=檔案名稱:
SharedFileLocationLabel=位置:
WizardUninstalling=解除安裝狀態
StatusUninstalling=正在解除安裝 %1...
; *** Shutdown block reasons
ShutdownBlockReasonInstallingApp=正在安裝 %1。
ShutdownBlockReasonUninstallingApp=正在解除安裝 %1。
; The custom messages below aren't used by Setup itself, but if you make
; use of them in your scripts, you'll want to translate them.
[CustomMessages]
NameAndVersion=%1 版本 %2
AdditionalIcons=附加圖示:
CreateDesktopIcon=建立桌面圖示(&D)
CreateQuickLaunchIcon=建立快速啟動圖示(&Q)
ProgramOnTheWeb=%1 的網站
UninstallProgram=解除安裝 %1
LaunchProgram=啟動 %1
AssocFileExtension=將 %1 與檔案副檔名 %2 產生關聯(&A)
AssocingFileExtension=正在將 %1 與檔案副檔名 %2 產生關聯...
AutoStartProgramGroupDescription=開啟:
AutoStartProgram=自動開啟 %1
AddonHostProgramNotFound=%1 無法在您所選的資料夾中找到。%n%n您是否還要繼續?
================================================
FILE: InnoDependencies/Greek.isl
================================================
; *** Inno Setup version 6.1.0+ Greek messages ***
;
; To download user-contributed translations of this file, go to:
; https://jrsoftware.org/files/istrans/
;
; Note: When translating this text, do not add periods (.) to the end of
; messages that didn't have them already, because on those messages Inno
; Setup adds the periods automatically (appending a period would result in
; two periods being displayed).
;
; Originally translated by Anastasis Chatzioglou, baldycom@hotmail.com
; Updated by XhmikosR [XhmikosR, my_nickname at yahoo dot com]
; Updated to version 6.1.0+ by Vasileios Karamichail, v.karamichail@outlook.com
;
[LangOptions]
; The following three entries are very important. Be sure to read and
; understand the '[LangOptions] section' topic in the help file.
LanguageName=Ελληνικά
LanguageID=$0408
LanguageCodePage=1253
; If the language you are translating to requires special font faces or
; sizes, uncomment any of the following entries and change them accordingly.
;DialogFontName=
;DialogFontSize=8
;WelcomeFontName=Verdana
;WelcomeFontSize=12
;TitleFontName=Arial
;TitleFontSize=29
;CopyrightFontName=Arial
;CopyrightFontSize=8
[Messages]
; *** Application titles
SetupAppTitle=Εγκατάσταση
SetupWindowTitle=Εγκατάσταση - %1
UninstallAppTitle=Απεγκατάσταση
UninstallAppFullTitle=%1 Απεγκατάσταση
; *** Misc. common
InformationTitle=Πληροφορίες
ConfirmTitle=Επιβεβαίωση
ErrorTitle=Σφάλμα
; *** SetupLdr messages
SetupLdrStartupMessage=Θα εκτελεστεί η εγκατάσταση του %1. Θέλετε να συνεχίσετε;
LdrCannotCreateTemp=Σφάλμα στη δημιουργία προσωρινού αρχείου. Η εγκατάσταση τερματίστηκε
LdrCannotExecTemp=Αδύνατη η εκτέλεση αρχείου στον φάκελο προσωρινών αρχείων. Η εγκατάσταση τερματίστηκε
HelpTextNote=
; *** Startup error messages
LastErrorMessage=%1.%n%nΣφάλμα %2: %3
SetupFileMissing=Το αρχείο %1 λείπει από τον κατάλογο εγκατάστασης. Διορθώστε το πρόβλημα ή αποκτήστε ένα νέο αντίγραφο του προγράμματος.
SetupFileCorrupt=Το αρχείο εγκατάστασης είναι κατεστραμμένο. Παρακαλώ προμηθευτείτε ένα νέο αντίγραφο του προγράμματος.
SetupFileCorruptOrWrongVer=Το αρχείο εγκατάστασης είναι κατεστραμμένο ή δεν είναι συμβατό με αυτήν την έκδοση του προγράμματος εγκατάστασης. Διορθώστε το πρόβλημα ή αποκτήστε ένα νέο αντίγραφο του προγράμματος.
InvalidParameter=Μία μη έγκυρη παράμετρος χρησιμοποιήθηκε στη γραμμή εντολών:%n%n%1
SetupAlreadyRunning=Η εγκατάσταση τρέχει ήδη.
WindowsVersionNotSupported=Αυτό το πρόγραμμα δεν υποστηρίζει την έκδοση των Windows που εκτελεί ο υπολογιστής σας.
WindowsServicePackRequired=Αυτό το πρόγραμμα χρειάζεται το %1 Service Pack %2 ή νεότερο.
NotOnThisPlatform=Αυτό το πρόγραμμα δεν μπορεί να εκτελεστεί σε %1.
OnlyOnThisPlatform=Αυτό το πρόγραμμα μπορεί να εκτελεστεί μόνο σε %1.
OnlyOnTheseArchitectures=Αυτό το πρόγραμμα μπορεί να εγκατασταθεί μόνο σε εκδόσεις των Windows που έχουν σχεδιαστεί για τις ακόλουθες αρχιτεκτονικές επεξεργαστών:%n%n%1
WinVersionTooLowError=Αυτό το πρόγραμμα απαιτεί %1 έκδοση %2 ή μεταγενέστερη.
WinVersionTooHighError=Αυτό το πρόγραμμα δεν μπορεί να εγκατασταθεί σε %1 έκδοση %2 ή μεταγενέστερη.
AdminPrivilegesRequired=Πρέπει να είστε συνδεδεμένοι ως διαχειριστής κατά την εγκατάσταση αυτού του προγράμματος.
PowerUserPrivilegesRequired=Πρέπει να είστε συνδεδεμένοι ως διαχειριστής ή ως μέλος της ομάδας Power User κατά την εγκατάσταση αυτού του προγράμματος.
SetupAppRunningError=Ο Οδηγός Εγκατάστασης εντόπισε ότι η εφαρμογή %1 εκτελείται ήδη.%n%nΠαρακαλώ κλείστε την εφαρμογή τώρα και πατήστε ΟΚ για να συνεχίσετε, ή Άκυρο για έξοδο.
UninstallAppRunningError=Ο Οδηγός Απεγκατάστασης εντόπισε ότι η εφαρμογή %1 εκτελείται ήδη.%n%nΠαρακαλώ κλείστε την εφαρμογή τώρα και πατήστε ΟΚ για να συνεχίσετε, ή Άκυρο για έξοδο.
; *** Startup questions
PrivilegesRequiredOverrideTitle=Επιλέξτε Τρόπο Εγκατάστασης
PrivilegesRequiredOverrideInstruction=Επιλέξτε τον τρόπο εγκατάστασης
PrivilegesRequiredOverrideText1=Το %1 μπορεί να εγκατασταθεί για όλους τους χρήστες (απαιτεί δικαιώματα διαχειριστή) ή μόνο για εσάς.
PrivilegesRequiredOverrideText2=Το %1 μπορεί να εγκατασταθεί μόνο για εσάς ή για όλους τους χρήστες (απαιτεί δικαιώματα διαχειριστή).
PrivilegesRequiredOverrideAllUsers=Εγκατάσταση για &όλους τους χρήστες
PrivilegesRequiredOverrideAllUsersRecommended=Εγκατάσταση για όλ&ους τους χρήστες (συνιστάται)
PrivilegesRequiredOverrideCurrentUser=Εγκατάσταση μόνο για &εμένα
PrivilegesRequiredOverrideCurrentUserRecommended=Εγκατάσταση μόνο για &εμένα (συνιστάται)
; *** Misc. errors
ErrorCreatingDir=Η εγκατάσταση δεν μπόρεσε να δημιουργήσει τον φάκελο "%1"
ErrorTooManyFilesInDir=Δεν είναι δυνατή η δημιουργία ενός αρχείου στον φάκελο "%1" επειδή περιέχει πολλά αρχεία
; *** Setup common messages
ExitSetupTitle=Τέλος Εγκατάστασης
ExitSetupMessage=Η εγκατάσταση δεν έχει ολοκληρωθεί. Αν την τερματίσετε τώρα, το πρόγραμμα δεν θα εγκατασταθεί.%n%nΜπορείτε να εκτελέσετε ξανά την εγκατάσταση αργότερα.%n%nΈξοδος;
AboutSetupMenuItem=&Σχετικά με την Εγκατάσταση...
AboutSetupTitle=Σχετικά με την Εγκατάσταση
AboutSetupMessage=%1 έκδοση %2%n%3%n%n%1 αρχική σελίδα:%n%4
AboutSetupNote=
TranslatorNote=
; *** Buttons
ButtonBack=< &Πίσω
ButtonNext=&Επόμενο >
ButtonInstall=&Εγκατάσταση
ButtonOK=ΟΚ
ButtonCancel=&Ακυρο
ButtonYes=Ν&αι
ButtonYesToAll=Ναι σε &Ολα
ButtonNo=Ό&χι
ButtonNoToAll=Όχι &σε όλα
ButtonFinish=&Τέλος
ButtonBrowse=&Αναζήτηση...
ButtonWizardBrowse=Ανα&ζήτηση...
ButtonNewFolder=&Δημιουργία νέου φακέλου
; *** "Select Language" dialog messages
SelectLanguageTitle=Επιλογή Γλώσσας Οδηγού Εγκατάστασης
SelectLanguageLabel=Επιλέξτε τη γλώσσα που θέλετε να χρησιμοποιήσετε κατά την εγκατάσταση.
; *** Common wizard text
ClickNext=Πατήστε Επόμενο για να συνεχίσετε ή Άκυρο για να τερματίσετε την εγκατάσταση.
BeveledLabel=
BrowseDialogTitle=Αναζήτηση Φακέλου
BrowseDialogLabel=Επιλέξτε ένα φάκελο από την ακόλουθη λίστα και πατήστε ΟΚ.
NewFolderName=Νέος φάκελος
; *** "Welcome" wizard page
WelcomeLabel1=Καλως ορίσατε στον Οδηγό Εγκατάστασης του [name]
WelcomeLabel2=Θα γίνει εγκατάσταση του [name/ver] στον υπολογιστή σας.%n%nΣυνιστάται να κλείσετε όλες τις άλλες εφαρμογές πριν συνεχίσετε.
; *** "Password" wizard page
WizardPassword=Κωδικός Πρόσβασης
PasswordLabel1=Αυτή η εγκατάσταση προστατεύεται με κωδικό πρόσβασης.
PasswordLabel3=Παρακαλώ εισάγετε τον κωδικό και πατήστε Επόμενο.
PasswordEditLabel=&Κωδικός:
IncorrectPassword=Ο κωδικός που έχετε εισάγει είναι λανθασμένος. Παρακαλώ, προσπαθήστε ξανά.
; *** "License Agreement" wizard page
WizardLicense=Άδεια Χρήσης
LicenseLabel=Παρακαλώ διαβάστε προσεκτικά τις ακόλουθες πληροφορίες πριν συνεχίσετε.
LicenseLabel3=Παρακαλώ διαβάστε την ακόλουθη Άδεια Χρήσης. Θα πρέπει να αποδεχτείτε τους όρους της πριν συνεχίσετε την εγκατάσταση.
LicenseAccepted=&Δέχομαι τους όρους της Άδειας Χρήσης
LicenseNotAccepted=Δεν &αποδέχομαι τους όρους της Άδειας Χρήσης
; *** "Information" wizard pages
WizardInfoBefore=Πληροφορίες
InfoBeforeLabel=Παρακαλώ διαβάστε προσεκτικά τις ακόλουθες πληροφορίες πριν συνεχίσετε.
InfoBeforeClickLabel=Όταν είστε έτοιμοι να συνεχίσετε με τον Οδηγό Εγκατάστασης, πατήστε Επόμενο.
WizardInfoAfter=Πληροφορίες
InfoAfterLabel=Παρακαλώ διαβάστε προσεκτικά τις ακόλουθες πληροφορίες πριν συνεχίσετε.
InfoAfterClickLabel=Όταν είστε έτοιμοι να συνεχίσετε με τον Οδηγό Εγκατάστασης, πατήστε Επόμενο.
; *** "User Information" wizard page
WizardUserInfo=Πληροφορίες Χρήστη
UserInfoDesc=Παρακαλώ εισάγετε τα στοιχεία σας.
UserInfoName=&Ονομα Χρήστη:
UserInfoOrg=&Εταιρεία:
UserInfoSerial=&Σειριακός Αριθμός:
UserInfoNameRequired=Πρέπει να εισάγετε ένα όνομα.
; *** "Select Destination Location" wizard page
WizardSelectDir=Επιλογή Φακέλου Εγκατάστασης
SelectDirDesc=Πού θέλετε να εγκατασταθεί το [name];
SelectDirLabel3=Ο Οδηγός Εγκατάστασης θα εγκαταστήσει το [name] στον ακόλουθο φάκελο.
SelectDirBrowseLabel=Για να συνεχίσετε, πατήστε Επόμενο. Εάν θέλετε να επιλέξετε διαφορετικό φάκελο, πατήστε Αναζήτηση.
DiskSpaceGBLabel=Απαιτούνται τουλάχιστον [gb] GB ελεύθερου χώρου στο δίσκο.
DiskSpaceMBLabel=Απαιτούνται τουλάχιστον [mb] MB ελεύθερου χώρου στο δίσκο.
CannotInstallToNetworkDrive=Η εγκατάσταση δεν μπορεί να γίνει σε δίσκο δικτύου.
CannotInstallToUNCPath=Η εγκατάσταση δεν μπορεί να γίνει σε διαδρομή UNC.
InvalidPath=Πρέπει να δώσετε την πλήρη διαδρομή με το γράμμα δίσκου, για παράδειγμα:%n%nC:\APP%n%nή μια διαδρομή UNC της μορφής:%n%n\\server\share
InvalidDrive=Ο τοπικός δίσκος ή ο δίσκος δικτύου που έχετε επιλέξει δεν υπάρχει ή δεν είναι προσβάσιμος. Παρακαλώ, επιλέξτε άλλον.
DiskSpaceWarningTitle=Ανεπαρκής Χώρος στο Δίσκο
DiskSpaceWarning=Η εγκατάσταση χρειάζεται τουλάχιστον %1 KB ελεύθερο χώρο στο δίσκο αλλά ο επιλεγμένος δίσκος διαθέτει μόνον %2 KB.%n%nΘέλετε να συνεχίσετε παρόλα αυτά;
DirNameTooLong=Το όνομα ή η διαδρομή του φακέλου είναι πολύ μεγάλη.
InvalidDirName=Το όνομα του φακέλου δεν είναι έγκυρο.
BadDirName32=Το όνομα του φακέλου δεν μπορεί να περιλαμβάνει κανέναν από τους παρακάτω χαρακτήρες:%n%n%1
DirExistsTitle=Ο Φάκελος Υπάρχει
DirExists=Ο φάκελος:%n%n%1%n%nυπάρχει ήδη. Θέλετε να γίνει η εγκατάσταση σε αυτόν τον φάκελο παρόλα αυτά;
DirDoesntExistTitle=Ο Φάκελος Δεν Υπάρχει
DirDoesntExist=Ο φάκελος:%n%n%1%n%nδεν υπάρχει. Θέλετε να δημιουργηθεί;
; *** "Select Components" wizard page
WizardSelectComponents=Επιλογή Λειτουργιών Μονάδων
SelectComponentsDesc=Ποια στοιχεία θέλετε να εγκατασταθούν;
SelectComponentsLabel2=Επιλέξτε τα στοιχεία που θέλετε να εγκαταστήσετε, αποεπιλέξτε τα στοιχεία που δεν θέλετε να εγκαταστήσετε. Πατήστε Επόμενο όταν είστε έτοιμοι να συνεχίσετε.
FullInstallation=Πλήρης εγκατάσταση
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
CompactInstallation=Τυπική εγκατάσταση
CustomInstallation=Προσαρμοσμένη εγκατάσταση
NoUninstallWarningTitle=Οι Λειτουργικές Μονάδες Υπάρχουν
NoUninstallWarning=Ο Οδηγός Εγκατάστασης εντόπισε ότι τα ακόλουθα στοιχεία είναι ήδη εγκατεστημένα στον υπολογιστή σας:%n%n%1%n%nΑποεπιλέγοντας αυτά τα στοιχεία δεν θα απεγκατασταθούν.%n%nΘέλετε να συνεχίσετε παρόλα αυτά;
ComponentSize1=%1 KB
ComponentSize2=%1 MB
ComponentsDiskSpaceGBLabel=Η τρέχουσα επιλογή απαιτεί τουλάχιστον [gb] GB χώρου στο δίσκο.
ComponentsDiskSpaceMBLabel=Η τρέχουσα επιλογή απαιτεί τουλάχιστον [mb] MB χώρου στο δίσκο.
; *** "Select Additional Tasks" wizard page
WizardSelectTasks=Επιλογή Επιπλέον Ενεργειών
SelectTasksDesc=Ποιες επιπλέον ενέργειες θέλετε να γίνουν;
SelectTasksLabel2=Επιλέξτε τις επιπλέον ενέργειες που θέλετε να γίνουν κατά την εγκατάσταση του [name] και πατήστε Επόμενο.
; *** "Select Start Menu Folder" wizard page
WizardSelectProgramGroup=Επιλογή Φακέλου Μενού Έναρξης
SelectStartMenuFolderDesc=Πού θέλετε να τοποθετηθούν οι συντομεύσεις του προγράμματος;
SelectStartMenuFolderLabel3=Η εγκατάσταση θα δημιουργήσει τις συντομεύσεις του προγράμματος στον ακόλουθο φάκελο του μενού Έναρξη.
SelectStartMenuFolderBrowseLabel=Για να συνεχίσετε, πατήστε Επόμενο. Αν θέλετε διαφορετικό φάκελο, πατήστε Αναζήτηση.
MustEnterGroupName=Πρέπει να εισαγάγετε ένα όνομα φακέλου.
GroupNameTooLong=Το όνομα ή η διαδρομή του φακέλου είναι πολύ μεγάλη.
InvalidGroupName=Το όνομα του φακέλου δεν είναι έγκυρο.
BadGroupName=Το όνομα του φακέλου δεν μπορεί να περιλαμβάνει κανέναν από τους παρακάτω χαρακτήρες:%n%n%1
NoProgramGroupCheck2=&Χωρίς δημιουργία φακέλου στο μενού Έναρξης.
; *** "Ready to Install" wizard page
WizardReady=Έτοιμα για Εγκατάσταση
ReadyLabel1=Ο Οδηγός Εγκατάστασης είναι έτοιμος να ξεκινήσει την εγκατάσταση του [name] στον υπολογιστή σας.
ReadyLabel2a=Πατήστε Εγκατάσταση για να συνεχίσετε με την εγκατάσταση ή πατήστε Πίσω, εάν θέλετε να ελέγξετε ή να αλλάξετε τυχόν ρυθμίσεις.
ReadyLabel2b=Πατήστε Εγκατάσταση για να συνεχίσετε την εγκατάσταση.
ReadyMemoUserInfo=Πληροφορίες Χρήστη:
ReadyMemoDir=Φάκελος προορισμού:
ReadyMemoType=Είδος εγκατάστασης:
ReadyMemoComponents=Επιλεγμένες λειτουργικές μονάδες:
ReadyMemoGroup=Φάκελος στο μενού Έναρξη:
ReadyMemoTasks=Επιπλέον ενέργειες:
; *** TDownloadWizardPage wizard page and DownloadTemporaryFile
DownloadingLabel=Λήψη πρόσθετων αρχείων...
ButtonStopDownload=&Διακοπή λήψης
StopDownload=Είστε βέβαιοι ότι θέλετε να διακόψετε τη λήψη;
ErrorDownloadAborted=Η λήψη ακυρώθηκε
ErrorDownloadFailed=Η λήψη απέτυχε: %1 %2
ErrorDownloadSizeFailed=Η λήψη του μεγέθους απέτυχε: %1 %2
ErrorFileHash1=Αποτυχία υπολογισμού hash: %1
ErrorFileHash2=Μη έγκυρο hash: αναμενόμενο %1, βρέθηκε %2
ErrorProgress=Μη έγκυρη πρόοδος: %1 από %2
ErrorFileSize=Μη έγκυρο μέγεθος αρχείου: αναμενόμενο %1, βρέθηκε %2
; *** "Preparing to Install" wizard page
WizardPreparing=Προετοιμασία Εγκατάστασης
PreparingDesc=Ο Οδηγός Εγκατάστασης προετοιμάζεται για την εγκατάσταση του [name] στον υπολογιστή σας.
PreviousInstallNotCompleted=Η εγκατάσταση/αφαίρεση ενός προηγούμενου προγράμματος δεν ολοκληρώθηκε. Θα χρειαστεί να κάνετε επανεκκίνηση του υπολογιστή σας για να ολοκληρωθεί.%n%nΜετά την επανεκκίνηση του υπολογιστή σας, εκτελέστε ξανά τον Οδηγό Εγκατάστασης για να ολοκληρώσετε την εγκατάσταση/αφαίρεση του [name].
CannotContinue=Η εγκατάσταση δεν μπορεί να συνεχιστεί. Παρακαλώ πατήστε Άκυρο για τερματισμό.
ApplicationsFound=Οι ακόλουθες εφαρμογές χρησιμοποιούν αρχεία που πρέπει να ενημερωθούν από τον Οδηγό Εγκατάστασης. Συνιστάται να επιτρέψετε στον Οδηγό Εγκατάστασης να κλείσει αυτόματα αυτές τις εφαρμογές.
ApplicationsFound2=Οι ακόλουθες εφαρμογές χρησιμοποιούν αρχεία που πρέπει να ενημερωθούν από τον Οδηγό Εγκατάστασης. Συνιστάται να επιτρέψετε στον Οδηγό Εγκατάστασης να κλείσει αυτόματα αυτές τις εφαρμογές. Μετά την ολοκλήρωση της εγκατάστασης, ο Οδηγός Εγκατάστασης θα επιχειρήσει να κάνει επανεκκίνηση των εφαρμογών.
CloseApplications=&Αυτόματο κλείσιμο των εφαρμογών
DontCloseApplications=&Χωρίς κλείσιμο των εφαρμογών
ErrorCloseApplications=Ο Οδηγός Εγκατάστασης δεν μπόρεσε να κλείσει αυτόματα όλες τις εφαρμογές. Συνιστάται να κλείσετε όλες τις εφαρμογές που χρησιμοποιούν αρχεία που πρέπει να ενημερωθούν από τον Οδηγό Εγκατάστασης προτού συνεχίσετε.
PrepareToInstallNeedsRestart=Ο Οδηγός Εγκατάστασης πρέπει να κάνει επανεκκίνηση του υπολογιστή σας. Μετά την επανεκκίνηση του υπολογιστή σας, εκτελέστε ξανά τον Οδηγό Εγκατάστασης για να ολοκληρώσετε την εγκατάσταση του [name].%n%nΘα θέλατε να κάνετε επανεκκίνηση τώρα;
; *** "Installing" wizard page
WizardInstalling=Εγκατάσταση
InstallingLabel=Παρακαλώ περιμένετε καθώς γίνεται η εγκατάσταση του [name] στον υπολογιστή σας.
; *** "Setup Completed" wizard page
FinishedHeadingLabel=Ολοκλήρωση του Οδηγού Εγκατάστασης του [name]
FinishedLabelNoIcons=Ο Οδηγός Εγκατάστασης ολοκλήρωσε την εγκατάσταση του [name] στον υπολογιστή σας.
FinishedLabel=Ο Οδηγός Εγκατάστασης ολοκλήρωσε την εγκατάσταση του [name] στον υπολογιστή σας. Η εφαρμογή μπορεί να ξεκινήσει επιλέγοντας κάποια από τις εγκατεστημένες συντομεύσεις.
ClickFinish=Πατήστε Τέλος για να τερματίσετε τον Οδηγό Εγκατάστασης.
FinishedRestartLabel=Για να ολοκληρώσετε την εγκατάσταση του [name], ο Οδηγός Εγκατάστασης πρέπει να κάνει επανεκκίνηση του υπολογιστή σας. Θα θέλατε να κάνετε επανεκκίνηση τώρα;
FinishedRestartMessage=Για να ολοκληρώσετε την εγκατάσταση του [name], ο Οδηγός Εγκατάστασης πρέπει να κάνει επανεκκίνηση του υπολογιστή σας.%n%nΘα θέλατε να κάνετε επανεκκίνηση τώρα;
ShowReadmeCheck=Ναι, θα ήθελα να δω το αρχείο README
YesRadio=&Ναι, να γίνει επανεκκίνηση τώρα
NoRadio=&Οχι, θα κάνω επανεκκίνηση αργότερα
; used for example as 'Run MyProg.exe'
RunEntryExec=Εκτέλεση του %1
; used for example as 'View Readme.txt'
RunEntryShellExec=Προβολή του %1
; *** "Setup Needs the Next Disk" stuff
ChangeDiskTitle=Ο Οδηγός Εγκατάστασης χρειάζεται τον επόμενο δίσκο
SelectDiskLabel2=Παρακαλώ, εισάγετε τον δίσκο %1 και πατήστε ΟΚ.%n%nΕάν τα αρχεία αυτού του δίσκου βρίσκονται σε φάκελο διαφορετικό από αυτόν που εμφανίζεται παρακάτω, πληκτρολογήστε τη σωστή διαδρομή ή πατήστε Αναζήτηση.
PathLabel=&Διαδρομή:
FileNotInDir2=Το αρχείο "%1" δε βρέθηκε στο "%2". Παρακαλώ εισάγετε το σωστό δίσκο ή επιλέξτε κάποιον άλλο φάκελο.
SelectDirectoryLabel=Παρακαλώ καθορίσετε την τοποθεσία του επόμενου δίσκου.
; *** Installation phase messages
SetupAborted=Η εγκατάσταση δεν ολοκληρώθηκε.%n%nΠαρακαλώ, διορθώστε το πρόβλημα και εκτελέστε ξανά τον Οδηγό Εγκατάστασης.
AbortRetryIgnoreSelectAction=Επιλέξτε ενέργεια
AbortRetryIgnoreRetry=&Δοκιμή
AbortRetryIgnoreIgnore=&Αγνόηση και συνέχεια
AbortRetryIgnoreCancel=Ακυρώση εγκατάστασης
; *** Installation status messages
StatusClosingApplications=Κλείσιμο εφαρμογών...
StatusCreateDirs=Δημιουργία φακέλων...
StatusExtractFiles=Αποσυμπίεση αρχείων...
StatusCreateIcons=Δημιουργία συντομεύσεων...
StatusCreateIniEntries=Δημιουργία καταχωρήσεων INI...
StatusCreateRegistryEntries=Δημιουργία καταχωρήσεων στο μητρώο...
StatusRegisterFiles=Καταχώρηση αρχείων...
StatusSavingUninstall=Αποθήκευση πληροφοριών απεγκατάστασης...
StatusRunProgram=Ολοκλήρωση εγκατάστασης...
StatusRestartingApplications=Επανεκκίνηση εφαρμογών...
StatusRollback=Επαναφορά αλλαγών...
; *** Misc. errors
ErrorInternal2=Εσωτερικό σφάλμα: %1
ErrorFunctionFailedNoCode=%1 απέτυχε
ErrorFunctionFailed=%1 απέτυχε, κωδικός %2
ErrorFunctionFailedWithMessage=%1 απέτυχε, κωδικός %2.%n%3
ErrorExecutingProgram=Δεν είναι δυνατή η εκτέλεση του αρχείου:%n%1
; *** Registry errors
ErrorRegOpenKey=Σφάλμα ανάγνωσης κλειδιού μητρώου:%n%1\%2
ErrorRegCreateKey=Σφάλμα δημιουργίας κλειδιού μητρώου:%n%1\%2
ErrorRegWriteKey=Σφάλμα καταχώρησης κλειδιού μητρώου:%n%1\%2
; *** INI errors
ErrorIniEntry=Σφάλμα στη δημιουργία καταχώρησης INI στο αρχείο "%1".
; *** File copying errors
FileAbortRetryIgnoreSkipNotRecommended=&Παράλειψη αυτού του αρχείου (δεν συνιστάται)
FileAbortRetryIgnoreIgnoreNotRecommended=Παράλειψη σφάλματος και &συνέχεια (δεν συνιστάται)
SourceIsCorrupted=Το αρχείο προέλευσης είναι κατεστραμμένο
SourceDoesntExist=Το αρχείο προέλευσης "%1" δεν υπάρχει
ExistingFileReadOnly2=Το υπάρχον αρχείο δεν μπόρεσε να αντικατασταθεί επειδή είναι μόνο για ανάγνωση.
ExistingFileReadOnlyRetry=&Καταργήστε το χαρακτηριστικό μόνο για ανάγνωση και δοκιμάστε ξανά
ExistingFileReadOnlyKeepExisting=&Διατηρήστε το υπάρχον αρχείο
ErrorReadingExistingDest=Παρουσιάστηκε σφάλμα κατά την προσπάθεια ανάγνωσης του υπάρχοντος αρχείου:
FileExistsSelectAction=Επιλέξτε ενέργεια
FileExists2=Το αρχείο υπάρχει ήδη.
FileExistsOverwriteExisting=&Αντικατάσταση υπάρχοντος αρχείου
FileExistsKeepExisting=&Διατήρηση υπάρχοντος αρχείου
FileExistsOverwriteOrKeepAll=&Να γίνει το ίδιο για τις επόμενες διενέξεις
ExistingFileNewerSelectAction=Επιλέξτε ενέργεια
ExistingFileNewer2=Το υπάρχον αρχείο είναι νεότερο από αυτό που προσπαθεί να εγκαταστήσει ο Οδηγός Εγκατάστασης.
ExistingFileNewerOverwriteExisting=&Αντικατάσταση υπάρχοντος αρχείου
ExistingFileNewerKeepExisting=&Διατήρηση υπάρχοντος αρχείου (συνιστάται)
ExistingFileNewerOverwriteOrKeepAll=&Να γίνει το ίδιο για τις επόμενες διενέξεις
ErrorChangingAttr=Παρουσιάστηκε σφάλμα κατά την προσπάθεια αλλαγής των χαρακτηριστικών του υπάρχοντος αρχείου:
ErrorCreatingTemp=Παρουσιάστηκε σφάλμα κατά την προσπάθεια δημιουργίας ενός αρχείου στον φακέλο προορισμού:
ErrorReadingSource=Παρουσιάστηκε σφάλμα κατά την προσπάθεια ανάγνωσης του αρχείου προέλευσης:
ErrorCopying=Παρουσιάστηκε σφάλμα κατά την προσπάθεια αντιγραφής ενός αρχείου:
ErrorReplacingExistingFile=Παρουσιάστηκε σφάλμα κατά την προσπάθεια αντικατάστασης του υπάρχοντος αρχείου:
ErrorRestartReplace=Η ΕπανεκκίνησηΑντικατάσταση απέτυχε:
ErrorRenamingTemp=Παρουσιάστηκε σφάλμα κατά την προσπάθεια μετονομασίας ενός αρχείου στον φακέλο προορισμού:
ErrorRegisterServer=Δεν είναι δυνατή η καταχώριση του DLL/OCX: %1
ErrorRegSvr32Failed=Το RegSvr32 απέτυχε με κωδικό εξόδου %1
ErrorRegisterTypeLib=Δεν είναι δυνατή η καταχώριση της βιβλιοθήκης τύπων: %1
; *** Uninstall display name markings
; used for example as 'My Program (32-bit)'
UninstallDisplayNameMark=%1 (%2)
; used for example as 'My Program (32-bit, All users)'
UninstallDisplayNameMarks=%1 (%2, %3)
UninstallDisplayNameMark32Bit=32-bit
UninstallDisplayNameMark64Bit=64-bit
UninstallDisplayNameMarkAllUsers=Ολοι οι χρήστες
UninstallDisplayNameMarkCurrentUser=Τρέχων χρήστης
; *** Post-installation errors
ErrorOpeningReadme=Παρουσιάστηκε σφάλμα κατά την προσπάθεια ανοίγματος του αρχείου README.
ErrorRestartingComputer=Ο Οδηγός Εγκατάστασης δεν μπόρεσε να κάνει επανεκκίνηση του υπολογιστή. Παρακαλώ επανεκκινήσετε τον υπολογιστή μόνοι σας.
; *** Uninstaller messages
UninstallNotFound=Το αρχείο "%1" δεν υπάρχει. Δεν είναι δυνατή η απεγκατάσταση.
UninstallOpenError=Το αρχείο "%1" δεν ήταν δυνατό να ανοίξει. Δεν είναι δυνατή η απεγκατάσταση
UninstallUnsupportedVer=Το αρχείο καταγραφής απεγκατάστασης "%1" είναι σε μορφή που δεν αναγνωρίζεται από αυτήν την έκδοση του Οδηγού Απεγκατάστασης. Δεν ήταν δυνατή η απεγκατάσταση
UninstallUnknownEntry=Μια άγνωστη καταχώρηση (%1) εντοπίστηκε στο αρχείο καταγραφής απεγκατάστασης
ConfirmUninstall=Είστε βέβαιοι ότι θέλετε να καταργήσετε εντελώς το %1 και όλα τα στοιχεία του;
UninstallOnlyOnWin64=Αυτή η εγκατάσταση μπορεί να απεγκατασταθεί μόνο σε Windows 64-bit.
OnlyAdminCanUninstall=Αυτή η εγκατάσταση μπορεί να απεγκατασταθεί μόνο από χρήστη με δικαιώματα διαχειριστή.
UninstallStatusLabel=Παρακαλώ περιμένετε μέχρι να καταργηθεί το %1 από τον υπολογιστή σας.
UninstalledAll=Το %1 αφαιρέθηκε με επιτυχία από τον υπολογιστή σας.
UninstalledMost=Το %1 αφαιρέθηκε με επιτυχία.%n%nΟρισμένα στοιχεία δεν ήταν δυνατό να καταργηθούν. Αυτά μπορούν να αφαιρεθούν από εσάς.
UninstalledAndNeedsRestart=Για να ολοκληρώσετε την απεγκατάσταση του %1, ο υπολογιστής σας πρέπει να επανεκκινηθεί.%n%nΘα θέλατε να κάνετε επανεκκίνηση τώρα;
UninstallDataCorrupted=Το "%1" αρχείο είναι κατεστραμμένο. Δεν ήταν δυνατή η απεγκατάσταση
; *** Uninstallation phase messages
ConfirmDeleteSharedFileTitle=Κατάργηση Κοινόχρηστου Αρχείου;
ConfirmDeleteSharedFile2=Το σύστημα υποδεικνύει ότι το ακόλουθο κοινόχρηστο αρχείο δεν χρησιμοποιείται πλέον από κανένα πρόγραμμα. Θέλετε να καταργηθεί αυτό το κοινόχρηστο αρχείο;%n%nΕάν κάποιο πρόγραμμα εξακολουθεί να το χρησιμοποιεί, ενδέχεται να μην λειτουργήσει σωστά. Εάν δεν είστε βέβαιοι, επιλέξτε Όχι. Αφήνοντάς το στο σύστημά σας δεν θα προκληθεί καμία ζημιά.
SharedFileNameLabel=Όνομα Αρχείου:
SharedFileLocationLabel=Τοποθεσία:
WizardUninstalling=Πρόοδος Απεγκατάστασης
StatusUninstalling=Απεγκατάσταση %1...
; *** Shutdown block reasons
ShutdownBlockReasonInstallingApp=Εγκατάσταση του %1.
ShutdownBlockReasonUninstallingApp=Απεγκατάσταση του %1.
; The custom messages below aren't used by Setup itself, but if you make
; use of them in your scripts, you'll want to translate them.
[CustomMessages]
NameAndVersion=%1 έκδοση %2
AdditionalIcons=Επιπλέον συντομεύσεις:
CreateDesktopIcon=Δημιουργία συντόμευσης στην &επιφάνεια εργασίας
CreateQuickLaunchIcon=Δημιουργία συντόμευσης στη &Γρήγορη Εκκίνηση
ProgramOnTheWeb=Το %1 στο Internet
UninstallProgram=Απεγκατάσταση του %1
LaunchProgram=Εκκίνηση του %1
AssocFileExtension=&Συσχέτιση του %1 με την επέκταση αρχείου %2
AssocingFileExtension=Γίνεται συσχέτιση του %1 με την επέκταση αρχείου "%2"...
AutoStartProgramGroupDescription=Εκκίνηση:
AutoStartProgram=Αυτόματη εκκίνηση του %1
AddonHostProgramNotFound=Το %1 δε βρέθηκε στο φάκελο που επιλέξατε.%n%nΘέλετε να συνεχίσετε παρόλα αυτά;
================================================
FILE: InnoDependencies/Latvian.isl
================================================
; *** Inno Setup version 6.1.0+ Latvian messages ***
;
; Translated from English by Zorgaats, zorgaats@gmail.com
;
; Note: When translating this text, do not add periods (.) to the end of
; messages that didn't have them already, because on those messages Inno
; Setup adds the periods automatically (appending a period would result in
; two periods being displayed).
[LangOptions]
LanguageName=Latviski
LanguageID=$0426
LanguageCodePage=1257
[Messages]
; *** Application titles
SetupAppTitle=Uzstādīšana
SetupWindowTitle=Uzstādīšana — %1
UninstallAppTitle=Noņemšana
UninstallAppFullTitle=Noņemšana — %
; *** Misc. common
InformationTitle=Informācija
ConfirmTitle=Apstiprināt
ErrorTitle=Kļūda
; *** SetupLdr messages
SetupLdrStartupMessage=Tiks uzstādīta programma %1 uz Jūsu datora. Vai vēlaties turpināt?
LdrCannotCreateTemp=Neiespējami izveidot pagaidu datnes. Uzstādīšana pārtraukta
LdrCannotExecTemp=Neiespējami palaist datni no pagaidu mapes. Uzstādīšana pārtraukta
HelpTextNote=
; *** Startup error messages
LastErrorMessage=%1.%n%nKļūda %2: %3
SetupFileMissing=Datne %1 nav atrodama uzstādīšanas mapē. Lūdzu izlabojiet kļūdu vai iegādājaties jaunu programmas kopiju.
SetupFileCorrupt=Uzstādīšanas datnes ir bojātas. Lūdzu iegādājaties jaunu programmas kopiju.
SetupFileCorruptOrWrongVer=Uzstādīšanas datnes ir bojātas vai nav savienojamas ar šo uzstādīšanas programmu. Lūdzu izlabojiet kļūdu vai iegādājaties jaunu programmas kopiju.
InvalidParameter=Komandrinda satur nepieļaujamu parametru:%n%n%1
SetupAlreadyRunning=Uzstādīšanas programma jau ir palaista.
WindowsVersionNotSupported=Šī programma neatbalsta Windows versiju, kas uzstādīta uz šī datora.
WindowsServicePackRequired=Programma pieprasa %1 Service Pack %2 vai jaunāku versiju.
NotOnThisPlatform=Šī pragramma nevar darboties uz %1.
OnlyOnThisPlatform=Programmu var palaist tikai uz %1.
OnlyOnTheseArchitectures=Programmu var uzstādīt tikai uz Windows versijas ar šādu procesoru arhitektūru:%n%n%1
WinVersionTooLowError=Programma pieprasa %1 versiju %2 vai jaunāku.
WinVersionTooHighError=Programmu nevar uzstādīt uz %1 versijas %2 vai jaunākas.
AdminPrivilegesRequired=Jums ir jābūt administratoram, lai varētu uzsākt uzstādīšanu.
PowerUserPrivilegesRequired=Jums ir jābūt administratoram vai pilnvarotam lietotājam, lai uzstādītu šo programmu.
SetupAppRunningError=Ir atrasts palaists eksemplārs %1.%n%nLūdzu,aizveriet visas programmas un spiediet "Ok" lai turpinātu vai "Atcelt", lai izietu.
UninstallAppRunningError=Noņemšana ir atklājusi, ka darbojas eksemplārs %1.%n%nLūdzu,aizveriet visas programmas un spiediet "Ok" lai turpinātu vai "Atcelt", lai izietu.
; *** Startup questions
PrivilegesRequiredOverrideTitle=Uzstādīšanas režīma izvēle
PrivilegesRequiredOverrideInstruction=Izvēlieties uzstādīšanas režīmu
PrivilegesRequiredOverrideText1=%1 var tikt uzstādīts vai nu visiem lietotājiem (nepieciešamas administratora privilēģijas), vai arī tikai Jums.
PrivilegesRequiredOverrideText2=%1 var tikt uzstādīts vai nu tikai Jums, vai arī visiem lietotājiem (nepieciešamas administratora privilēģijas).
PrivilegesRequiredOverrideAllUsers=Uzstādīt &visiem lietotājiem
PrivilegesRequiredOverrideAllUsersRecommended=Uzstādīt &visiem lietotājiem (rekomendējas)
PrivilegesRequiredOverrideCurrentUser=Uzstādīt tikai &man
PrivilegesRequiredOverrideCurrentUserRecommended=Uzstādīt tikai &man (rekomendējas)
; *** Misc. errors
ErrorCreatingDir=Nevar izveidot mapi "%1"
ErrorTooManyFilesInDir=Neiespējami izveidot datnes mapē "%1", jo tā satur pārāk daudz datņu
; *** Setup common messages
ExitSetupTitle=Iziet no uzstādīšanas
ExitSetupMessage=Uzstādīšana nav pabeigta. Ja Jūs tagad iziesiet, programma netiks uzstādīta.%n%nLai uzstādītu programmu, Jums būs atkal jāpalaiž uzstādīšana. %n%nIziet no uzstādīšanas?
AboutSetupMenuItem=&Par uzstādīšanu...
AboutSetupTitle=Par uzstādīšanu
AboutSetupMessage=%1, varsija %2%n%3%n%n%1mājas lapa:%n%4
AboutSetupNote=
TranslatorNote=Latvian translation by Zorgaats
; *** Buttons
ButtonBack=< &Atpakaļ
ButtonNext=&Tālāk >
ButtonInstall=&Uzstādīt
ButtonOK=OK
ButtonCancel=Atcelt
ButtonYes=&Jā
ButtonYesToAll=Jā &Visam
ButtonNo=&Nē
ButtonNoToAll=Nē V&isam
ButtonFinish=&Pabeigt
ButtonBrowse=Pā&rlūkot...
ButtonWizardBrowse=Pārlū&kot...
ButtonNewFolder=I&zveidot jaunu mapi
; *** "Select Language" dialog messages
SelectLanguageTitle=Izvēlieties uzstādīšanas valodu
SelectLanguageLabel=Izvēlieties valodu, kurā notiks uzstādīšana:
; *** Common wizard text
ClickNext=Spiediet "Tālāk", lai turpinātu, vai "Atcelt", lai izietu no uzstādīšanas.
BeveledLabel=
BrowseDialogTitle=Pārlūkot mapi
BrowseDialogLabel=Izvēlieties mapi no saraksta, tad spiediet "Ok".
NewFolderName=Jauna mape
; *** "Welcome" wizard page
WelcomeLabel1=Вас приветствует Мастер установки [name]
WelcomeLabel2=Programma uzstādīs [name/ver] uz Jūsu datora.%n%nPirms uzstādīšanas vēlams aizvērt visas programmas.
; *** "Password" wizard page
WizardPassword=Parole
PasswordLabel1=Uzstādīšana ir aizsargāta ar paroli.
PasswordLabel3=Lūdzu, ievadiet paroli, tad spiediet "Tālāk", lai turpinātu. Parole ir reģistrjūtīga.
PasswordEditLabel=&Parole:
IncorrectPassword=Jūsu ievadītā parole ir nepareiza. Lūdzu, mēģiniet vēlreiz.
; *** "License Agreement" wizard page
WizardLicense=Licence
LicenseLabel=Lūdzu, izlasiet sekojošo informāciju, pirms turpināt.
LicenseLabel3=Lūdzu, izlasiet Līgumu. Jums ir jāapstiprina Līgums, lai turpinātu uzstādīšanu.
LicenseAccepted=Es &piekrītu līgumam
LicenseNotAccepted=Es &nepiekrītu līgumam
; *** "Information" wizard pages
WizardInfoBefore=Informācija
InfoBeforeLabel=Lūdzu, izlasiet šo informāciju.
InfoBeforeClickLabel=Kad esat gatavs turpināt uzstādīšanu, spiediet "Tālāk".
WizardInfoAfter=Informācija
InfoAfterLabel=Lūdzu, izlasiet šo informāciju.
InfoAfterClickLabel=Kad esat gatavs turpināt uzstādīšanu, spiediet "Tālāk".
; *** "User Information" wizard page
WizardUserInfo=Lietotāja informācija
UserInfoDesc=Lūdzu, ievadiet datus par sevi.
UserInfoName=&Lietotāja vārds:
UserInfoOrg=&Organizācija:
UserInfoSerial=&Sērijas numurs:
UserInfoNameRequired=Jums ir jāievada savs vārds.
; *** "Select Destination Location" wizard page
WizardSelectDir=Uzstādīšanas mapes izvēle
SelectDirDesc=Kur [name] tiks instalēts?
SelectDirLabel3=[name] datnes tiks instalētas norādītajā mapē.
SelectDirBrowseLabel=Lai turpinātu, spiediet "Tālāk". Ja vēlaties norādīt citu mapi, spiediet "Pārlūkot".
DiskSpaceGBLabel=Ir nepieciešami brīvi [gb] GB uz cietā diska.
DiskSpaceMBLabel=Ir nepieciešami brīvi [mb] MB uz cietā diska.
CannotInstallToNetworkDrive=Uzstādīšana nevar tikt veikta uz tīkla diska.
CannotInstallToUNCPath=Uzstādīšana nevar tikt veikta mapē pa UNC-adresi.
InvalidPath=Jums ir jānorāda pilna uzstādīšanas adrese, piemērs:%n%nC:\APP%n%nvai UNC adrese:%n%n\\server\share
InvalidDrive=Disks vai tīkla adrese, kuru Jūs izvēlējāties, nepastāv vai arī nav pieejams. Lūdzu, izvēlieties citu.
DiskSpaceWarningTitle=Nepietiek vietas uz diska
DiskSpaceWarning=Uzstādīšanai ir nepieciešami vismaz %1 KB brīvas vietas uz diska, bet pieejami ir tikai %2 KB.%n%nVai vēlaties turpināt?
DirNameTooLong=Mapes nosaukums vai adrese ir pārāk gara.
InvalidDirName=Mapes nosaukums nav derīgs.
BadDirName32=Mapes nosaukumā nedrīkst būt šādi simboli: %n%n%1
DirExistsTitle=Mape jau pastāv.
DirExists=Mape:%n%n%1%n%njau pastāv. Vai vienalga vēlaties turpināt?
DirDoesntExistTitle=Mape nepastāv
DirDoesntExist=Mape%n%n%1%n%nnepastāv. Vai vēlaties to izveidot?
; *** "Select Components" wizard page
WizardSelectComponents=Izvēlieties sastāvdaļas
SelectComponentsDesc=Kurus komponentus vēlaties uzstādīt?
SelectComponentsLabel2=Izvēlieties komponentus, kurus vēlaties uzstādīt. Spiediet "Tālāk", lai turpinātu.
FullInstallation=Pilna uzstādīšana
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
CompactInstallation=Kompakta uzstādīšana
CustomInstallation=Izveidot uzstādīšanu
NoUninstallWarningTitle=Komponenti jau pastāv
NoUninstallWarning=Uzstādīšana ir atklājusi, ka šādi komponenti jau ir uzstādīti:%n%n%1%n%nŠo komponentu uzstādīšanas atcelšana neizdzēsīs tos.%n%nVai turpināt?
ComponentSize1=%1 Кб
ComponentSize2=%1 Мб
ComponentsDiskSpaceGBLabel=Pašlaik izvēlētie komponenti aizņem [gb] GB uz cietā diska.
ComponentsDiskSpaceMBLabel=Pašlaik izvēlētie komponenti aizņem [mb] MB uz cietā diska.
; *** "Select Additional Tasks" wizard page
WizardSelectTasks=Papilduzdevumu izvēlne
SelectTasksDesc=Kurus papilduzdevumus vajadzētu veikt?
SelectTasksLabel2=Izvēlieties, kādi papilduzdevumi tiks veikti [name] uzstādīšanas laikā, tad spiediet "Tālāk".
; *** "Select Start Menu Folder" wizard page
WizardSelectProgramGroup=Izvēlieties Start Menu mapi
SelectStartMenuFolderDesc=Kur uzstādīšanas programmai vajadzētu likt īsinājumikonas?
SelectStartMenuFolderLabel3=Uzstādīšana izveidos īsinājumikonas Start Menu mapē.
SelectStartMenuFolderBrowseLabel=Lai turpinātu, spiediet "Tālāk". Ja vēlaties norādīt citu mapi, spiediet "Pārlūkot".
MustEnterGroupName=Jums ir jānorāda mape.
GroupNameTooLong=Mapes nosaukums ir pārāk garš.
InvalidGroupName=Mape nav derīga.
BadGroupName=Mapes nosaukums satur kādu no šiem simboliem:%n%n%1
NoProgramGroupCheck2=&Neizveidot Start Menu mapi
; *** "Ready to Install" wizard page
WizardReady=Gatavs uzstādīšanai
ReadyLabel1=Uzstādīšana ir gatava instalēt [name] uz Jūsu datora.
ReadyLabel2a=Spiediet "Uzstādīt", lai sāktu uzstādīšanu, vai spiediet "Atpakaļ", lai izmainītu parametrus.
ReadyLabel2b=Spiediet "Uzstādīt", lai sāktu uzstādīšanu.
ReadyMemoUserInfo=Lietotāja informācija:
ReadyMemoDir=Galamēķis:
ReadyMemoType=Uzstādīšanas tips:
ReadyMemoComponents=Izvēlētie komponenti:
ReadyMemoGroup=Start Menu mape:
ReadyMemoTasks=Papilduzdevumi:
; *** TDownloadWizardPage wizard page and DownloadTemporaryFile
DownloadingLabel=Papildus datņu lejupielāde...
ButtonStopDownload=&Pārtraukt ielādi
StopDownload=Jūs tiešām vēlaties pārtraukt lejupielādi?
ErrorDownloadAborted=Lejupielāde pārtraukta
ErrorDownloadFailed=Lejupielādes kļūda: %1 %2
ErrorDownloadSizeFailed=Izmēra kļūda: %1 %2
ErrorFileHash1=Ошибка хэша файла: %1
ErrorFileHash2=Неверный хэш файла: ожидался %1, получен %2
ErrorProgress=Izpildes kļūda: %1 из %2
ErrorFileSize=Kļūdains faila izmērs: tika gaidīts %1, iegūts %2
; *** "Preparing to Install" wizard page
WizardPreparing=Gatavoties uzstādīšanai
PreparingDesc=Uzstādīšana ir gatava instalēt [name] uz Jūsu datora.
PreviousInstallNotCompleted=Uzstādīšana/noņemšana iepriekšējai programmai nav pabeigta. Jums ir jāpārstartē dators, lai pabeigtu uzstādīšanu.%n%nPēc pārstartēšanas palaidiet uzstādīšanu no jauna, lai pabeigtu uzstādīt [name].
CannotContinue=Uzstādīšanu nevar turpināt. Lūdzu, spiediet "Atcelt", lai izietu.
ApplicationsFound=Sekojošas programmas izmanto datnes, kuras uzstādīšanai jāatjauno. Rekomendējas uzstādīšanai atļaut automātiski aizvērt šīs programmas.
ApplicationsFound2=Sekojošas programmas izmanto datnes, kuras uzstādīšanai jāatjauno. Rekomendējas uzstādīšanai atļaut automātiski aizvērt šīs programmas. Kad instalācija būs pabeigta, uzstādīšana mēģinās tās atkal palaist.
CloseApplications=&Automātiski aizvērt šīs programmas
DontCloseApplications=&Neaizvērt šīs programmas
ErrorCloseApplications=Uzstādīšanai neizdevās automātiski aizvērt visas programmas.Pirms uzstādīšanas rekomendējas aizvērt visas programmas, kas izmanto atjaunināmās datnes.
PrepareToInstallNeedsRestart=Uzstādīšanai nepieciešams pārstartēt Jūsu datoru. Kad dators pārstartēsies, lūdzu, palaidiet uzstādīšanas programmu vēlreiz, lai pabeigtu uzstādīšanu [name].%n%nVeikt pārstartēšanu tūlīt?
; *** "Installing" wizard page
WizardInstalling=Uzstādīšana...
InstallingLabel=Lūdzu, uzgaidiet, kamēr [name] tiks uzstādīts uz Jūsu datora.
; *** "Setup Completed" wizard page
FinishedHeadingLabel=Pabeigta [name] uzstādīšana
FinishedLabelNoIcons=Uzstādīšana pabeigta.
FinishedLabel=Programma [name] ir uzstādīta uz Jūsu datora. Programmu var palaist, uzklikšķinot uz izveidotajām ikonām.
ClickFinish=Spiediet "Pabeigt", lai aizvērtu uzstādīšanu.
FinishedRestartLabel=Lai pabeigtu [name] uzstādīšanu, nepieciešams pārstartēt Jūsu datoru. Vai vēlaties to darīt tagad?
FinishedRestartMessage=Lai pabeigtu [name] uzstādīšanu, nepieciešams pārstartēt Jūsu datoru.%n%nVai vēlaties to darīt tagad?
ShowReadmeCheck=Jā, vēlos apskatīt README failu
YesRadio=&Jā, pārstartēt datoru tagad
NoRadio=&Nē, datoru pārstartēšu vēlāk
; used for example as 'Run MyProg.exe'
RunEntryExec=Palaist %1
; used for example as 'View Readme.txt'
RunEntryShellExec=Apskatīt %1
; *** "Setup Needs the Next Disk" stuff
ChangeDiskTitle=Uzstādīšanai ir nepieciešams nākamais disks
SelectDiskLabel2=Lūdzu, ielieciet %1 disku un spiediet "Ok".%n%nJa datne ir atrodama uz šī paša diska kādā citā mapē, norādiet tās atrašanās vietu vai spiediet "Pārlūkot", lai to norādītu.
PathLabel=&Ceļš:
FileNotInDir2=Datne "%1" neatrodas "%2". Lūdzu, ielieciet pareizo disku vai norādiet pareizo mapi.
SelectDirectoryLabel=Lūdzu, norādiet nākamā diska atrašanās vietu.
; *** Installation phase messages
SetupAborted=Uzstādīšana netika pabeigta.%n%nLūdzu, izlabojiet kļūdu un palaidiet uzstādīšanu no jauna.
AbortRetryIgnoreSelectAction=Izvēlieties darbību
AbortRetryIgnoreRetry=Mēģināt no &jauna
AbortRetryIgnoreIgnore=&Ignorēt kļūdu un turpināt
AbortRetryIgnoreCancel=Pārtraukt uzstādīšanu
; *** Installation status messages
StatusClosingApplications=Programmu aizvēršana...
StatusCreateDirs=Mapju izveidošana...
StatusExtractFiles=Datņu kopēšana...
StatusCreateIcons=Īsinājumikonu izveidošana...
StatusCreateIniEntries=Izveido INI ierakstu...
StatusCreateRegistryEntries=Izveido reģistra ierakstus...
StatusRegisterFiles=Reģistrē datnes...
StatusSavingUninstall=Saglabā noņemšanas datus...
StatusRunProgram=Pabeidz uzstādīšanu...
StatusRestartingApplications=Programmu restartēšana...
StatusRollback=Izmaiņu atiestatīšana...
; *** Misc. errors
ErrorInternal2=Iekšēja kļūda: %1
ErrorFunctionFailedNoCode=%1: cieta neveiksmi
ErrorFunctionFailed=%1: cieta neveiksmi; kods %2
ErrorFunctionFailedWithMessage=%1: cieta neveiksmi; kods %2.%n%3
ErrorExecutingProgram=Nespēju palaist failu:%n%1
; *** Registry errors
ErrorRegOpenKey=Kļūda, atverot reģistra atslēgu:%n%1\%2
ErrorRegCreateKey=Kļūda, izveidojot reģistra atslēgu:%n%1\%2
ErrorRegWriteKey=Kļūda, rakstot reģistra atslēgu:%n%1\%2
; *** INI errors
ErrorIniEntry=Kļūda, izveidojot INI ieraksta datni "%1".
; *** File copying errors
FileAbortRetryIgnoreSkipNotRecommended=I&zlaist šo failu (nerekomendējas)
FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorēt kļūdu un turpināt (nerekomendējas)
SourceIsCorrupted=Datnes avots ir bojāts
SourceDoesntExist=Datnes avots "%1" nepastāv
ExistingFileReadOnly2=Nevar aizstāt esošo failu, tā kā tas ir iezīmēts kā "read only".
ExistingFileReadOnlyRetry=&Dzēst atribūtu "read only" un atkārtot mēģinājumu
ExistingFileReadOnlyKeepExisting=&Paturēt esošo failu
ErrorReadingExistingDest=Kļūda, mēģinot lasīt pastāvošo failu:
FileExistsSelectAction=Izvēlieties darbību
FileExists2=Fails jau pastāv.
FileExistsOverwriteExisting=&Aizstāt esošo failu
FileExistsKeepExisting=&Saglabāt esošo failu
FileExistsOverwriteOrKeepAll=A&tkārtot darbību visiem turpmākajiem konfliktiem
ExistingFileNewerSelectAction=Izvēlieties darbību
ExistingFileNewer2=Esošais fails ir jaunāks nekā uzstādāmais.
ExistingFileNewerOverwriteExisting=&Aizstāt esošo failu
ExistingFileNewerKeepExisting=&Saglabāt esošo failu (rekomendējas)
ExistingFileNewerOverwriteOrKeepAll=A&tkārtot darbību visiem turpmākajiem konfliktiem
ErrorChangingAttr=Radusies kļūda, mēģinot nomainīt datnes īpašību:
ErrorCreatingTemp=Radusies kļūda, izveidojot datni galamērķa mapē:
ErrorReadingSource=Radusies kļūda, nolasot datni:
ErrorCopying=Radusies kļūda, pārkopējot datni:
ErrorReplacingExistingFile=Radusies kļūda, pārrakstot jau pastāvošo datni:
ErrorRestartReplace=Atkārtota aizstāšana cietusi neveiksmi:
ErrorRenamingTemp=Radusies kļūda, nomainot nosaukumu datnei galamērķa mapē:
ErrorRegisterServer=Neiespējami reģistrēt DLL/OCX: %1
ErrorRegSvr32Failed=Kļūda, palaižot RegSvr32, kods %1
ErrorRegisterTypeLib=Neiespējami reģistrēt tipa bibliotēku: %1
; *** Uninstall display name markings
UninstallDisplayNameMark=%1 (%2)
UninstallDisplayNameMarks=%1 (%2, %3)
UninstallDisplayNameMark32Bit=32 biti
UninstallDisplayNameMark64Bit=64 biti
UninstallDisplayNameMarkAllUsers=Visi lietotāji
UninstallDisplayNameMarkCurrentUser=Tekošais lietotājs
; *** Post-installation errors
ErrorOpeningReadme=Radusies kļūda, atverot README datni.
ErrorRestartingComputer=Uzstādīšana nevar pārstartēt datoru. Lūdzu, izdariet to manuāli.
; *** Uninstaller messages
UninstallNotFound=Datne "%1" nepastāv. Nevar noņemt.
UninstallOpenError=Datni "%1" nevar atvērt. Nevar noņemt
UninstallUnsupportedVer=Noņemšanas datne "%1" nav atpazīstama šai noņemšanas programmai. Nevar noņemt
UninstallUnknownEntry=Nezināms ieraksts (%1) izveidoja sadursmi ar noņemšanu
ConfirmUninstall=Vai esat pārliecināts, ka vēlaties pilnībā noņemt %1 un visus tā komponentus?
UninstallOnlyOnWin64=Noņemšanu var veikt tikai ar 64-bitu Windows.
OnlyAdminCanUninstall=Noņemšanu var veikt tikai lietotājs ar Adminstratora privilēģijām.
UninstallStatusLabel=Lūdzu uzgaidiet, kamēr %1 tiek noņemts no Jūsu datora.
UninstalledAll=%1 tika veiksmīgi noņemts no Jūsu datora.
UninstalledMost=%1 noņemšana pabeigta.%n%nDažus elementus nevarēja noņemt. Tos var noņemt manuāli.
UninstalledAndNeedsRestart=Lai pabeigtu %1 noņemšanu, Jūsu dators jāpārstartē.%n%nVai vēlaties to darīt tagad?
UninstallDataCorrupted="%1" datne ir bojāta. Nevar noņemt
; *** Uninstallation phase messages
ConfirmDeleteSharedFileTitle=Noņemt kopīgo datni?
ConfirmDeleteSharedFile2=Sistēma ir secinājusi, ka šī koplietošanas datne vairs netiks lietota. Vai vēlaties to noņemt?%n%nJa kāda cita programma izmanto šo datni, tad šī programma var strādāt nekorekti. Ja neesat drošs, izvēlieties "Nē". Atstājot šo datni, Jūsu datoram netiks nodarīti nekādi bojājumi.
SharedFileNameLabel=Faila nosaukums:
SharedFileLocationLabel=Atrašanās vieta:
WizardUninstalling=Noņemšanas statuss
StatusUninstalling=Noņem %1...
; *** Shutdown block reasons
ShutdownBlockReasonInstallingApp=%1 uzstādīšana.
ShutdownBlockReasonUninstallingApp=%1 noņemšana.
; The custom messages below aren't used by Setup itself, but if you make
; use of them in your scripts, you'll want to translate them.
[CustomMessages]
NameAndVersion=%1, versija %2
AdditionalIcons=Papildu ikonas:
CreateDesktopIcon=Izveidot &darbvisrmas ikonu
CreateQuickLaunchIcon=Izveidot &Quick Launch ikonu
ProgramOnTheWeb=%1 vietne Internetā
UninstallProgram=Noņemt %1
LaunchProgram=Palaist %1
AssocFileExtension=&Apvienot %1 ar %2 faila paplašinājumu
AssocingFileExtension=Apvieno %1 ar %2 faila paplašinājumu...
AutoStartProgramGroupDescription=Automātiskā palaišana:
AutoStartProgram=Automātiski palaist %1
AddonHostProgramNotFound=%1 nav atrasts Jūsu norādītajā mapē.%n%nTomēr turpināt?
================================================
FILE: InnoDependencies/Romanian.isl
================================================
; *** Inno Setup version 5.5.3+ Romanian messages ***
; Translator : Alexandru Bogdan Munteanu (muntealb@gmail.com)
;
; To download user-contributed translations of this file, go to:
; http://www.jrsoftware.org/files/istrans/
;
; Note: When translating this text, do not add periods (.) to the end of
; messages that didn't have them already, because on those messages Inno
; Setup adds the periods automatically (appending a period would result in
; two periods being displayed).
[LangOptions]
; The following three entries are very important. Be sure to read and
; understand the '[LangOptions] section' topic in the help file.
LanguageName=Rom<00E2>n<0103>
LanguageID=$0418
LanguageCodePage=1250
; If the language you are translating to requires special font faces or
; sizes, uncomment any of the following entries and change them accordingly.
;DialogFontName=
;DialogFontSize=8
;WelcomeFontName=Verdana
;WelcomeFontSize=12
;TitleFontName=Arial
;TitleFontSize=29
;CopyrightFontName=Arial
;CopyrightFontSize=8
[Messages]
; *** Application titles
SetupAppTitle=Instalare
SetupWindowTitle=Instalare - %1
UninstallAppTitle=Dezinstalare
UninstallAppFullTitle=Dezinstalare %1
; *** Misc. common
InformationTitle=Informaii
ConfirmTitle=Confirmare
ErrorTitle=Eroare
; *** SetupLdr messages
SetupLdrStartupMessage=Va fi instalat programul %1. Vrei s continui?
LdrCannotCreateTemp=Nu pot crea o fil temporar. Instalare abandonat
LdrCannotExecTemp=Nu pot executa o fil din dosarul temporar. Instalare abandonat
; *** Startup error messages
LastErrorMessage=%1.%n%nEroarea %2: %3
SetupFileMissing=Fila %1 lipsete din dosarul de instalare. Corecteaz problema sau folosete o alt copie a programului.
SetupFileCorrupt=Filele de instalare snt stricate (corupte). Folosete o alt copie a programului.
SetupFileCorruptOrWrongVer=Filele de instalare snt stricate (corupte) sau snt incompatibile cu aceast versiune a Instalatorului. Remediaz problema sau folosete o alt copie a programului.
InvalidParameter=Un parametru invalid a fost trecut ctre linia de comand:%n%n%1
SetupAlreadyRunning=Instalarea ruleaz deja.
WindowsVersionNotSupported=Acest program nu suport versiunea de Windows care ruleaz pe calculatorul tu.
WindowsServicePackRequired=Acest program necesit %1 Service Pack %2 sau mai nou.
NotOnThisPlatform=Acest program nu va rula pe %1.
OnlyOnThisPlatform=Acest program trebuie s ruleze pe %1.
OnlyOnTheseArchitectures=Acest program poate fi instalat doar pe versiuni de Windows proiectate pentru urmtoarele arhitecturi de procesor:%n%n%1
MissingWOW64APIs=Versiunea de Windows pe care o rulezi nu include funcionalitatea cerut de Instalator pentru a realiza o instalare pe 64-bii. Pentru a corecta problema, va trebui s instalezi Service Pack %1.
WinVersionTooLowError=Acest program necesit %1 versiunea %2 sau mai nou.
WinVersionTooHighError=Acest program nu poate fi instalat pe %1 versiunea %2 sau mai nou.
AdminPrivilegesRequired=Trebuie s fii logat ca Administrator pentru instalarea acestui program.
PowerUserPrivilegesRequired=Trebuie s fii logat ca Administrator sau ca Membru al Grupului de Utilizatori Pricepui ("Power Users") pentru a instala acest program.
SetupAppRunningError=Instalatorul a detectat c %1 ruleaz n acest moment.%n%nnchide toate instanele programului respectiv, apoi clicheaz OK pentru a continua sau Anuleaz pentru a abandona instalarea.
UninstallAppRunningError=Dezinstalatorul a detectat c %1 ruleaz n acest moment.%n%nnchide toate instanele programului respectiv, apoi clicheaz OK pentru a continua sau Anuleaz pentru a abandona dezinstalarea.
; *** Misc. errors
ErrorCreatingDir=Instalatorul nu a putut crea dosarul "%1"
ErrorTooManyFilesInDir=Nu pot crea o fil n dosarul "%1" din cauz c are deja prea multe file
; *** Setup common messages
ExitSetupTitle=Abandonarea Instalrii
ExitSetupMessage=Instalarea nu este terminat. Dac o abandonezi acum, programul nu va fi instalat.%n%nPoi s rulezi Instalatorul din nou alt dat pentru a termina instalarea.%n%nAbandonezi Instalarea?
AboutSetupMenuItem=&Despre Instalator...
AboutSetupTitle=Despre Instalator
AboutSetupMessage=%1 versiunea %2%n%3%n%n%1 sit:%n%4
AboutSetupNote=
TranslatorNote=
; *** Buttons
ButtonBack=< na&poi
ButtonNext=&Continu >
ButtonInstall=&Instaleaz
ButtonOK=OK
ButtonCancel=Anuleaz
ButtonYes=&Da
ButtonYesToAll=Da la &Tot
ButtonNo=&Nu
ButtonNoToAll=N&u la Tot
ButtonFinish=&Finalizeaz
ButtonBrowse=&Exploreaz...
ButtonWizardBrowse=Explo&reaz...
ButtonNewFolder=Creea&z Dosar Nou
; *** "Select Language" dialog messages
SelectLanguageTitle=Selectarea Limbii Instalatorului
SelectLanguageLabel=Selecteaz limba folosit pentru instalare:
; *** Common wizard text
ClickNext=Clicheaz pe Continu pentru a avansa cu instalarea sau pe Anuleaz pentru a o abandona.
BeveledLabel=
BrowseDialogTitle=Explorare dup Dosar
BrowseDialogLabel=Selecteaz un dosar din lista de mai jos, apoi clicheaz pe OK.
NewFolderName=Dosar Nou
; *** "Welcome" wizard page
WelcomeLabel1=Bun venit la Instalarea [name]
WelcomeLabel2=Programul [name/ver] va fi instalat pe calculator.%n%nEste recomandat s nchizi toate celelalte aplicaii nainte de a continua.
; *** "Password" wizard page
WizardPassword=Parol
PasswordLabel1=Aceast instalare este protejat prin parol.
PasswordLabel3=Completeaz parola, apoi clicheaz pe Continu pentru a merge mai departe. Tipul literelor din parol (Majuscule/minuscule) este luat n considerare.
PasswordEditLabel=&Parol:
IncorrectPassword=Parola pe care ai introdus-o nu este corect. Rencearc.
; *** "License Agreement" wizard page
WizardLicense=Acord de Liceniere
LicenseLabel=Citete informaiile urmtoare nainte de a continua, snt importante.
LicenseLabel3=Citete urmtorul Acord de Liceniere. Trebuie s accepi termenii acestui acord nainte de a continua instalarea.
LicenseAccepted=&Accept licena
LicenseNotAccepted=&Nu accept licena
; *** "Information" wizard pages
WizardInfoBefore=Informaii
InfoBeforeLabel=Citete informaiile urmtoare nainte de a continua, snt importante.
InfoBeforeClickLabel=Cnd eti gata de a trece la Instalare, clicheaz pe Continu.
WizardInfoAfter=Informaii
InfoAfterLabel=Citete informaiile urmtoare nainte de a continua, snt importante.
InfoAfterClickLabel=Cnd eti gata de a trece la Instalare, clicheaz pe Continu.
; *** "User Information" wizard page
WizardUserInfo=Informaii despre Utilizator
UserInfoDesc=Completeaz informaiile cerute.
UserInfoName=&Utilizator:
UserInfoOrg=&Organizaie:
UserInfoSerial=Numr de &Serie:
UserInfoNameRequired=Trebuie s introduci un nume.
; *** "Select Destination Location" wizard page
WizardSelectDir=Selectarea Locului de Destinaie
SelectDirDesc=Unde vrei s instalezi [name]?
SelectDirLabel3=Instalatorul va pune [name] n dosarul specificat mai jos.
SelectDirBrowseLabel=Pentru a avansa cu instalarea, clicheaz pe Continu. Dac vrei s selectezi un alt dosar, clicheaz pe Exploreaz.
DiskSpaceMBLabel=Este necesar un spaiu liber de stocare de cel puin [mb] MB.
CannotInstallToNetworkDrive=Instalatorul nu poate realiza instalarea pe un dispozitiv de reea.
CannotInstallToUNCPath=Instalatorul nu poate realiza instalarea pe o cale n format UNC.
InvalidPath=Trebuie s introduci o cale complet, inclusiv litera dispozitivului; de exemplu:%n%nC:\APP%n%nsau o cale UNC de forma:%n%n\\server\share
InvalidDrive=Dispozitivul sau partajul UNC pe care l-ai selectat nu exist sau nu este accesibil. Selecteaz altul.
DiskSpaceWarningTitle=Spaiu de Stocare Insuficient
DiskSpaceWarning=Instalarea necesit cel puin %1 KB de spaiu de stocare liber, dar dispozitivul selectat are doar %2 KB liberi.%n%nVrei s continui oricum?
DirNameTooLong=Numele dosarului sau al cii este prea lung.
InvalidDirName=Numele dosarului nu este valid.
BadDirName32=Numele dosarelor nu pot include unul din urmtoarele caractere:%n%n%1
DirExistsTitle=Dosarul Exist
DirExists=Dosarul:%n%n%1%n%nexist deja. Vrei totui s instalezi n acel dosar?
DirDoesntExistTitle=Dosarul Nu Exist
DirDoesntExist=Dosarul:%n%n%1%n%nnu exist. Vrei ca el s fie creat?
; *** "Select Components" wizard page
WizardSelectComponents=Selectarea Componentelor
SelectComponentsDesc=Care dintre componente trebuie instalate?
SelectComponentsLabel2=Selecteaz componentele de instalat; deselecteaz componentele care nu trebuie instalate. Clicheaz pe Continu pentru a merge mai departe.
FullInstallation=Instalare Complet
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
CompactInstallation=Instalare Compact
CustomInstallation=Instalare Personalizat
NoUninstallWarningTitle=Componentele Exist
NoUninstallWarning=Instalatorul a detectat c urmtoarele componente snt deja instalate pe calculator:%n%n%1%n%nDeselectarea lor nu le va dezinstala.%n%nVrei s continui oricum?
ComponentSize1=%1 KB
ComponentSize2=%1 MB
ComponentsDiskSpaceMBLabel=Selecia curent necesit cel puin [mb] MB spaiu de stocare.
; *** "Select Additional Tasks" wizard page
WizardSelectTasks=Selectarea Sarcinilor Suplimentare
SelectTasksDesc=Ce sarcini suplimentare trebuie ndeplinite?
SelectTasksLabel2=Selecteaz sarcinile suplimentare care trebuie ndeplinite n timpul instalrii [name], apoi clicheaz pe Continu.
; *** "Select Start Menu Folder" wizard page
WizardSelectProgramGroup=Selectarea Dosarului din Meniul de Start
SelectStartMenuFolderDesc=Unde trebuie s fie plasate scurtturile programului?
SelectStartMenuFolderLabel3=Scurtturile vor fi plasate n dosarul specificat mai jos al Meniului de Start.
SelectStartMenuFolderBrowseLabel=Pentru a avansa cu instalarea, clicheaz pe Continu. Dac vrei s selectezi un alt dosar, clicheaz pe Exploreaz.
MustEnterGroupName=Trebuie s introduci numele dosarului.
GroupNameTooLong=Numele dosarului sau al cii este prea lung.
InvalidGroupName=Numele dosarului nu este valid.
BadGroupName=Numele dosarului nu poate include unul dintre caracterele urmtoarele:%n%n%1
NoProgramGroupCheck2=Nu crea un &dosar n Meniul de Start
; *** "Ready to Install" wizard page
WizardReady=Pregtit de Instalare
ReadyLabel1=Instalatorul e pregtit pentru instalarea [name] pe calculator.
ReadyLabel2a=Clicheaz pe Instaleaz pentru a continua cu instalarea, sau clicheaz pe napoi dac vrei s revezi sau s schimbi setrile.
ReadyLabel2b=Clicheaz pe Instaleaz pentru a continua cu instalarea.
ReadyMemoUserInfo=Info Utilizator:
ReadyMemoDir=Loc de Destinaie:
ReadyMemoType=Tip de Instalare:
ReadyMemoComponents=Componente Selectate:
ReadyMemoGroup=Dosarul Meniului de Start:
ReadyMemoTasks=Sarcini Suplimentare:
; *** "Preparing to Install" wizard page
WizardPreparing=Pregtire pentru Instalare
PreparingDesc=Instalatorul pregtete instalarea [name] pe calculator.
PreviousInstallNotCompleted=Instalarea/dezinstalarea anterioar a unui program nu a fost terminat. Va trebui s reporneti calculatorul pentru a termina operaia precedent.%n%nDup repornirea calculatorului, ruleaz Instalatorul din nou pentru a realiza instalarea [name].
CannotContinue=Instalarea nu poate continua. Clicheaz pe Anuleaz pentru a o nchide.
ApplicationsFound=Aplicaiile urmtoare folosesc file care trebuie actualizate de ctre Instalator. Este recomandat s permii Instalatorului s nchid automat aplicaiile respective.
ApplicationsFound2=Aplicaiile urmtoare folosesc file care trebuie actualizate de ctre Instalator. Este recomandat s permii Instalatorului s nchid automat aplicaiile respective. Dup ce instalarea e terminat, Instalatorul va ncerca s reporneasc aplicaiile.
CloseApplications=nchide &automat aplicaiile
DontCloseApplications=Nu nchi&de aplicaiile
ErrorCloseApplications=Instalatorul nu a putut nchide automat toate aplicaiile. nainte de a continua, e recomandat s nchizi manual toate aplicaiile care folosesc file ce trebuie actualizate de Instalator.
; *** "Installing" wizard page
WizardInstalling=Instalare n Desfurare
InstallingLabel=Ateapt s se termine instalarea [name] pe calculator.
; *** "Setup Completed" wizard page
FinishedHeadingLabel=Finalizarea Instalrii [name]
FinishedLabelNoIcons=Instalarea [name] pe calculator a fost terminat.
FinishedLabel=Instalarea [name] pe calculator a fost terminat. Aplicaia poate fi lansat prin clicarea pe icoanele instalate.
ClickFinish=Clicheaz pe Finalizeaz pentru a prsi Instalatorul.
FinishedRestartLabel=Pentru a termina instalarea [name], trebuie repornit calculatorul. Vrei s fie repornit acum?
FinishedRestartMessage=Pentru a termina instalarea [name], trebuie repornit calculatorul.%n%nVrei s fie repornit acum?
ShowReadmeCheck=Da, vreau s vd fila de informare (README)
YesRadio=&Da, repornete calculatorul acum
NoRadio=&Nu, voi reporni eu calculatorul mai trziu
; used for example as 'Run MyProg.exe'
RunEntryExec=Ruleaz %1
; used for example as 'View Readme.txt'
RunEntryShellExec=Vezi %1
; *** "Setup Needs the Next Disk" stuff
ChangeDiskTitle=Instalatorul Necesit Discul Urmtor
SelectDiskLabel2=Introdu Discul %1 i clicheaz pe OK.%n%nDac filele de pe acest disc pot fi gsite ntr-un alt dosar dect cel afiat mai jos, introdu calea corect sau clicheaz pe Exploreaz.
PathLabel=&Cale:
FileNotInDir2=Fila "%1" nu poate fi gsit n "%2". Introdu discul corect sau selecteaz alt dosar.
SelectDirectoryLabel=Specific locul discului urmtor.
; *** Installation phase messages
SetupAborted=Instalarea nu a fost terminat.%n%nCorecteaz problema i apoi ruleaz Instalarea din nou.
EntryAbortRetryIgnore=Clicheaz pe Rencearc pentru a ncerca din nou, pe Ignor pentru a continua oricum, sau pe Abandoneaz pentru a anula instalarea.
; *** Installation status messages
StatusClosingApplications=nchid aplicaiile...
StatusCreateDirs=Creez dosarele...
StatusExtractFiles=Extrag filele...
StatusCreateIcons=Creez scurtturile...
StatusCreateIniEntries=Creez intrrile INI...
StatusCreateRegistryEntries=Creez intrrile n registru...
StatusRegisterFiles=nregistrez filele...
StatusSavingUninstall=Salvez informaiile de dezinstalare...
StatusRunProgram=Finalizez instalarea...
StatusRestartingApplications=Repornesc aplicaiile...
StatusRollback=Rentorc la starea iniial, prin anularea modificrilor fcute...
; *** Misc. errors
ErrorInternal2=Eroare Intern: %1
ErrorFunctionFailedNoCode=%1 a euat
ErrorFunctionFailed=%1 a euat; cod %2
ErrorFunctionFailedWithMessage=%1 a euat; cod %2.%n%3
ErrorExecutingProgram=Nu pot executa fila:%n%1
; *** Registry errors
ErrorRegOpenKey=Eroare la deschiderea cheii de registru:%n%1\%2
ErrorRegCreateKey=Eroare la crearea cheii de registru:%n%1\%2
ErrorRegWriteKey=Eroare la scrierea n cheia de registru:%n%1\%2
; *** INI errors
ErrorIniEntry=Eroare la crearea intrrii INI n fiierul "%1".
; *** File copying errors
FileAbortRetryIgnore=Clicheaz pe Rencearc pentru a ncerca din nou, pe Ignor pentru a sri aceast fil (nerecomandat), sau pe Abandoneaz pentru a anula instalarea.
FileAbortRetryIgnore2=Clicheaz pe Rencearc pentru a ncerca din nou, pe Ignor pentru a continua oricum (nerecomandat), sau pe Abandoneaz pentru a anula instalarea.
SourceIsCorrupted=Fila surs este stricat (corupt)
SourceDoesntExist=Fila surs "%1" nu exist
ExistingFileReadOnly=Fila deja existent este marcat doar-citire.%n%nClicheaz pe Rencearc pentru a nltura atributul doar-citire i a ncerca din nou, pe Ignor pentru a sri aceast fil, sau pe Abandoneaz pentru a anula instalarea.
ErrorReadingExistingDest=A aprut o eroare n timpul citirii filei deja existente:
FileExists=Fila exist deja.%n%Vrei ca ea s fie suprascris de Instalator?
ExistingFileNewer=Fila deja existent este mai nou dect cea care trebuie instalat. Este recomandat s-o pstrezi pe cea existent.%n%nVrei s pstrezi fila deja existent?
ErrorChangingAttr=A aprut o eroare n timpul schimbrii atributelor filei deja existente:
ErrorCreatingTemp=A aprut o eroare n timpul crerii filei n dosarul de destinaie:
ErrorReadingSource=A aprut o eroare n timpul citirii filei surs:
ErrorCopying=A aprut o eroare n timpul copierii filei:
ErrorReplacingExistingFile=A aprut o eroare n timpul nlocuirii filei deja existente:
ErrorRestartReplace=Repornirea/nlocuirea a euat:
ErrorRenamingTemp=A aprut o eroare n timpul renumirii unei file din dosarul de destinaie:
ErrorRegisterServer=Nu pot nregistra DLL/OCX: %1
ErrorRegSvr32Failed=RegSvr32 a euat, avnd codul de ieire %1
ErrorRegisterTypeLib=Nu pot nregistra biblioteca de tipuri: %1
; *** Post-installation errors
ErrorOpeningReadme=A aprut o eroare la deschiderea filei de informare (README).
ErrorRestartingComputer=Instalatorul nu a putut reporni calculatorul. Va trebui s-l reporneti manual.
; *** Uninstaller messages
UninstallNotFound=Fila "%1" nu exist. Dezinstalarea nu poate fi fcut.
UninstallOpenError=Fila "%1" nu poate fi deschis. Dezinstalarea nu poate fi fcut
UninstallUnsupportedVer=Fila "%1" ce conine jurnalul de dezinstalare este ntr-un format nerecunoscut de aceast versiune a dezinstalatorului. Dezinstalarea nu poate fi fcut
UninstallUnknownEntry=A fost ntlnit o intrare necunoscut (%1) n jurnalul de dezinstalare
ConfirmUninstall=Sigur vrei s nlturi complet %1 i componentele sale?
UninstallOnlyOnWin64=Aceast instalare poate fi dezinstalat doar pe un sistem Windows 64-bii.
OnlyAdminCanUninstall=Aceast instalare poate fi dezinstalat doar de ctre un utilizator cu drepturi de Administrator.
UninstallStatusLabel=Ateapt ca %1 s fie nlturat de pe calculator.
UninstalledAll=%1 a fost nlturat cu succes de pe calculator.
UninstalledMost=Dezinstalare complet a %1.%n%nAnumite elemente nu au putut fi nlturate. Acestea pot fi nlturate manual.
UninstalledAndNeedsRestart=Pentru a termina dezinstalarea %1, calculatorul trebuie repornit.%n%nVrei s fie repornit acum?
UninstallDataCorrupted=Fila "%1" este stricat (corupt). Dezinstalarea nu poate fi fcut
; *** Uninstallation phase messages
ConfirmDeleteSharedFileTitle=terg Fila Partajat?
ConfirmDeleteSharedFile2=Sistemul indic faptul c fila partajat urmtoare pare s nu mai fie folosit de vreun alt program. Vrei ca Dezinstalatorul s tearg aceast fil partajat?%n%nDac totui mai exist programe care folosesc fila i ea este tears, acele programe ar putea s funcioneze greit. Dac nu eti sigur, alege Nu. Lsarea filei n sistem nu va produce nici o neplcere.
SharedFileNameLabel=Nume Fil:
SharedFileLocationLabel=Loc:
WizardUninstalling=Starea Dezinstalrii
StatusUninstalling=Dezinstalez %1...
; *** Shutdown block reasons
ShutdownBlockReasonInstallingApp=Instalez %1.
ShutdownBlockReasonUninstallingApp=Dezinstalez %1.
; The custom messages below aren't used by Setup itself, but if you make
; use of them in your scripts, you'll want to translate them.
[CustomMessages]
NameAndVersion=%1 versiunea %2
AdditionalIcons=Icoane suplimentare:
CreateDesktopIcon=Creeaz o icoan pe &Birou ("Desktop")
CreateQuickLaunchIcon=Creeaz o icoan n Bara de &Lansare Rapid ("Quick Launch")
ProgramOnTheWeb=%1 pe internet
UninstallProgram=Dezinstaleaz %1
LaunchProgram=Lanseaz %1
AssocFileExtension=&Asociaz %1 cu extensia de file %2
AssocingFileExtension=Asociez %1 cu extensia de file %2...
AutoStartProgramGroupDescription=Pornire:
AutoStartProgram=Pornete automat %1
AddonHostProgramNotFound=%1 nu poate fi gsit n dosarul selectat.%n%nVrei s continui oricum?
================================================
FILE: InnoDependencies/Vietnamese.isl
================================================
; *** Inno Setup version 6.1.0+ Vietnamese messages ***
; Translated by Vu Khac Hiep (email: vukhachiep@gmail.com)
; To download user-contributed translations of this file, go to:
; https://jrsoftware.org/files/istrans/
;
; Note: When translating this text, do not add periods (.) to the end of
; messages that didn't have them already, because on those messages Inno
; Setup adds the periods automatically (appending a period would result in
; two periods being displayed).
[LangOptions]
; The following three entries are very important. Be sure to read and
; understand the '[LangOptions] section' topic in the help file.
LanguageName=Vietnamese
LanguageID=$042A
LanguageCodePage=0
; If the language you are translating to requires special font faces or
; sizes, uncomment any of the following entries and change them accordingly.
;DialogFontName=
;DialogFontSize=8
;WelcomeFontName=Verdana
;WelcomeFontSize=12
;TitleFontName=Arial
;TitleFontSize=29
;CopyrightFontName=Arial
;CopyrightFontSize=8
[Messages]
; *** Application titles
SetupAppTitle=Cài đặt
SetupWindowTitle=Cài đặt - %1
UninstallAppTitle=Gỡ cài đặt
UninstallAppFullTitle=Gỡ cài đặt - %1
; *** Misc. common
InformationTitle=Thông tin
ConfirmTitle=Xác nhận
ErrorTitle=Lỗi
; *** SetupLdr messages
SetupLdrStartupMessage=Chương trình này sẽ cài đặt %1. Bạn có muốn tiếp tục không?
LdrCannotCreateTemp=Không thể tạo tệp tạm thời. Cài đặt bị hủy bỏ
LdrCannotExecTemp=Không thể chạy tệp trong thư mục tạm thời. Cài đặt bị hủy bỏ
HelpTextNote=
; *** Startup error messages
LastErrorMessage=%1.%n%nLỗi %2: %3
SetupFileMissing=Tệp %1 bị thiếu trong thư mục cài đặt. Hãy sửa lỗi hoặc lấy một bản sao mới của chương trình.
SetupFileCorrupt=Các tệp cài đặt đã bị hỏng. Hãy sửa lỗi hoặc lấy một bản sao của chương trình.
SetupFileCorruptOrWrongVer=Các tệp cài đặt bị hỏng, hoặc không tương thích với bản cài đặt này. Hãy sửa lỗi hoặc lấy một bản sao mới của chương trình.
InvalidParameter=Một thông số không hợp lệ đã được đưa vào dòng lệnh:%n%n%1
SetupAlreadyRunning=Cài đặt này đang chạy.
WindowsVersionNotSupported=Chương trình này không tương thích với phiên bản Windows bạn đang chạy.
WindowsServicePackRequired=Chương trình này yêu cầu %1 Service Pack %2 hoặc mới hơn.
NotOnThisPlatform=Chương trình này sẽ không chạy trên %1.
OnlyOnThisPlatform=Chương trình này phải chạy trên %1.
OnlyOnTheseArchitectures=Chương trình này chỉ có thể được cài đặt trên phiên bản Windows được thiết kế cho các hệ vi xử lí:%n%n%1
WinVersionTooLowError=Chương trình này yêu cầu %1 phiên bản %2 hoặc mới hơn.
WinVersionTooHighError=Chương trình này không thể được cài đặt trên %1 phiên bản %2 hoặc mới hơn.
AdminPrivilegesRequired=Bạn phải được đăng nhập như người quản trị khi cài đặt chương trình này.
PowerUserPrivilegesRequired=Bạn phải được đăng nhập như người quản trị hoặc thành viên trong nhóm Người dùng mạnh khi cài đặt chương trình này.
SetupAppRunningError=Cài đặt phát hiện %1 đang chạy.%n%nHãy đóng tất cả các tiến trình của nó ngay, rồi click OK để tiếp tục, hoặc Hủy để thoát.
UninstallAppRunningError=Gỡ cài đặt phát hiện %1 đang chạy.%n%nHãy đóng tất cả các tiến trình của nó ngay, rồi click OK để tiếp tục, hoặc Hủy để thoát.
; *** Startup questions
PrivilegesRequiredOverrideTitle=Select Setup Install Mode
PrivilegesRequiredOverrideInstruction=Select install mode
PrivilegesRequiredOverrideText1=%1 can be installed for all users (requires administrative privileges), or for you only.
PrivilegesRequiredOverrideText2=%1 can be installed for you only, or for all users (requires administrative privileges).
PrivilegesRequiredOverrideAllUsers=Install for &all users
PrivilegesRequiredOverrideAllUsersRecommended=Install for &all users (recommended)
PrivilegesRequiredOverrideCurrentUser=Install for &me only
PrivilegesRequiredOverrideCurrentUserRecommended=Install for &me only (recommended)
; *** Misc. errors
ErrorCreatingDir=Cài đặt không thể tạo ra thư mục "%1"
ErrorTooManyFilesInDir=Không thể tạo một tệp trong thư mục "%1" vì nó chứa quá nhiều tệp
; *** Setup common messages
ExitSetupTitle=Thoát cài đặt
ExitSetupMessage=Cài đặt chưa hoàn thành. Nếu bạn thoát bây giờ, chương trình sẽ không được cài đặt.%n%nBạn có thể chạy lại Cài đặt một lần khác để hoàn thành cài đặt.%n%nThoát ngay?
AboutSetupMenuItem=&Về trình cài đặt...
AboutSetupTitle=Về trình cài đặt
AboutSetupMessage=%1 phiên bản %2%n%3%n%n%1 trang chủ:%n%4
AboutSetupNote=
TranslatorNote=Giao diện người dùng tiếng Việt bởi: Vũ Khắc Hiệp
; *** Buttons
ButtonBack=< &Trước
ButtonNext=T&iếp >
ButtonInstall=&Cài đặt
ButtonOK=OK
ButtonCancel=Hủy
ButtonYes=&Có
ButtonYesToAll=Có c&ho tất cả
ButtonNo=&Không
ButtonNoToAll=Khô&ng cho tất cả
ButtonFinish=&Hoàn thành
ButtonBrowse=&Duyệt...
ButtonWizardBrowse=D&uyệt...
ButtonNewFolder=Tạ&o thư mục mới
; *** "Select Language" dialog messages
SelectLanguageTitle=Chọn ngôn ngữ cài đặt
SelectLanguageLabel=Chọn ngôn ngữ để sử dụng khi cài đặt:
; *** Common wizard text
ClickNext=Nhấn Tiếp để tiếp tục, hoặc Hủy để thoát cài đặt
BeveledLabel=
BrowseDialogTitle=Tìm thư mục
BrowseDialogLabel=Chọn một thư mục trong danh sách sau rồi ấn OK.
NewFolderName=Tạo thư mục mới
; *** "Welcome" wizard page
WelcomeLabel1=Chào mừng tới trình cài đặt [name]
WelcomeLabel2=Chương trình này sẽ cài [name/ver] trên máy tính của bạn.%n%nChúng tôi khuyên bạn đóng mọi chương trình khác lại trước khi cài đặt.
; *** "Password" wizard page
WizardPassword=Mật khẩu
PasswordLabel1=Việc cài đặt được bảo vệ bằng mật khẩu.
PasswordLabel3=Hãy nhập mật khẩu, rồi nhấn Tiếp để tiếp tục. Mật khẩu phân biệt chữ hoa/thường.
PasswordEditLabel=&Mật khẩu:
IncorrectPassword=Mật khẩu bạn đã nhập không đúng. Hãy thử lại.
; *** "License Agreement" wizard page
WizardLicense=Thỏa thuận cấp phép
LicenseLabel=Hãy đọc những thông tin quan trọng sau trước khi tiếp tục.
LicenseLabel3=Hãy đọc Thỏa thuận cấp phép sau. Bạn phải chấp nhận các điều khoản của cài đặt này trước khi tiếp tục.
LicenseAccepted=Tô&i chấp nhận thỏa thuận
LicenseNotAccepted=Tôi khôn&g chấp nhận thỏa thuận
; *** "Information" wizard pages
WizardInfoBefore=Thông tin
InfoBeforeLabel=Hãy đọc những thông tin quan trọng sau trước khi tiếp tục.
InfoBeforeClickLabel=Khi bạn đã sẵn sàng cài đặt tiếp, click Tiếp.
WizardInfoAfter=Thông tin
InfoAfterLabel=Hãy đọc những thông tin quan trọng sau trước khi tiếp tục.
InfoAfterClickLabel=Khi bạn đã sẵn sàng cài đặt tiếp, click Tiếp.
; *** "User Information" wizard page
WizardUserInfo=Thông tin người dùng
UserInfoDesc=Hãy nhập thông tin của bạn.
UserInfoName=Tên n&gười dùng:
UserInfoOrg=Tổ c&hức:
UserInfoSerial=&Số serial:
UserInfoNameRequired=Bạn phải nhập một tên.
; *** "Select Destination Location" wizard page
WizardSelectDir=Chọn vị trí cài đặt
SelectDirDesc=[name] nên được cài đặt ở đâu?
SelectDirLabel3=[name] sẽ được cài đặt vào thư mục sau:
SelectDirBrowseLabel=Để tiếp tục. nhấn Tiếp. Nếu bạn muốn chọn một thư mục khác, nhấn Duyệt.
DiskSpaceGBLabel=Cần có ít nhất [gb] GB ổ đĩa trống.
DiskSpaceMBLabel=Cần có ít nhất [mb] MB ổ đĩa trống.
CannotInstallToNetworkDrive=Cài đặt không thể cài vào một ổ đĩa mạng.
CannotInstallToUNCPath=Cài đặt không thể cài vào đường dẫn UNC.
InvalidPath=Bạn phải nhập đường dẫn đầy đủ với chữ cái ổ đĩa, ví dụ:%n%nC:\APP%n%nhoặc một đường dẫn UNC theo mẫu:%n%n\\server\share
InvalidDrive=Ổ đĩa hoặc chia sẻ UNC bạn đã chọn không tồn tại hoặc không truy cập được. Hãy chọn cái khác.
DiskSpaceWarningTitle=Không đủ dung lượng đĩa
DiskSpaceWarning=Cài đặt yêu cầu ít nhất %1 KB dung lượng trống để cài đặt, nhưng ổ đĩa đã chọn chỉ còn %2KB.%n%nBạn muốn tiếp tục bằng mọi giá?
DirNameTooLong=Tên thư mục hoặc đường dẫn quá dài.
InvalidDirName=Tên thư mục không hợp lệ.
BadDirName32=Tên thư mục không được chứa các kí tự sau:%n%n%1
DirExistsTitle=Thư mục đã tồn tại
DirExists=Thư mục:%n%n%1%n%nđã tồn tại. Bạn có muốn cài đặt vào thư mục đó bằng mọi giá?
DirDoesntExistTitle=Thư mục không tồn tại
DirDoesntExist=Thư mục:%n%n%1%n%nkhông tồn tại. Bạn có muốn tạo thư mục không?
; *** "Select Components" wizard page
WizardSelectComponents=Chọn các thành phần
SelectComponentsDesc=Những thành phần nào nên được cài đặt?
SelectComponentsLabel2=Chọn các thành phần bạn muốn cài đặt, bỏ chọn các thành phần bạn không muốn. Click Tiếp khi bạn đã sẵn sàng để tiếp tục.
FullInstallation=Cài đặt đầy đủ
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
CompactInstallation=Cài đặt rút gọn
CustomInstallation=Cài đặt tủy chỉnh
NoUninstallWarningTitle=Thành phần đã tồn tại
NoUninstallWarning=Cài đặt phát hiện các thành phần sau đã được cài đặt trên máy tính của bạn:%n%n%1%n%nBỏ chọn những thành phần này sẽ không cài đặt chúng.%n%nBạn có muốn tiếp tục bằng mọi giá?
ComponentSize1=%1 KB
ComponentSize2=%1 MB
ComponentsDiskSpaceGBLabel=Lựa chọn này yêu cầu ít nhất [gb] GB không gian đĩa.
ComponentsDiskSpaceMBLabel=Lựa chọn này yêu cầu ít nhất [mb] MB không gian đĩa.
; *** "Select Additional Tasks" wizard page
WizardSelectTasks=Chọn các tác vụ bổ sung
SelectTasksDesc=Các tác vụ bổ sung nào nên được thực hiện?
SelectTasksLabel2=Chọn các tác vụ bổ sung mà bạn muốn cài đặt thực hiện khi cài đặt [name], rồi nhấn Tiếp.
; *** "Select Start Menu Folder" wizard page
WizardSelectProgramGroup=Chọn thư mục bắt đầu
SelectStartMenuFolderDesc=Các lối tắt đến chương trình nên được đặt ở đâu?
SelectStartMenuFolderLabel3=Cài đặt sẽ tạo các lối tắt đến chương trình trong thư mục bắt đầu sau.
SelectStartMenuFolderBrowseLabel=Để tiếp tục, click Tiếp. Nếu bạn muốn chọn thư mục khác, click Duyệt.
MustEnterGroupName=Bạn phải nhập tên một thư mục.
GroupNameTooLong=Tên thư mục hoặc đường dẫn quá dài.
InvalidGroupName=Tên thư mục không hợp lệ.
BadGroupName=Tên thư mục không được chứa các kí tự sau:%n%n%1
NoProgramGroupCheck2=&Không tạo thư mục bắt đầu
; *** "Ready to Install" wizard page
WizardReady=Sẵn sàng cài đặt
ReadyLabel1=[name] đã sẵn sàng để dược cài đặt trên máy tính của bạn.
ReadyLabel2a=Click Cài đặt để tiếp tục, hoặc click Trước nếu bạn muốn xem lại/thay đổi bất kì cài đặt nào.
ReadyLabel2b=Click Cài đặt để tiếp tục cài đặt.
ReadyMemoUserInfo=Thông tin người dùng:
ReadyMemoDir=Vị trí đích:
ReadyMemoType=Kiểu cài đặt:
ReadyMemoComponents=Các thành phần được chọn:
ReadyMemoGroup=Thư mục bắt đầu:
ReadyMemoTasks=Các tác vụ bổ sung:
; *** TDownloadWizardPage wizard page and DownloadTemporaryFile
DownloadingLabel=Đang tải các tập tin bổ sung...
ButtonStopDownload=&Dừng tải xuống
StopDownload=Bạn có chắc chắn muốn dừng tải xuống không?
ErrorDownloadAborted=Tải xuống bị hủy bỏ
ErrorDownloadFailed=Tải xuống không thành công: %1 %2
ErrorDownloadSizeFailed=Getting size failed: %1 %2
ErrorFileHash1=File hash failed: %1
ErrorFileHash2=Invalid file hash: expected %1, found %2
ErrorProgress=Invalid progress: %1 of %2
ErrorFileSize=Invalid file size: expected %1, found %2
; *** "Preparing to Install" wizard page
WizardPreparing=Chuẩn bị cài đặt
PreparingDesc=[name] đang chuẩn bị được cài đặt trên máy tính của bạn.
PreviousInstallNotCompleted=Việc cài đặt/gỡ bỏ một chương trình chưa được hoàn tất trước đó. Bạn sẽ phải khởi động lại máy tính để hoàn tất cài đặt đó.%n%nSau khi chởi động lại, chạy Cài đặt một lần nữa để hoàn tất cài đặt [name].
CannotContinue=Cài đặt không thể tiếp tục. Nhấn Hủy để thoát.
ApplicationsFound=Những chương trình sau đang sử dụng các tệp cần được cập nhật bởi trình cài đặt. Chúng tôi khuyên bạn cho phép Cài đặt đóng các chương trình này.
ApplicationsFound2=Những chương trình sau đang sử dụng các tệp cần được cập nhật bởi trình cài đặt. Chúng tôi khuyên bạn cho phép Cài đặt đóng các chương trình này. Sau khi hoàn thành cài đặt, chúng tôi sẽ thử khởi động lại các chương trình này.
CloseApplications=Tự độn&g đóng các chương trình này
DontCloseApplications=Không đóng các chương t&rình này
ErrorCloseApplications=Cài đặt không thể đóng mọi chương trình. Chúng tôi khuyên bạn đóng các chương trình đang sử dụng các tệp cần được cập nhật bởi Cài đặt một cách thủ công trước khi tiếp tục.
PrepareToInstallNeedsRestart=Setup must restart your computer. After restarting your computer, run Setup again to complete the installation of [name].%n%nWould you like to restart now?
; *** "Installing" wizard page
WizardInstalling=Đang cài đặt
InstallingLabel=Hãy đợi khi [name] đang được cài đặt trên máy tính của bạn.
; *** "Setup Completed" wizard page
FinishedHeadingLabel=Hoàn thành cài đặt [name]
FinishedLabelNoIcons=[name] đã được cài đặt xong trên máy tính của bạn.
FinishedLabel=[name] đã được cài đặt xong trên máy tính của bạn. Chương trình có thể được khởi động bằng cách click vào lối tắt đến chương trình.
ClickFinish=Click Hoàn thành để thoát Cài đặt.
FinishedRestartLabel=Để hoàn thành cài đặt [name], máy tính của bạn cần đươc khởi động lại. Bạn có muốn khởi động lại ngay?
FinishedRestartMessage=Để hoàn thành cài đặt [name], máy tính của bạn cần đươc khởi động lại.%n%nBạn có muốn khởi động lại ngay?
ShowReadmeCheck=Có, tôi muốn xem tệp README
YesRadio=&Có, khởi động lại máy tính ngay
NoRadio=&Không, tôi sẽ khởi động lại máy tính sau
; used for example as 'Run MyProg.exe'
RunEntryExec=Chạy %1
; used for example as 'View Readme.txt'
RunEntryShellExec=Xem %1
; *** "Setup Needs the Next Disk" stuff
ChangeDiskTitle=Cài đặt cần đĩa tiếp theo
SelectDiskLabel2=Hãy chèn đĩa %1 và click OK.%n%nNếu các tệp trên đĩa này có thể được tìm thấy trên một thư mục khác với được hiển thị dưới đây, nhập đường dẫn hoặc click Duyệt.
PathLabel=Đườ&ng dẫn:
FileNotInDir2=Tệp "%1" không thể được xác định trong "%2". Hãy chọn đia xđúng hoặc chọn thư mục khác.
SelectDirectoryLabel=Hãy chọn vị trí của đĩa tiếp theo.
; *** Installation phase messages
SetupAborted=Cài đặt không được hoàn thành.%n%nHãy sửa lỗi và chạy Cài đặt lại.
AbortRetryIgnoreSelectAction=Chọn hành động
AbortRetryIgnoreRetry=&Thử lại
AbortRetryIgnoreIgnore=&Bỏ qua lỗi và tiếp tục
AbortRetryIgnoreCancel=Hủy
; *** Installation status messages
StatusClosingApplications=Đang đóng các chương trình...
StatusCreateDirs=Đang tạo các thư mục...
StatusExtractFiles=Đang giải nén các tệp...
StatusCreateIcons=Đang tạo các lối tắt...
StatusCreateIniEntries=Đang tạo các đầu vào INI...
StatusCreateRegistryEntries=Đang tạo các đầu vào registry...
StatusRegisterFiles=Đang đăng kí các tệp...
StatusSavingUninstall=Đang lưu thông tin gỡ cài đặt...
StatusRunProgram=Đang hoàn thành cài đặt...
StatusRestartingApplications=Đang khởi động lại các chương trình...
StatusRollback=Đang hoàn lại các thay đổi...
; *** Misc. errors
ErrorInternal2=Lỗi nội bộ: %1
ErrorFunctionFailedNoCode=%1 thất bại
ErrorFunctionFailed=%1 thất bại với mã lỗi %2
ErrorFunctionFailedWithMessage=%1 thất bại với mã lỗi %2.%n%3
ErrorExecutingProgram=Không thể chạy tệp:%n%1
; *** Registry errors
ErrorRegOpenKey=Lỗi khi mở registry:%n%1\%2
ErrorRegCreateKey=Lỗi khi tạo registry:%n%1\%2
ErrorRegWriteKey=Lỗi khi viết registry:%n%1\%2
; *** INI errors
ErrorIniEntry=Lỗi tạo đầu vào INI cho tệp "%1".
; *** File copying errors
FileAbortRetryIgnoreSkipNotRecommended=&Bỏ qua tệp này (không khuyến nghị)
FileAbortRetryIgnoreIgnoreNotRecommended=&Bỏ qua để tiếp tục bằng mọi giá (không khuyến nghị)
SourceIsCorrupted=Tệp nguồn bị hỏng
SourceDoesntExist=Tệp nguồn "%1" không tồn tại
ExistingFileReadOnly2=Tệp đã tồn tại với đánh dấu chỉ đọc.
ExistingFileReadOnlyRetry=&Xóa thuộc tính chỉ đọc và thử lại
ExistingFileReadOnlyKeepExisting=&Giữ tập tin hiện có
ErrorReadingExistingDest=Một lỗi đã xảy ra khi đọc tệp:
FileExistsSelectAction=Select action
FileExists2=Tệp đã tồn tại.
FileExistsOverwriteExisting=G&hi đè tệp hiện có
FileExistsKeepExisting=&Giữ tệp hiện có
FileExistsOverwriteOrKeepAll=&Do this for the next conflicts
ExistingFileNewerSelectAction=Select action
ExistingFileNewer2=Tệp hiện có mới hơn tệp mà Thiết lập đang cố gắng cài đặt.
ExistingFileNewerOverwriteExisting=&Ghi đè tệp hiện có
ExistingFileNewerKeepExisting=&Giữ tệp hiện có (khuyến nghị)
ExistingFileNewerOverwriteOrKeepAll=&Do this for the next conflicts
ErrorChangingAttr=Một lỗi đã xảy ra khi thay đổi thuộc tính của tệp sau:
ErrorCreatingTemp=Một lỗi đã xảy ra khi tạo một tệp trong thư mục đích:
ErrorReadingSource=Một lỗi đã xảy ra khi đọc tệp nguồn:
ErrorCopying=Một lỗi đã xảy ra khi sao chép tệp:
ErrorReplacingExistingFile=Một lỗi đã xảy ra khi thay thế tệp:
ErrorRestartReplace=Khởi động lại & Thay thế (RestartReplace) thất bại:
ErrorRenamingTemp=Một lỗi đã xảy ra khi đổi tên tệp trong thư mục đích:
ErrorRegisterServer=Không thể đăng kí DLL/OCX: %1
ErrorRegSvr32Failed=RegSvr32 thất bại với mã thoát %1
ErrorRegisterTypeLib=Không thể đăng kí thư viện kiểu: %1
; *** Uninstall display name markings
; used for example as 'My Program (32-bit)'
UninstallDisplayNameMark=%1 (%2)
; used for example as 'My Program (32-bit, All users)'
UninstallDisplayNameMarks=%1 (%2, %3)
UninstallDisplayNameMark32Bit=32-bit
UninstallDisplayNameMark64Bit=64-bit
UninstallDisplayNameMarkAllUsers=All users
UninstallDisplayNameMarkCurrentUser=Current user
; *** Post-installation errors
ErrorOpeningReadme=Một lỗi đã xảy ra khi mở tệp README.
ErrorRestartingComputer=Cài đặt không thể khởi động lại máy tính. Hãy làm việc này một cách thủ công.
; *** Uninstaller messages
UninstallNotFound=Tệp "%1" không tồn tại. Không thể gỡ cài đặt.
UninstallOpenError=Tệp "%1" không thể được mở. Không thể gỡ cài đặt
UninstallUnsupportedVer=Tệp nhật kí gỡ cài đặt "%1" có định dạng không thể được xác định bởi phiên bản gỡ cài đặt này. Không thể gỡ cài đặt
UninstallUnknownEntry=Một đầu vào không xác định (%1) đã bị phát hiện trong nhật kí gỡ cài đặt
ConfirmUninstall=Bạn có muốn dỡ bỏ hoàn toàn %1 và mọi thành phần của nó?
UninstallOnlyOnWin64=Cài đặt này chỉ có thể được gỡ bỏ trên Windows 64 bit.
OnlyAdminCanUninstall=Cài đặt này chỉ có thể được gỡ bỏ bằng một người dùng có quyền người quản trị.
UninstallStatusLabel=Hãy đợi khi %1 được gỡ khỏi máy tính của bạn.
UninstalledAll=%1 đã được gỡ bỏ thành công khỏi máy tính của bạn.
UninstalledMost=%1 đã được gỡ bỏ thành công.%n%nMột số thành phần không thể được gỡ bỏ. Hãy làm việc này một cách thủ công.
UninstalledAndNeedsRestart=Để hoàn thành việc gỡ cài đặt %1, bạn phải khởi động lại máy tính.%n%nBạn có muốn khởi động lại ngay?
UninstallDataCorrupted=Tệp "%1" bị hỏng. Không thể gỡ cài đặt
; *** Uninstallation phase messages
ConfirmDeleteSharedFileTitle=Gỡ bỏ tệp được chia sẻ?
ConfirmDeleteSharedFile2=Hệ thống chỉ ra các tệp được chia sẻ sau không được sử dụng bởi chương trình nào. Bạn có muốn gỡ bỏ tệp này?%n%nNếu có một chương trình vẫn sử dụng tệp này mà tệp bị gỡ bỏ, chúng có thể không chạy tốt. Nếu bạn không chắc chắn, chọn Không. Để lại tệp trên hệ thống của bạn sẽ không gây ra tổn hại.
SharedFileNameLabel=Tên tệp:
SharedFileLocationLabel=Vị trí:
WizardUninstalling=Trạng thái gỡ cài đặt
StatusUninstalling=Đang gỡ cài đặt %1...
; *** Shutdown block reasons
ShutdownBlockReasonInstallingApp=Đang cài đặt %1.
ShutdownBlockReasonUninstallingApp=Đang gỡ cài đặt %1.
; The custom messages below aren't used by Setup itself, but if you make
; use of them in your scripts, you'll want to translate them.
[CustomMessages]
NameAndVersion=%1 phiên bản %2
AdditionalIcons=Các lối tắt bổ sung:
CreateDesktopIcon=Tạo một &lối tắt trên Desktop
CreateQuickLaunchIcon=Tạo một lối tắt &Khởi động nhanh
ProgramOnTheWeb=%1 trên Web
UninstallProgram=Gỡ cài đặt %1
LaunchProgram=Khởi động %1
AssocFileExtension=&Gán %1 với đuôi tệp %2
AssocingFileExtension=Đang gán %1 với đuôi tệp %2...
AutoStartProgramGroupDescription=Khởi động:
AutoStartProgram=Tự động khởi động %1
AddonHostProgramNotFound=%1 không thể được xác định trong thư mục bạn đã chọn.%n%nBạn có muốn tiếp tục bằng mọi giá?
================================================
FILE: InnoDependencies/install_dotnet.iss
================================================
#define DotNetPrettyName "Microsoft .NET Desktop Runtime"
#define DotNetName "Microsoft.WindowsDesktop.App 8"
#define DotNetVersion "8.0.15"
#define DotNetURL "https://builds.dotnet.microsoft.com/dotnet/WindowsDesktop/8.0.15/windowsdesktop-runtime-8.0.15-win-x64.exe"
#define DotNetExeName "dotnet8.exe"
#define DotNetExeArgs "/install /repair /passive /norestart"
[Code]
var
NeedsInstall: Boolean;
Dependency_DownloadPage: TDownloadWizardPage;
Dependency_Memo: String;
function SplitString(Text: String; Separator: String): TArrayOfString;
var
i, p: Integer;
dest: TArrayOfString;
begin
i := 0;
repeat
SetArrayLength(dest, i + 1);
p := Pos(Separator, Text);
if p > 0 then begin
dest[i] := Copy(Text, 1, p - 1);
Text := Copy(Text, p + Length(Separator), Length(Text));
i := i + 1;
end else begin
dest[i] := Text;
Text := '';
end;
until Length(Text)=0;
Result := dest
end;
function CheckDotNetVersionEqualOrHigher(StringArray: TArrayOfString; DotNetName: String; MinimumVersionString: String): Boolean;
var
i, p: Integer;
str, verStr: String;
strArray: TArrayOfString;
minVer, ver: Int64;
begin
Result := False;
if StrToVersion(MinimumVersionString, minVer) then begin
for i := 0 to GetArrayLength(StringArray) - 1 do begin
str := StringArray[i];
p := Pos(DotNetName, str);
if p > 0 then begin
strArray := SplitString(str, ' ');
if GetArrayLength(strArray) >= 3 then begin
verStr := strArray[1];
if StrToVersion(verStr, ver) then begin
if ComparePackedVersion(minVer, ver) <= 0 then begin
Result := True;
break;
end;
end;
end;
end;
end;
end;
end;
function IsDotNetInstalled(DotNetName: string; DotNetVersion: string): Boolean;
var
cmd, args, fileName, command: string;
output: AnsiString;
resultCode: Integer;
begin
command := 'dotnet --list-runtimes';
fileName := ExpandConstant('{tmp}\dotnet.txt');
cmd := ExpandConstant('{cmd}');
args := '/C ' + command + ' > "' + fileName + '" 2>&1';
if Exec(cmd, args, '', SW_HIDE, ewWaitUntilTerminated, resultCode) and (resultCode = 0) then begin
if LoadStringFromFile(fileName, output) then begin
if CheckDotNetVersionEqualOrHigher(SplitString(output, #13#10), DotNetName, DotNetVersion) then begin
Log('"' + DotNetName + '" version "' + DotNetVersion + '" or higher found in output of "' + command + '"');
Result := True;
end
else begin
Log('"' + DotNetName + '" version "' + DotNetVersion + '" or higher not found in output of "' + command + '"');
Result := False;
end;
end
else begin
Log('Failed to read output of "' + command + '"');
Result := False;
end;
end
else begin
Log('Failed to execute "' + command + '"');
Result := False;
end;
DeleteFile(fileName);
end;
procedure InstallDotNet6DesktopRuntime;
begin
if not IsDotNetInstalled('{#DotNetName}', '{#DotNetVersion}') then begin
NeedsInstall := True;
Dependency_Memo := Dependency_Memo + #13#10 + '%1' + '{#DotNetPrettyName} {#DotNetVersion}';
end;
end;
procedure Dependency_InitializeWizard;
begin
Dependency_DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil);
end;
function Dependency_UpdateReadyMemo(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
begin
Result := '';
if MemoUserInfoInfo <> '' then begin
Result := Result + MemoUserInfoInfo + Newline + NewLine;
end;
if MemoDirInfo <> '' then begin
Result := Result + MemoDirInfo + Newline + NewLine;
end;
if MemoTypeInfo <> '' then begin
Result := Result + MemoTypeInfo + Newline + NewLine;
end;
if MemoComponentsInfo <> '' then begin
Result := Result + MemoComponentsInfo + Newline + NewLine;
end;
if MemoGroupInfo <> '' then begin
Result := Result + MemoGroupInfo + Newline + NewLine;
end;
if MemoTasksInfo <> '' then begin
Result := Result + MemoTasksInfo;
end;
if Dependency_Memo <> '' then begin
if MemoTasksInfo = '' then begin
Result := Result + SetupMessage(msgReadyMemoTasks);
end;
Result := Result + FmtMessage(Dependency_Memo, [Space]);
end;
end;
function Dependency_PrepareToInstall(var NeedsRestart: Boolean): String;
var
prettyName: String;
retry, abort: Boolean;
resultCode: Integer;
begin
if NeedsInstall then begin
prettyName := '{#DotNetPrettyName} {#DotNetVersion}'
Dependency_DownloadPage.Show;
Dependency_DownloadPage.Clear;
Dependency_DownloadPage.Add('{#DotNetURL}', '{#DotNetExeName}', '');
retry := True;
while retry do begin
retry := False;
abort := False;
try
Dependency_DownloadPage.Download;
except
if Dependency_DownloadPage.AbortedByUser then begin
abort := True
end else begin
case SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbError, MB_RETRYCANCEL, IDRETRY) of
IDCANCEL: begin
abort := True;
end;
IDRETRY: begin
retry := True;
end;
end;
end;
end;
end;
if not abort then begin
Dependency_DownloadPage.SetText(prettyName, '');
Dependency_DownloadPage.SetProgress(1, 1);
while True do begin
resultCode := 0;
if ShellExec('', ExpandConstant('{tmp}{\}') + '{#DotNetExeName}', '{#DotNetExeArgs}', '', SW_SHOWNORMAL, ewWaitUntilTerminated, resultCode) then begin
if (resultCode = 0) then begin
break;
end;
end;
case SuppressibleMsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [prettyName, IntToStr(ResultCode)]), mbError, MB_RETRYCANCEL, IDRETRY) of
IDCANCEL: begin
abort := True;
break;
end;
end;
end;
end;
Dependency_DownloadPage.Hide;
end;
end;
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: LenovoLegionToolkit.CLI/Flags.cs
================================================
using System.Collections.Generic;
using System.Linq;
namespace LenovoLegionToolkit.CLI;
public readonly struct Flags
{
public bool Silent { get; }
public string? QuickActionRunName { get; }
public bool Help { get; }
public static Flags Create(IEnumerable startupArgs)
{
try
{
return new(startupArgs);
}
catch
{
return default;
}
}
private Flags(IEnumerable startupArgs)
{
var args = startupArgs.ToArray();
QuickActionRunName = StringValue(args, "--quickAction") ?? StringValue(args, "-qa");
Silent = BoolValue(args, "--silent") || BoolValue(args, "-s");
Help = BoolValue(args, "--help") || BoolValue(args, "-h");
}
private static bool BoolValue(IEnumerable values, string key) => values.Contains(key);
private static string? StringValue(IEnumerable values, string key)
{
var value = values.FirstOrDefault(s => s.StartsWith(key));
return value?.Remove(0, key.Length + 1);
}
}
================================================
FILE: LenovoLegionToolkit.CLI/IpcClient.cs
================================================
using System;
using System.IO.Pipes;
using System.Threading;
using System.Threading.Tasks;
using LenovoLegionToolkit.CLI.Lib;
using LenovoLegionToolkit.CLI.Lib.Extensions;
namespace LenovoLegionToolkit.CLI;
public static class IpcClient
{
public static async Task ListQuickActionsAsync()
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.ListQuickActions
};
return await SendRequestAsync(req).ConfigureAwait(false)
?? throw new IpcException("Missing return message");
}
public static Task RunQuickActionAsync(string name)
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.QuickAction,
Name = name
};
return SendRequestAsync(req);
}
public static async Task ListFeaturesAsync()
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.ListFeatures,
};
return await SendRequestAsync(req).ConfigureAwait(false)
?? throw new IpcException("Missing return message");
}
public static async Task ListFeatureValuesAsync(string name)
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.ListFeatureValues,
Name = name,
};
return await SendRequestAsync(req).ConfigureAwait(false)
?? throw new IpcException("Missing return message");
}
public static Task SetFeatureValueAsync(string name, string value)
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.SetFeatureValue,
Name = name,
Value = value
};
return SendRequestAsync(req);
}
public static async Task GetFeatureValueAsync(string name)
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.GetFeatureValue,
Name = name
};
return await SendRequestAsync(req).ConfigureAwait(false)
?? throw new IpcException("Missing return message");
}
public static async Task GetSpectrumProfileAsync()
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.GetSpectrumProfile
};
return await SendRequestAsync(req).ConfigureAwait(false)
?? throw new IpcException("Missing return message");
}
public static Task SetSpectrumProfileAsync(string value)
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.SetSpectrumProfile,
Value = value
};
return SendRequestAsync(req);
}
public static async Task GetSpectrumBrightnessAsync()
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.GetSpectrumBrightness
};
return await SendRequestAsync(req).ConfigureAwait(false)
?? throw new IpcException("Missing return message");
}
public static Task SetSpectrumBrightnessAsync(string value)
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.SetSpectrumBrightness,
Value = value
};
return SendRequestAsync(req);
}
public static async Task GetRGBPresetAsync()
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.GetRGBPreset
};
return await SendRequestAsync(req).ConfigureAwait(false)
?? throw new IpcException("Missing return message");
}
public static Task SetRGBPresetAsync(string value)
{
var req = new IpcRequest
{
Operation = IpcRequest.OperationType.SetRGBPreset,
Value = value
};
return SendRequestAsync(req);
}
private static async Task SendRequestAsync(IpcRequest req)
{
await using var pipe = new NamedPipeClientStream(Constants.PIPE_NAME);
await ConnectAsync(pipe).ConfigureAwait(false);
await pipe.WriteObjectAsync(req).ConfigureAwait(false);
var res = await pipe.ReadObjectAsync().ConfigureAwait(false);
if (res is null || !res.Success)
throw new IpcException(res?.Message ?? "Unknown failure");
return res.Message;
}
private static async Task ConnectAsync(NamedPipeClientStream pipe)
{
var retries = 3;
while (retries >= 0)
{
try
{
await pipe.ConnectAsync(TimeSpan.FromMilliseconds(500), CancellationToken.None).ConfigureAwait(false);
pipe.ReadMode = PipeTransmissionMode.Message;
return;
}
catch (TimeoutException) { }
retries--;
}
throw new IpcConnectException();
}
}
================================================
FILE: LenovoLegionToolkit.CLI/LenovoLegionToolkit.CLI.csproj
================================================
Exe
net8.0-windows
win-x64
enable
© 2024 Bartosz Cichecki
llt
x64
0.0.1
0.0.1
en
build$([System.DateTime]::UtcNow.ToString("yyyyMMddHHmmss"))
en
en
portable
embedded
================================================
FILE: LenovoLegionToolkit.CLI/Program.cs
================================================
using System;
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Invocation;
using System.CommandLine.IO;
using System.CommandLine.Parsing;
using System.Threading.Tasks;
using LenovoLegionToolkit.CLI.Lib;
namespace LenovoLegionToolkit.CLI;
public class Program
{
public static Task Main(string[] args) => BuildCommandLine().InvokeAsync(args);
private static Parser BuildCommandLine()
{
var root = new RootCommand("Utility that controls Lenovo Legion Toolkit from command line.\n\n" +
"Lenovo Legion Toolkit must be running in the background and CLI setting must be " +
"turned on for this utility to work.");
var builder = new CommandLineBuilder(root)
.UseDefaults()
.UseExceptionHandler(OnException);
root.AddCommand(BuildQuickActionsCommand());
root.AddCommand(BuildFeatureCommand());
root.AddCommand(BuildSpectrumCommand());
root.AddCommand(BuildRGBCommand());
return builder.Build();
}
private static Command BuildQuickActionsCommand()
{
var nameArgument = new Argument("name", "Name of the Quick Action") { Arity = ArgumentArity.ZeroOrOne };
var listOption = new Option("--list", "List available Quick Actions") { Arity = ArgumentArity.ZeroOrOne };
listOption.AddAlias("-l");
var cmd = new Command("quickAction", "Run Quick Action");
cmd.AddAlias("qa");
cmd.AddArgument(nameArgument);
cmd.AddOption(listOption);
cmd.SetHandler(async (name, list) =>
{
if (list)
{
var result = await IpcClient.ListQuickActionsAsync();
Console.WriteLine(result);
return;
}
await IpcClient.RunQuickActionAsync(name);
}, nameArgument, listOption);
cmd.AddValidator(result =>
{
if (result.FindResultFor(nameArgument) is not null)
return;
if (result.FindResultFor(listOption) is not null)
return;
result.ErrorMessage = $"{nameArgument.Name} or --{listOption.Name} should be specified";
});
return cmd;
}
private static Command BuildFeatureCommand()
{
var getCmd = BuildGetFeatureCommand();
var setCmd = BuildSetFeatureCommand();
var listOption = new Option("--list", "List available features") { Arity = ArgumentArity.ZeroOrOne };
listOption.AddAlias("-l");
var cmd = new Command("feature", "Control features");
cmd.AddAlias("f");
cmd.AddCommand(getCmd);
cmd.AddCommand(setCmd);
cmd.AddOption(listOption);
cmd.SetHandler(async list =>
{
if (!list.HasValue || !list.Value)
return;
var value = await IpcClient.ListFeaturesAsync();
Console.WriteLine(value);
}, listOption);
cmd.AddValidator(result =>
{
if (result.FindResultFor(getCmd) is not null)
return;
if (result.FindResultFor(setCmd) is not null)
return;
if (result.FindResultFor(listOption) is not null)
return;
result.ErrorMessage = $"{getCmd.Name}, {setCmd.Name} or --{listOption.Name} should be specified";
});
return cmd;
}
private static Command BuildGetFeatureCommand()
{
var nameArgument = new Argument("name", "Name of the feature") { Arity = ArgumentArity.ExactlyOne };
var cmd = new Command("get", "Get value of a feature");
cmd.AddAlias("g");
cmd.AddArgument(nameArgument);
cmd.SetHandler(async name =>
{
var result = await IpcClient.GetFeatureValueAsync(name);
Console.WriteLine(result);
}, nameArgument);
return cmd;
}
private static Command BuildSetFeatureCommand()
{
var nameArgument = new Argument("name", "Name of the feature") { Arity = ArgumentArity.ExactlyOne };
var valueArgument = new Argument("value", "Value of the feature") { Arity = ArgumentArity.ZeroOrOne };
var listOption = new Option("--list", "List available feature values") { Arity = ArgumentArity.ZeroOrOne };
listOption.AddAlias("-l");
var cmd = new Command("set", "Set value of a feature");
cmd.AddAlias("s");
cmd.AddArgument(nameArgument);
cmd.AddArgument(valueArgument);
cmd.AddOption(listOption);
cmd.SetHandler(async (name, value, list) =>
{
if (list)
{
var result = await IpcClient.ListFeatureValuesAsync(name);
Console.WriteLine(result);
return;
}
await IpcClient.SetFeatureValueAsync(name, value);
}, nameArgument, valueArgument, listOption);
cmd.AddValidator(result =>
{
if (result.FindResultFor(nameArgument) is not null)
return;
if (result.FindResultFor(listOption) is not null)
return;
result.ErrorMessage = $"{nameArgument.Name} or --{listOption.Name} should be specified";
});
return cmd;
}
private static Command BuildSpectrumCommand()
{
var profileCommand = BuildSpectrumProfileCommand();
var brightnessCommand = BuildSpectrumBrightnessCommand();
var cmd = new Command("spectrum", "Control Spectrum backlight");
cmd.AddAlias("s");
cmd.AddCommand(profileCommand);
cmd.AddCommand(brightnessCommand);
return cmd;
}
private static Command BuildSpectrumProfileCommand()
{
var getCmd = BuildGetSpectrumProfileCommand();
var setCmd = BuildSetSpectrumProfileCommand();
var cmd = new Command("profile", "Control Spectrum backlight profile");
cmd.AddAlias("p");
cmd.AddCommand(getCmd);
cmd.AddCommand(setCmd);
return cmd;
}
private static Command BuildGetSpectrumProfileCommand()
{
var cmd = new Command("get", "Get current Spectrum profile");
cmd.AddAlias("g");
cmd.SetHandler(async _ =>
{
var result = await IpcClient.GetSpectrumProfileAsync();
Console.WriteLine(result);
});
return cmd;
}
private static Command BuildSetSpectrumProfileCommand()
{
var valueArgument = new Argument("profile", "Profile to set") { Arity = ArgumentArity.ExactlyOne };
var cmd = new Command("set", "Set current Spectrum profile");
cmd.AddAlias("s");
cmd.AddArgument(valueArgument);
cmd.SetHandler(async value =>
{
await IpcClient.SetSpectrumProfileAsync($"{value}");
}, valueArgument);
return cmd;
}
private static Command BuildSpectrumBrightnessCommand()
{
var getCmd = BuildGetSpectrumBrightnessCommand();
var setCmd = BuildSetSpectrumBrightnessCommand();
var cmd = new Command("brightness", "Control Spectrum brightness");
cmd.AddAlias("b");
cmd.AddCommand(getCmd);
cmd.AddCommand(setCmd);
return cmd;
}
private static Command BuildGetSpectrumBrightnessCommand()
{
var cmd = new Command("get", "Get current Spectrum brightness");
cmd.AddAlias("g");
cmd.SetHandler(async _ =>
{
var result = await IpcClient.GetSpectrumBrightnessAsync();
Console.WriteLine(result);
});
return cmd;
}
private static Command BuildSetSpectrumBrightnessCommand()
{
var valueArgument = new Argument("brightness", "Brightness to set") { Arity = ArgumentArity.ExactlyOne };
var cmd = new Command("set", "Set current Spectrum brightness");
cmd.AddAlias("s");
cmd.AddArgument(valueArgument);
cmd.SetHandler(async value =>
{
await IpcClient.SetSpectrumBrightnessAsync($"{value}");
}, valueArgument);
return cmd;
}
private static Command BuildRGBCommand()
{
var getCmd = BuildGetRGBCommand();
var setCmd = BuildSetRGBCommand();
var cmd = new Command("rgb", "Control RGB backlight preset");
cmd.AddAlias("r");
cmd.AddCommand(getCmd);
cmd.AddCommand(setCmd);
return cmd;
}
private static Command BuildGetRGBCommand()
{
var cmd = new Command("get", "Get current RGB preset");
cmd.AddAlias("g");
cmd.SetHandler(async _ =>
{
var result = await IpcClient.GetRGBPresetAsync();
Console.WriteLine(result);
});
return cmd;
}
private static Command BuildSetRGBCommand()
{
var valueArgument = new Argument("preset", "Preset to set") { Arity = ArgumentArity.ExactlyOne };
var cmd = new Command("set", "Set current RGB preset");
cmd.AddAlias("s");
cmd.AddArgument(valueArgument);
cmd.SetHandler(async value =>
{
await IpcClient.SetRGBPresetAsync($"{value}");
}, valueArgument);
return cmd;
}
private static void OnException(Exception ex, InvocationContext context)
{
var message = ex switch
{
IpcConnectException => "Failed to connect. " +
"Make sure that Lenovo Legion Toolkit is running " +
"in background and CLI is enabled in Settings.",
IpcException => ex.Message,
_ => ex.ToString()
};
var exitCode = ex switch
{
IpcConnectException => -1,
IpcException => -2,
_ => -99
};
if (!Console.IsOutputRedirected)
{
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Red;
}
context.Console.Error.WriteLine(message);
context.ExitCode = exitCode;
if (!Console.IsOutputRedirected)
Console.ResetColor();
}
}
================================================
FILE: LenovoLegionToolkit.CLI.Lib/Constants.cs
================================================
namespace LenovoLegionToolkit.CLI.Lib;
public static class Constants
{
public const string PIPE_NAME = "LenovoLegionToolkit-IPC-0";
}
================================================
FILE: LenovoLegionToolkit.CLI.Lib/Extensions/PipeStreamExtensions.cs
================================================
using System;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace LenovoLegionToolkit.CLI.Lib.Extensions;
public static class PipeStreamExtensions
{
private static readonly Encoding Encoding = Encoding.UTF8;
public static async Task WriteObjectAsync(this PipeStream stream, T obj, CancellationToken token = default)
{
if (stream.ReadMode != PipeTransmissionMode.Message)
throw new InvalidOperationException("ReadMode is not PipeTransmissionMode.Message");
var str = JsonConvert.SerializeObject(obj);
var bytes = Encoding.GetBytes(str);
await stream.WriteAsync(bytes, token).ConfigureAwait(false);
}
public static async Task ReadObjectAsync(this PipeStream stream, CancellationToken token = default)
{
if (stream.ReadMode != PipeTransmissionMode.Message)
throw new InvalidOperationException("ReadMode is not PipeTransmissionMode.Message");
var buffer = new byte[1024];
var builder = new StringBuilder();
do
{
_ = await stream.ReadAsync(buffer, token).ConfigureAwait(false);
builder.Append(Encoding.GetString(buffer));
} while (!stream.IsMessageComplete);
return JsonConvert.DeserializeObject(builder.ToString());
}
}
================================================
FILE: LenovoLegionToolkit.CLI.Lib/IpcConnectException.cs
================================================
using System;
namespace LenovoLegionToolkit.CLI.Lib;
public class IpcConnectException : Exception;
================================================
FILE: LenovoLegionToolkit.CLI.Lib/IpcException.cs
================================================
using System;
namespace LenovoLegionToolkit.CLI.Lib;
public class IpcException(string? name) : Exception(name);
================================================
FILE: LenovoLegionToolkit.CLI.Lib/IpcRequest.cs
================================================
namespace LenovoLegionToolkit.CLI.Lib;
public class IpcRequest
{
public enum OperationType
{
Unknown,
ListFeatures,
ListFeatureValues,
ListQuickActions,
GetFeatureValue,
SetFeatureValue,
GetSpectrumProfile,
SetSpectrumProfile,
GetSpectrumBrightness,
SetSpectrumBrightness,
GetRGBPreset,
SetRGBPreset,
QuickAction,
}
public OperationType? Operation { get; init; }
public string? Name { get; init; }
public string? Value { get; init; }
}
================================================
FILE: LenovoLegionToolkit.CLI.Lib/IpcResponse.cs
================================================
namespace LenovoLegionToolkit.CLI.Lib;
public class IpcResponse
{
public bool Success { get; init; }
public string? Message { get; init; }
}
================================================
FILE: LenovoLegionToolkit.CLI.Lib/LenovoLegionToolkit.CLI.Lib.csproj
================================================
net8.0-windows
win-x64
x64
disable
enable
© 2024 Bartosz Cichecki
en
================================================
FILE: LenovoLegionToolkit.Lib/AutoListeners/AbstractAutoListener.cs
================================================
using System;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Utils;
using NeoSmart.AsyncLock;
namespace LenovoLegionToolkit.Lib.AutoListeners;
public abstract class AbstractAutoListener : IAutoListener where TEventArgs : EventArgs
{
private readonly AsyncLock _startStopLock = new();
private bool _started;
private event EventHandler? Changed;
public async Task SubscribeChangedAsync(EventHandler eventHandler)
{
Changed += eventHandler;
await StartStopAsync().ConfigureAwait(false);
}
public async Task UnsubscribeChangedAsync(EventHandler eventHandler)
{
Changed -= eventHandler;
await StartStopAsync().ConfigureAwait(false);
}
private async Task StartStopAsync()
{
using (await _startStopLock.LockAsync().ConfigureAwait(false))
{
var subscribers = Changed?.GetInvocationList().Length ?? 0;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Subscribers: {subscribers}. [type={GetType().Name}]");
if (subscribers > 0)
await StartInternalAsync().ConfigureAwait(false);
else
await StopInternalAsync().ConfigureAwait(false);
}
}
private async Task StartInternalAsync()
{
if (_started)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Already started. [type={GetType().Name}]");
return;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Starting... [type={GetType().Name}]");
await StartAsync().ConfigureAwait(false);
_started = true;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Started. [type={GetType().Name}]");
}
private async Task StopInternalAsync()
{
if (!_started)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Already stopped. [type={GetType().Name}]");
return;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Stopping... [type={GetType().Name}]");
await StopAsync().ConfigureAwait(false);
_started = false;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Stopped. [type={GetType().Name}]");
}
protected abstract Task StartAsync();
protected abstract Task StopAsync();
protected void RaiseChanged(TEventArgs value) => Changed?.Invoke(this, value);
}
================================================
FILE: LenovoLegionToolkit.Lib/AutoListeners/GameAutoListener.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.GameDetection;
using LenovoLegionToolkit.Lib.Utils;
namespace LenovoLegionToolkit.Lib.AutoListeners;
public class GameAutoListener : AbstractAutoListener
{
public class ChangedEventArgs(bool running) : EventArgs
{
public bool Running { get; } = running;
}
private class ProcessEqualityComparer : IEqualityComparer
{
public bool Equals(Process? x, Process? y)
{
if (ReferenceEquals(x, y)) return true;
if (x is null) return false;
if (y is null) return false;
if (x.GetType() != y.GetType()) return false;
return x.Id == y.Id;
}
public int GetHashCode(Process obj) => obj.Id;
}
private static readonly object Lock = new();
private readonly InstanceStartedEventAutoAutoListener _instanceStartedEventAutoAutoListener;
private readonly GameConfigStoreDetector _gameConfigStoreDetector;
private readonly EffectiveGameModeDetector _effectiveGameModeDetector;
private readonly HashSet _detectedGamePathsCache = [];
private readonly HashSet _processCache = new(new ProcessEqualityComparer());
private bool _lastState;
public GameAutoListener(InstanceStartedEventAutoAutoListener instanceStartedEventAutoAutoListener)
{
_instanceStartedEventAutoAutoListener = instanceStartedEventAutoAutoListener;
_gameConfigStoreDetector = new GameConfigStoreDetector();
_gameConfigStoreDetector.GamesDetected += GameConfigStoreDetectorGamesConfigStoreDetected;
_effectiveGameModeDetector = new EffectiveGameModeDetector();
_effectiveGameModeDetector.Changed += EffectiveGameModeDetectorChanged;
}
protected override async Task StartAsync()
{
lock (Lock)
{
foreach (var gamePath in GameConfigStoreDetector.GetDetectedGamePaths())
_detectedGamePathsCache.Add(gamePath);
}
await _gameConfigStoreDetector.StartAsync().ConfigureAwait(false);
await _effectiveGameModeDetector.StartAsync().ConfigureAwait(false);
await _instanceStartedEventAutoAutoListener.SubscribeChangedAsync(InstanceStartedEventAutoAutoListener_Changed).ConfigureAwait(false);
}
protected override async Task StopAsync()
{
await _instanceStartedEventAutoAutoListener.UnsubscribeChangedAsync(InstanceStartedEventAutoAutoListener_Changed).ConfigureAwait(false);
await _gameConfigStoreDetector.StopAsync().ConfigureAwait(false);
await _effectiveGameModeDetector.StopAsync().ConfigureAwait(false);
lock (Lock)
{
foreach (var process in _processCache)
Detach(process);
_processCache.Clear();
_detectedGamePathsCache.Clear();
_lastState = false;
}
}
public bool AreGamesRunning()
{
lock (Lock)
{
return _lastState;
}
}
private void GameConfigStoreDetectorGamesConfigStoreDetected(object? sender, GameConfigStoreDetector.GameDetectedEventArgs e)
{
lock (Lock)
{
_detectedGamePathsCache.Clear();
foreach (var game in e.Games)
{
_detectedGamePathsCache.Add(game);
foreach (var process in Process.GetProcessesByName(game.Name))
{
try
{
var processPath = process.MainModule?.FileName;
if (game.ExecutablePath is null || !game.ExecutablePath.Equals(processPath, StringComparison.CurrentCultureIgnoreCase))
continue;
if (!_processCache.Contains(process))
{
Attach(process);
_processCache.Add(process);
}
RaiseChangedIfNeeded(true);
}
catch (Exception)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Can't get game \"{game}\" details.");
}
}
}
}
}
private void EffectiveGameModeDetectorChanged(object? sender, bool e)
{
lock (Lock)
{
if (_processCache.Count != 0)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Ignoring, process cache is not empty.");
return;
}
RaiseChangedIfNeeded(e);
}
}
private void InstanceStartedEventAutoAutoListener_Changed(object? sender, InstanceStartedEventAutoAutoListener.ChangedEventArgs e)
{
lock (Lock)
{
if (e.ProcessId < 0)
return;
if (!_detectedGamePathsCache.Any(p => e.ProcessName.Equals(p.Name, StringComparison.CurrentCultureIgnoreCase)))
return;
try
{
var process = Process.GetProcessById(e.ProcessId);
var processPath = process.GetFileName();
if (string.IsNullOrEmpty(processPath))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Can't get path for {e.ProcessName}. [processId={e.ProcessId}]");
return;
}
var processInfo = ProcessInfo.FromPath(processPath);
if (!_detectedGamePathsCache.Contains(processInfo))
return;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Game {processInfo} is running. [processId={e.ProcessId}, processPath={processPath}]");
Attach(process);
_processCache.Add(process);
RaiseChangedIfNeeded(true);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to attach to {e.ProcessName}. [processId={e.ProcessId}]", ex);
}
}
}
private void RaiseChangedIfNeeded(bool newState)
{
lock (Lock)
{
if (newState == _lastState)
return;
_lastState = newState;
RaiseChanged(new ChangedEventArgs(newState));
}
}
private void Attach(Process process)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Attaching to process {process.Id}...");
process.EnableRaisingEvents = true;
process.Exited += Process_Exited;
}
private void Detach(Process process)
{
process.EnableRaisingEvents = false;
process.Exited -= Process_Exited;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Detached from process {process.Id}.");
}
private void Process_Exited(object? o, EventArgs args)
{
lock (Lock)
{
if (o is not Process process)
return;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Process {process.Id} exited.");
var staleProcesses = _processCache.RemoveWhere(p =>
{
try { return p.HasExited; }
catch { return true; }
});
if (staleProcesses > 1)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Removed {staleProcesses} stale processes.");
}
if (_processCache.Count != 0)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"More games are running...");
return;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"No more games are running.");
RaiseChangedIfNeeded(false);
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/AutoListeners/IAutoListener.cs
================================================
using System;
using System.Threading.Tasks;
namespace LenovoLegionToolkit.Lib.AutoListeners;
public interface IAutoListener where T : EventArgs
{
Task SubscribeChangedAsync(EventHandler eventHandler);
Task UnsubscribeChangedAsync(EventHandler eventHandler);
}
================================================
FILE: LenovoLegionToolkit.Lib/AutoListeners/InstanceStartedEventAutoAutoListener.cs
================================================
using System;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.System.Management;
namespace LenovoLegionToolkit.Lib.AutoListeners;
public class InstanceStartedEventAutoAutoListener : AbstractAutoListener
{
public class ChangedEventArgs(int processId, string processName) : EventArgs
{
public int ProcessId { get; } = processId;
public string ProcessName { get; } = processName;
}
private IDisposable? _disposable;
protected override Task StartAsync()
{
_disposable = WMI.Win32.ProcessStartTrace.Listen(Handle);
return Task.CompletedTask;
}
protected override Task StopAsync()
{
_disposable?.Dispose();
_disposable = null;
return Task.CompletedTask;
}
private void Handle(int processId, string processName) => RaiseChanged(new ChangedEventArgs(processId, processName));
}
================================================
FILE: LenovoLegionToolkit.Lib/AutoListeners/InstanceStoppedEventAutoAutoListener.cs
================================================
using System;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.System.Management;
namespace LenovoLegionToolkit.Lib.AutoListeners;
public class InstanceStoppedEventAutoAutoListener : AbstractAutoListener
{
public class ChangedEventArgs(int processId, string processName) : EventArgs
{
public int ProcessId { get; } = processId;
public string ProcessName { get; } = processName;
}
private IDisposable? _disposable;
protected override Task StartAsync()
{
_disposable = WMI.Win32.ProcessStopTrace.Listen(Handle);
return Task.CompletedTask;
}
protected override Task StopAsync()
{
_disposable?.Dispose();
_disposable = null;
return Task.CompletedTask;
}
private void Handle(int processId, string processName) => RaiseChanged(new ChangedEventArgs(processId, processName));
}
================================================
FILE: LenovoLegionToolkit.Lib/AutoListeners/ProcessAutoListener.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.Utils;
namespace LenovoLegionToolkit.Lib.AutoListeners;
public class ProcessAutoListener(
InstanceStartedEventAutoAutoListener instanceStartedEventAutoAutoListener,
InstanceStoppedEventAutoAutoListener instanceStoppedEventAutoAutoListener)
: AbstractAutoListener
{
public class ChangedEventArgs(ProcessEventInfoType type, ProcessInfo processInfo) : EventArgs
{
public ProcessEventInfoType Type { get; } = type;
public ProcessInfo ProcessInfo { get; } = processInfo;
}
private static readonly object Lock = new();
// ReSharper disable StringLiteralTypo
private static readonly string[] IgnoredNames =
[
"backgroundTaskHost",
"cmd",
"CompPkgSrv",
"conhost",
"dllhost",
"Lenovo Legion Toolkit",
"msedge",
"msedgewebview2",
"NvOAWrapperCache",
"SearchProtocolHost",
"svchost",
"taskhostw",
"WmiApSrv",
"WmiPrvSE"
];
// ReSharper restore StringLiteralTypo
private static readonly string[] IgnoredPaths =
[
Environment.GetFolderPath(Environment.SpecialFolder.Windows),
];
private readonly Dictionary _processCache = [];
protected override async Task StartAsync()
{
await instanceStartedEventAutoAutoListener.SubscribeChangedAsync(InstanceStartedEventAutoListener_Changed).ConfigureAwait(false);
await instanceStoppedEventAutoAutoListener.SubscribeChangedAsync(InstanceStoppedEventAutoListener_Changed).ConfigureAwait(false);
}
protected override async Task StopAsync()
{
await instanceStartedEventAutoAutoListener.UnsubscribeChangedAsync(InstanceStartedEventAutoListener_Changed).ConfigureAwait(false);
await instanceStoppedEventAutoAutoListener.UnsubscribeChangedAsync(InstanceStoppedEventAutoListener_Changed).ConfigureAwait(false);
lock (Lock)
_processCache.Clear();
}
private void InstanceStartedEventAutoListener_Changed(object? sender, InstanceStartedEventAutoAutoListener.ChangedEventArgs e)
{
lock (Lock)
{
if (e.ProcessId < 0)
return;
if (string.IsNullOrWhiteSpace(e.ProcessName))
return;
if (IgnoredNames.Contains(e.ProcessName, StringComparer.InvariantCultureIgnoreCase))
return;
string? processPath = null;
try
{
processPath = Process.GetProcessById(e.ProcessId).GetFileName();
}
catch (ArgumentException)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Process {e.ProcessName} isn't running, ignoring... [processId={e.ProcessId}]");
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Can't get process {e.ProcessName} details. [processId={e.ProcessId}]", ex);
}
if (!string.IsNullOrEmpty(processPath) && IgnoredPaths.Any(p => processPath.StartsWith(p, StringComparison.InvariantCultureIgnoreCase)))
return;
var processInfo = new ProcessInfo(e.ProcessName, processPath);
_processCache[e.ProcessId] = processInfo;
CleanUpCacheIfNecessary();
RaiseChanged(new ChangedEventArgs(ProcessEventInfoType.Started, processInfo));
}
}
private void InstanceStoppedEventAutoListener_Changed(object? sender, InstanceStoppedEventAutoAutoListener.ChangedEventArgs e)
{
lock (Lock)
{
CleanUpCacheIfNecessary();
if (e.ProcessId < 0)
return;
if (string.IsNullOrWhiteSpace(e.ProcessName))
return;
if (IgnoredNames.Contains(e.ProcessName, StringComparer.InvariantCultureIgnoreCase))
return;
if (!_processCache.Remove(e.ProcessId, out var processInfo))
return;
RaiseChanged(new ChangedEventArgs(ProcessEventInfoType.Stopped, processInfo));
}
}
private void CleanUpCacheIfNecessary()
{
if (_processCache.Count < 250)
return;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Cleaning up process cache. Current size: {_processCache.Count}.");
foreach (var (processId, _) in _processCache)
{
try
{
_ = Process.GetProcessById(processId);
}
catch (ArgumentException)
{
_processCache.Remove(processId);
}
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Cleaned up process cache. Current size: {_processCache.Count}.");
}
}
================================================
FILE: LenovoLegionToolkit.Lib/AutoListeners/TimeAutoListener.cs
================================================
using System;
using System.Threading.Tasks;
using System.Timers;
using LenovoLegionToolkit.Lib.Extensions;
namespace LenovoLegionToolkit.Lib.AutoListeners;
public class TimeAutoListener : AbstractAutoListener
{
public class ChangedEventArgs(Time time, DayOfWeek day) : EventArgs
{
public Time Time { get; } = time;
public DayOfWeek Day { get; } = day;
}
private readonly Timer _timer;
public TimeAutoListener()
{
_timer = new Timer(60_000);
_timer.Elapsed += Timer_Elapsed;
_timer.AutoReset = true;
}
protected override Task StartAsync()
{
if (!_timer.Enabled)
_timer.Enabled = true;
return Task.CompletedTask;
}
protected override Task StopAsync()
{
_timer.Enabled = false;
return Task.CompletedTask;
}
private void Timer_Elapsed(object? sender, ElapsedEventArgs e) => RaiseChanged(new ChangedEventArgs(TimeExtensions.UtcNow, DateTime.UtcNow.DayOfWeek));
}
================================================
FILE: LenovoLegionToolkit.Lib/AutoListeners/UserInactivityAutoListener.cs
================================================
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using LenovoLegionToolkit.Lib.Utils;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
using Timer = System.Threading.Timer;
namespace LenovoLegionToolkit.Lib.AutoListeners;
public class UserInactivityAutoListener(IMainThreadDispatcher mainThreadDispatcher)
: AbstractAutoListener
{
public class ChangedEventArgs(TimeSpan timerResolution, uint tickCount) : EventArgs
{
public TimeSpan TimerResolution { get; } = timerResolution;
public uint TickCount { get; } = tickCount;
}
private class UserInactivityWindow : NativeWindow, IDisposable
{
private readonly Action _callback;
private readonly HOOKPROC _hookProc;
private HHOOK _kbHook;
private HHOOK _mouseHook;
public UserInactivityWindow(Action callback)
{
_callback = callback;
_hookProc = HookProc;
}
public void Create()
{
CreateHandle(new CreateParams
{
Caption = "LenovoLegionToolkit_UserInactivityListenerWindow",
Parent = new IntPtr(-3)
});
_kbHook = PInvoke.SetWindowsHookEx(WINDOWS_HOOK_ID.WH_KEYBOARD_LL, _hookProc, HINSTANCE.Null, 0);
_mouseHook = PInvoke.SetWindowsHookEx(WINDOWS_HOOK_ID.WH_MOUSE_LL, _hookProc, HINSTANCE.Null, 0);
}
private LRESULT HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
_callback();
return PInvoke.CallNextHookEx(HHOOK.Null, nCode, wParam, lParam);
}
public void Dispose()
{
PInvoke.UnhookWindowsHookEx(_kbHook);
PInvoke.UnhookWindowsHookEx(_mouseHook);
_kbHook = HHOOK.Null;
_mouseHook = HHOOK.Null;
ReleaseHandle();
GC.SuppressFinalize(this);
}
}
private readonly TimeSpan _timerResolution = TimeSpan.FromSeconds(10);
private readonly object _lock = new();
private UserInactivityWindow? _window;
private uint _tickCount;
private Timer? _timer;
public TimeSpan InactivityTimeSpan => _timerResolution * _tickCount;
protected override Task StartAsync() => mainThreadDispatcher.DispatchAsync(() =>
{
lock (_lock)
{
_timer = new Timer(TimerCallback, null, _timerResolution, _timerResolution);
_tickCount = 0;
var window = new UserInactivityWindow(WindowCallback);
window.Create();
_window = window;
}
return Task.CompletedTask;
});
protected override Task StopAsync() => mainThreadDispatcher.DispatchAsync(() =>
{
lock (_lock)
{
_timer?.Dispose();
_timer = null;
_tickCount = 0;
_window?.Dispose();
_window = null;
}
return Task.CompletedTask;
});
private void WindowCallback()
{
lock (_lock)
{
_timer?.Change(_timerResolution, _timerResolution);
if (_tickCount < 1)
return;
_tickCount = 0;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"User became active.");
RaiseChanged(new ChangedEventArgs(_timerResolution, 0));
}
}
private void TimerCallback(object? state)
{
lock (_lock)
{
_tickCount++;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"User is not active [time={_timerResolution * _tickCount}]");
RaiseChanged(new ChangedEventArgs(_timerResolution, _tickCount));
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/AutoListeners/WiFiAutoListener.cs
================================================
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Utils;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.NetworkManagement.WiFi;
namespace LenovoLegionToolkit.Lib.AutoListeners;
public class WiFiAutoListener : AbstractAutoListener
{
public class ChangedEventArgs(bool isConnected, string? ssid) : EventArgs
{
public bool IsConnected { get; } = isConnected;
public string? Ssid { get; } = ssid;
}
private readonly IMainThreadDispatcher _mainThreadDispatcher;
private readonly WLAN_NOTIFICATION_CALLBACK _wlanCallback;
private LambdaDisposable? _wlanNotificationDisposable;
public unsafe WiFiAutoListener(IMainThreadDispatcher mainThreadDispatcher)
{
_mainThreadDispatcher = mainThreadDispatcher;
_wlanCallback = WlanCallback;
}
protected override Task StartAsync() => _mainThreadDispatcher.DispatchAsync(() =>
{
_wlanNotificationDisposable = RegisterWlanNotification();
return Task.CompletedTask;
});
protected override Task StopAsync() => _mainThreadDispatcher.DispatchAsync(() =>
{
_wlanNotificationDisposable?.Dispose();
_wlanNotificationDisposable = null;
return Task.CompletedTask;
});
private unsafe LambdaDisposable? RegisterWlanNotification()
{
var handlePtr = IntPtr.Zero;
try
{
handlePtr = Marshal.AllocHGlobal(Marshal.SizeOf());
if (PInvoke.WlanOpenHandle(2, out _, (HANDLE*)handlePtr) != 0)
return null;
var handle = Marshal.PtrToStructure(handlePtr);
var result = PInvoke.WlanRegisterNotification(handle,
WLAN_NOTIFICATION_SOURCES.WLAN_NOTIFICATION_SOURCE_ACM,
true,
_wlanCallback,
null,
null,
null);
if (result != 0)
return null;
return new LambdaDisposable(() =>
{
_ = PInvoke.WlanRegisterNotification(handle,
WLAN_NOTIFICATION_SOURCES.WLAN_NOTIFICATION_SOURCE_NONE,
true,
_wlanCallback,
null,
null,
null);
_ = PInvoke.WlanCloseHandle(handle, null);
});
}
finally
{
Marshal.FreeHGlobal(handlePtr);
}
}
private unsafe void WlanCallback(L2_NOTIFICATION_DATA* param0, void* param1)
{
ref var data = ref Unsafe.AsRef(param0);
switch (data.NotificationCode)
{
case 0x0A: /* Connected */
ref var notificationData = ref Unsafe.AsRef(data.pData);
var dot11Ssid = notificationData.dot11Ssid;
var ssid = Encoding.UTF8.GetString(dot11Ssid.ucSSID.Value, (int)dot11Ssid.uSSIDLength);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"WiFi connected. [ssid={ssid}]");
RaiseChanged(new ChangedEventArgs(true, ssid));
break;
case 0x15: /* Disconnected */
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"WiFi disconnected.");
RaiseChanged(new ChangedEventArgs(false, null));
break;
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/AIController.cs
================================================
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.AutoListeners;
using LenovoLegionToolkit.Lib.Features;
using LenovoLegionToolkit.Lib.Listeners;
using LenovoLegionToolkit.Lib.Settings;
using LenovoLegionToolkit.Lib.System;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
using NeoSmart.AsyncLock;
namespace LenovoLegionToolkit.Lib.Controllers;
public class AIController(
PowerModeListener powerModeListener,
PowerStateListener powerStateListener,
GameAutoListener gameAutoListener,
PowerModeFeature powerModeFeature,
BalanceModeSettings settings)
{
private readonly ThrottleLastDispatcher _dispatcher = new(TimeSpan.FromSeconds(1), nameof(AIController));
private readonly AsyncLock _startStopLock = new();
public bool IsAIModeEnabled
{
get => settings.Store.AIModeEnabled;
set
{
settings.Store.AIModeEnabled = value;
settings.SynchronizeStore();
}
}
public async Task StartIfNeededAsync()
{
if (!await IsSupportedAsync().ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Not supported.");
return;
}
await StopAsync().ConfigureAwait(false);
if (!IsAIModeEnabled)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"AI Mode is not enabled.");
return;
}
using (await _startStopLock.LockAsync().ConfigureAwait(false))
{
powerModeListener.Changed += PowerModeListener_Changed;
powerStateListener.Changed += PowerStateListener_Changed;
await gameAutoListener.SubscribeChangedAsync(GameAutoListener_Changed).ConfigureAwait(false);
await RefreshAsync().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Started.");
}
}
public async Task StopAsync()
{
if (!await IsSupportedAsync().ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Not supported.");
return;
}
using (await _startStopLock.LockAsync().ConfigureAwait(false))
{
powerModeListener.Changed -= PowerModeListener_Changed;
powerStateListener.Changed -= PowerStateListener_Changed;
await gameAutoListener.UnsubscribeChangedAsync(GameAutoListener_Changed).ConfigureAwait(false);
if (await ShouldDisableAsync().ConfigureAwait(false))
await DisableAsync().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Stopped.");
}
}
private async void PowerModeListener_Changed(object? sender, PowerModeListener.ChangedEventArgs e) => await _dispatcher.DispatchAsync(RefreshAsync).ConfigureAwait(false);
private async void PowerStateListener_Changed(object? sender, PowerStateListener.ChangedEventArgs e) => await _dispatcher.DispatchAsync(RefreshAsync).ConfigureAwait(false);
private async void GameAutoListener_Changed(object? sender, GameAutoListener.ChangedEventArgs e) => await _dispatcher.DispatchAsync(RefreshAsync).ConfigureAwait(false);
private async Task RefreshAsync()
{
if (!await IsSupportedAsync().ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Not supported.");
return;
}
using (await _startStopLock.LockAsync().ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Refreshing...");
if (await ShouldDisableAsync().ConfigureAwait(false))
await DisableAsync().ConfigureAwait(false);
if (await ShouldEnableAsync().ConfigureAwait(false))
await EnableAsync().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Refreshed");
}
}
private static async Task IsSupportedAsync()
{
var mi = await Compatibility.GetMachineInformationAsync().ConfigureAwait(false);
return mi.Properties.SupportsAIMode;
}
private async Task ShouldEnableAsync()
{
if (await Power.IsPowerAdapterConnectedAsync().ConfigureAwait(false) != PowerAdapterStatus.Connected)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Power adapter not connected.");
return false;
}
if (await powerModeFeature.GetStateAsync().ConfigureAwait(false) != PowerModeState.Balance)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Not in balanced mode.");
return false;
}
if (!gameAutoListener.AreGamesRunning())
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Games aren't running.");
return false;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"All conditions met.");
return true;
}
private async Task ShouldDisableAsync()
{
if (await powerModeFeature.GetStateAsync().ConfigureAwait(false) != PowerModeState.Balance)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Not in balanced mode.");
return false;
}
if (await WMI.LenovoGameZoneData.GetIntelligentSubModeAsync().ConfigureAwait(false) == 0)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Not needed.");
return false;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"All conditions met.");
return true;
}
private static async Task EnableAsync()
{
try
{
var targetSubMode = 1;
var intelligentOpList = await WMI.LenovoIntelligentOPList.ReadAsync().ConfigureAwait(false);
foreach (var (processName, subMode) in intelligentOpList)
{
var process = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(processName)).FirstOrDefault();
if (process is null)
continue;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Found running process {processName}. [processId={process.Id}, subMode={subMode}]");
targetSubMode = subMode;
break;
}
await WMI.LenovoGameZoneData.SetIntelligentSubModeAsync(targetSubMode).ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Initial sub mode set.");
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to start.", ex);
}
}
private static async Task DisableAsync()
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Stopping...");
await WMI.LenovoGameZoneData.SetIntelligentSubModeAsync(0).ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Stopped");
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to stop.", ex);
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/DisplayBrightnessController.cs
================================================
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.System.Management;
namespace LenovoLegionToolkit.Lib.Controllers;
public class DisplayBrightnessController
{
public Task SetBrightnessAsync(int brightness) => WMI.WmiMonitorBrightnessMethods.WmiSetBrightness(brightness, 1);
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/GPUController.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.Resources;
using LenovoLegionToolkit.Lib.System;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
using NeoSmart.AsyncLock;
namespace LenovoLegionToolkit.Lib.Controllers;
public class GPUController
{
private readonly AsyncLock _lock = new();
private Task? _refreshTask;
private CancellationTokenSource? _refreshCancellationTokenSource;
private GPUState _state = GPUState.Unknown;
private List _processes = [];
private string? _gpuInstanceId;
private string? _performanceState;
public event EventHandler? Refreshed;
public bool IsStarted { get => _refreshTask != null; }
public bool IsSupported()
{
try
{
NVAPI.Initialize();
return NVAPI.GetGPU() is not null;
}
catch
{
return false;
}
finally
{
try
{
NVAPI.Unload();
}
catch { /* Ignored. */ }
}
}
public async Task GetLastKnownStateAsync()
{
using (await _lock.LockAsync().ConfigureAwait(false))
return _state;
}
public async Task RefreshNowAsync()
{
using (await _lock.LockAsync().ConfigureAwait(false))
{
await RefreshLoopAsync(0, 0, CancellationToken.None).ConfigureAwait(false);
return new GPUStatus(_state, _performanceState, _processes);
}
}
public Task StartAsync(int delay = 1_000, int interval = 5_000)
{
if (IsStarted)
return Task.CompletedTask;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Starting... [delay={delay}, interval={interval}]");
_refreshCancellationTokenSource = new CancellationTokenSource();
var token = _refreshCancellationTokenSource.Token;
_refreshTask = Task.Run(() => RefreshLoopAsync(delay, interval, token), token);
return Task.CompletedTask;
}
public async Task StopAsync(bool waitForFinish = false)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Stopping... [refreshTask.isNull={_refreshTask is null}, _refreshCancellationTokenSource.IsCancellationRequested={_refreshCancellationTokenSource?.IsCancellationRequested}]");
if (_refreshCancellationTokenSource is not null)
await _refreshCancellationTokenSource.CancelAsync().ConfigureAwait(false);
if (waitForFinish)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Waiting to finish...");
if (_refreshTask is not null)
{
try
{
await _refreshTask.ConfigureAwait(false);
}
catch (OperationCanceledException) { }
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Finished");
}
_refreshCancellationTokenSource = null;
_refreshTask = null;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Stopped");
}
public async Task RestartGPUAsync()
{
using (await _lock.LockAsync().ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Deactivating... [state={_state}, gpuInstanceId={_gpuInstanceId}]");
if (_state is not GPUState.Active and not GPUState.Inactive)
return;
if (string.IsNullOrEmpty(_gpuInstanceId))
return;
await CMD.RunAsync("pnputil", $"/restart-device \"{_gpuInstanceId}\"").ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Deactivating... [state= {_state}, gpuInstanceId={_gpuInstanceId}]");
}
}
public async Task KillGPUProcessesAsync()
{
using (await _lock.LockAsync().ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Deactivating... [state= {_state}, gpuInstanceId={_gpuInstanceId}]");
if (_state is not GPUState.Active)
return;
if (string.IsNullOrEmpty(_gpuInstanceId))
return;
foreach (var process in _processes)
{
try
{
process.Kill(true);
await process.WaitForExitAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Couldn't kill process. [pid={process.Id}, name={process.ProcessName}]", ex);
}
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Deactivating... [state= {_state}, gpuInstanceId={_gpuInstanceId}]");
}
}
private async Task RefreshLoopAsync(int delay, int interval, CancellationToken token)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Initializing NVAPI...");
NVAPI.Initialize();
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Initialized NVAPI");
await Task.Delay(delay, token).ConfigureAwait(false);
while (true)
{
token.ThrowIfCancellationRequested();
using (await _lock.LockAsync(token).ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Will refresh...");
await RefreshStateAsync().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Refreshed");
Refreshed?.Invoke(this, new GPUStatus(_state, _performanceState, _processes));
}
if (interval > 0)
await Task.Delay(interval, token).ConfigureAwait(false);
else
break;
}
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Exception occurred", ex);
throw;
}
finally
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Unloading NVAPI...");
NVAPI.Unload();
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Unloaded NVAPI");
}
}
private async Task RefreshStateAsync()
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Refresh in progress...");
_state = GPUState.Unknown;
_processes = [];
_gpuInstanceId = null;
_performanceState = null;
var gpu = NVAPI.GetGPU();
if (gpu is null)
{
_state = GPUState.NvidiaGpuNotFound;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"GPU present [state={_state}, processes.Count={_processes.Count}, gpuInstanceId={_gpuInstanceId}]");
return;
}
try
{
var stateId = gpu.PerformanceStatesInfo.CurrentPerformanceState.StateId.ToString().GetUntilOrEmpty("_");
_performanceState = Resource.GPUController_PoweredOn;
if (!string.IsNullOrWhiteSpace(stateId))
_performanceState += $", {stateId}";
}
catch (Exception ex) when (ex.Message == "NVAPI_GPU_NOT_POWERED")
{
_state = GPUState.PoweredOff;
_performanceState = Resource.GPUController_PoweredOff;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Powered off [state={_state}, processes.Count={_processes.Count}, gpuInstanceId={_gpuInstanceId}]");
return;
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"GPU status exception.", ex);
_performanceState = "Unknown";
}
var pnpDeviceIdPart = NVAPI.GetGPUId(gpu);
if (string.IsNullOrEmpty(pnpDeviceIdPart))
throw new InvalidOperationException("pnpDeviceIdPart is null or empty");
var gpuInstanceId = await WMI.Win32.PnpEntity.GetDeviceIDAsync(pnpDeviceIdPart).ConfigureAwait(false);
var processNames = NVAPIExtensions.GetActiveProcesses(gpu);
if (NVAPI.IsDisplayConnected(gpu))
{
_processes = processNames;
_state = GPUState.MonitorConnected;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace(
$"Monitor connected [state={_state}, processes.Count={_processes.Count}, gpuInstanceId={_gpuInstanceId}]");
}
else if (processNames.Count != 0)
{
_processes = processNames;
_state = GPUState.Active;
_gpuInstanceId = gpuInstanceId;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Active [state={_state}, processes.Count={_processes.Count}, gpuInstanceId={_gpuInstanceId}, pnpDeviceIdPart={pnpDeviceIdPart}]");
}
else
{
_state = GPUState.Inactive;
_gpuInstanceId = gpuInstanceId;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Inactive [state={_state}, processes.Count={_processes.Count}, gpuInstanceId={_gpuInstanceId}]");
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/GPUOverclockController.cs
================================================
using System;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Listeners;
using LenovoLegionToolkit.Lib.Settings;
using LenovoLegionToolkit.Lib.SoftwareDisabler;
using LenovoLegionToolkit.Lib.System;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
using NvAPIWrapper.GPU;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace LenovoLegionToolkit.Lib.Controllers;
public class GPUOverclockController
{
private readonly GPUOverclockSettings _settings;
private readonly VantageDisabler _vantageDisabler;
private readonly LegionZoneDisabler _legionZoneDisabler;
private readonly NativeWindowsMessageListener _nativeWindowsMessageListener;
public event EventHandler? Changed;
public GPUOverclockController(GPUOverclockSettings settings,
VantageDisabler vantageDisabler,
LegionZoneDisabler legionZoneDisabler,
NativeWindowsMessageListener nativeWindowsMessageListener)
{
_settings = settings;
_vantageDisabler = vantageDisabler;
_legionZoneDisabler = legionZoneDisabler;
_nativeWindowsMessageListener = nativeWindowsMessageListener;
_nativeWindowsMessageListener.Changed += NativeWindowsMessageListenerOnChanged;
}
public static int GetMaxCoreDeltaMhz() => 500;
public static int GetMaxMemoryDeltaMhz()
{
try
{
NVAPI.Initialize();
return GetMaxMemoryDeltaMhz(NVAPI.GetGPU());
}
finally
{
try { NVAPI.Unload(); } catch { /* Ignored */ }
}
}
public async Task IsSupportedAsync()
{
bool isSupported;
try
{
NVAPI.Initialize();
isSupported = NVAPI.GetGPU() is not null;
}
catch
{
isSupported = false;
}
finally
{
try { NVAPI.Unload(); } catch { /* Ignored */ }
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"NVAPI status: {isSupported}.");
if (!isSupported)
return isSupported;
try
{
isSupported = await WMI.LenovoGameZoneData.IsSupportGpuOCAsync().ConfigureAwait(false) > 0;
if (!isSupported)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Clearing settings...");
_settings.Store.Enabled = false;
_settings.Store.Info = GPUOverclockInfo.Zero;
_settings.SynchronizeStore();
}
}
catch
{
isSupported = false;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Supports GPU OC status: {isSupported}");
return isSupported;
}
public (bool, GPUOverclockInfo) GetState() => (_settings.Store.Enabled, _settings.Store.Info);
public void SaveState(bool enabled, GPUOverclockInfo info)
{
_settings.Store.Enabled = enabled;
_settings.Store.Info = info;
_settings.SynchronizeStore();
}
public async Task ApplyStateAsync(bool force = false)
{
if (await _vantageDisabler.GetStatusAsync().ConfigureAwait(false) == SoftwareStatus.Enabled)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Can't correctly apply state when Vantage is running.");
Changed?.Invoke(this, EventArgs.Empty);
return;
}
if (await _legionZoneDisabler.GetStatusAsync().ConfigureAwait(false) == SoftwareStatus.Enabled)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Can't correctly apply state when Legion Zone is running.");
Changed?.Invoke(this, EventArgs.Empty);
return;
}
var enabled = _settings.Store.Enabled;
var info = _settings.Store.Info;
if (force)
{
info = enabled ? info : GPUOverclockInfo.Zero;
enabled = true;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Forcing... [enabled=true, info={info}]");
}
if (!enabled)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Not enabled.");
Changed?.Invoke(this, EventArgs.Empty);
return;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying overclock: {info}.");
try
{
NVAPI.Initialize();
var gpu = NVAPI.GetGPU();
if (gpu is null)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"dGPU not found.");
Changed?.Invoke(this, EventArgs.Empty);
return;
}
SetOverclockInfo(gpu, info);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applied overclock: {info}, current: {GetOverclockInfo(gpu)}.");
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to apply overclock: {info}, clearing settings...", ex);
_settings.Store.Enabled = false;
_settings.Store.Info = GPUOverclockInfo.Zero;
_settings.SynchronizeStore();
}
finally
{
Changed?.Invoke(this, EventArgs.Empty);
try { NVAPI.Unload(); } catch { /* Ignored */ }
}
}
public async Task EnsureOverclockIsAppliedAsync()
{
var (enabled, _) = GetState();
if (!enabled)
return false;
await ApplyStateAsync().ConfigureAwait(false);
return true;
}
private async void NativeWindowsMessageListenerOnChanged(object? sender, NativeWindowsMessageListener.ChangedEventArgs e)
{
if (e.Message != NativeWindowsMessage.OnDisplayDeviceArrival)
return;
if (await IsSupportedAsync().ConfigureAwait(false))
await ApplyStateAsync().ConfigureAwait(false);
}
private static int GetMaxMemoryDeltaMhz(PhysicalGPU? gpu) => gpu?.MemoryInformation.RAMMaker switch
{
GPUMemoryMaker.Samsung => 1500,
_ => 750
};
private static void SetOverclockInfo(PhysicalGPU gpu, GPUOverclockInfo info)
{
var coreDelta = Math.Clamp(info.CoreDeltaMhz, 0, GetMaxCoreDeltaMhz());
var memoryDelta = Math.Clamp(info.MemoryDeltaMhz, 0, GetMaxMemoryDeltaMhz(gpu));
var clockEntries = new[]
{
new PerformanceStates20ClockEntryV1(PublicClockDomain.Graphics, new PerformanceStates20ParameterDelta(coreDelta * 1000)),
new PerformanceStates20ClockEntryV1(PublicClockDomain.Memory, new PerformanceStates20ParameterDelta(memoryDelta * 1000))
};
var voltageEntries = Array.Empty();
var performanceStateInfo = new[] { new PerformanceStates20InfoV1.PerformanceState20(PerformanceStateId.P0_3DPerformance, clockEntries, voltageEntries) };
var overclock = new PerformanceStates20InfoV1(performanceStateInfo, 2, 0);
GPUApi.SetPerformanceStates20(gpu.Handle, overclock);
}
private static GPUOverclockInfo GetOverclockInfo(PhysicalGPU gpu)
{
var states = GPUApi.GetPerformanceStates20(gpu.Handle);
var core = states.Clocks[PerformanceStateId.P0_3DPerformance][0].FrequencyDeltaInkHz.DeltaValue / 1000;
var memory = states.Clocks[PerformanceStateId.P0_3DPerformance][1].FrequencyDeltaInkHz.DeltaValue / 1000;
return new(core, memory);
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/GodMode/AbstractGodModeController.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.Settings;
using LenovoLegionToolkit.Lib.Utils;
namespace LenovoLegionToolkit.Lib.Controllers.GodMode;
public abstract class AbstractGodModeController(GodModeSettings settings)
: IGodModeController
{
public event EventHandler? PresetChanged;
public abstract Task NeedsVantageDisabledAsync();
public abstract Task NeedsLegionZoneDisabledAsync();
public Task GetActivePresetIdAsync() => Task.FromResult(settings.Store.ActivePresetId);
public Task GetActivePresetNameAsync()
{
var store = settings.Store;
var name = store.Presets
.Where(p => p.Key == store.ActivePresetId)
.Select(p => p.Value.Name)
.FirstOrDefault();
return Task.FromResult(name);
}
public async Task GetStateAsync()
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting state...");
var store = settings.Store;
var defaultState = await GetDefaultStateAsync().ConfigureAwait(false);
if (!IsValidStore(store))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Loading default state...");
var id = Guid.NewGuid();
return new GodModeState
{
ActivePresetId = id,
Presets = new Dictionary { { id, defaultState } }.AsReadOnlyDictionary()
};
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Loading state from store...");
return await LoadStateFromStoreAsync(store, defaultState).ConfigureAwait(false);
}
public Task SetStateAsync(GodModeState state)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Setting state...");
var activePresetId = state.ActivePresetId;
var presets = new Dictionary();
foreach (var (id, preset) in state.Presets)
{
presets.Add(id, new()
{
Name = preset.Name,
CPULongTermPowerLimit = preset.CPULongTermPowerLimit,
CPUShortTermPowerLimit = preset.CPUShortTermPowerLimit,
CPUPeakPowerLimit = preset.CPUPeakPowerLimit,
CPUCrossLoadingPowerLimit = preset.CPUCrossLoadingPowerLimit,
CPUPL1Tau = preset.CPUPL1Tau,
APUsPPTPowerLimit = preset.APUsPPTPowerLimit,
CPUTemperatureLimit = preset.CPUTemperatureLimit,
GPUPowerBoost = preset.GPUPowerBoost,
GPUConfigurableTGP = preset.GPUConfigurableTGP,
GPUTemperatureLimit = preset.GPUTemperatureLimit,
GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline = preset.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline,
GPUToCPUDynamicBoost = preset.GPUToCPUDynamicBoost,
FanTable = preset.FanTableInfo?.Table,
FanFullSpeed = preset.FanFullSpeed,
MinValueOffset = preset.MinValueOffset,
MaxValueOffset = preset.MaxValueOffset,
});
}
settings.Store.ActivePresetId = activePresetId;
settings.Store.Presets = presets;
settings.SynchronizeStore();
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"State saved.");
return Task.CompletedTask;
}
public abstract Task ApplyStateAsync();
public Task GetDefaultFanTableAsync()
{
var fanTable = new FanTable([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
return Task.FromResult(fanTable);
}
public abstract Task GetMinimumFanTableAsync();
public abstract Task> GetDefaultsInOtherPowerModesAsync();
public abstract Task RestoreDefaultsInOtherPowerModeAsync(PowerModeState state);
protected abstract Task GetDefaultStateAsync();
protected void RaisePresetChanged(Guid presetId) => PresetChanged?.Invoke(this, presetId);
protected async Task<(Guid, GodModeSettings.GodModeSettingsStore.Preset)> GetActivePresetAsync()
{
if (!IsValidStore(settings.Store))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Invalid store, generating default one.");
var state = await GetStateAsync().ConfigureAwait(false);
await SetStateAsync(state).ConfigureAwait(false);
}
var activePresetId = settings.Store.ActivePresetId;
var presets = settings.Store.Presets;
if (presets.TryGetValue(activePresetId, out var activePreset))
return (activePresetId, activePreset);
throw new InvalidOperationException($"Preset with ID {activePresetId} not found");
}
protected async Task IsValidFanTableAsync(FanTable fanTable)
{
var minimumFanTable = await GetMinimumFanTableAsync().ConfigureAwait(false);
var minimum = minimumFanTable.GetTable();
return fanTable.GetTable().Where((t, i) => t < minimum[i] || t > 10u).IsEmpty();
}
private static bool IsValidStore(GodModeSettings.GodModeSettingsStore store) => store.Presets.Count != 0 && store.Presets.ContainsKey(store.ActivePresetId);
private async Task LoadStateFromStoreAsync(GodModeSettings.GodModeSettingsStore store, GodModePreset defaultState)
{
var states = new Dictionary();
foreach (var (id, preset) in store.Presets)
{
states.Add(id, new GodModePreset
{
Name = preset.Name,
CPULongTermPowerLimit = CreateStepperValue(defaultState.CPULongTermPowerLimit, preset.CPULongTermPowerLimit, preset.MinValueOffset, preset.MaxValueOffset),
CPUShortTermPowerLimit = CreateStepperValue(defaultState.CPUShortTermPowerLimit, preset.CPUShortTermPowerLimit, preset.MinValueOffset, preset.MaxValueOffset),
CPUPeakPowerLimit = CreateStepperValue(defaultState.CPUPeakPowerLimit, preset.CPUPeakPowerLimit, preset.MinValueOffset, preset.MaxValueOffset),
CPUCrossLoadingPowerLimit = CreateStepperValue(defaultState.CPUCrossLoadingPowerLimit, preset.CPUCrossLoadingPowerLimit, preset.MinValueOffset, preset.MaxValueOffset),
CPUPL1Tau = CreateStepperValue(defaultState.CPUPL1Tau, preset.CPUPL1Tau, preset.MinValueOffset, preset.MaxValueOffset),
APUsPPTPowerLimit = CreateStepperValue(defaultState.APUsPPTPowerLimit, preset.APUsPPTPowerLimit, preset.MinValueOffset, preset.MaxValueOffset),
CPUTemperatureLimit = CreateStepperValue(defaultState.CPUTemperatureLimit, preset.CPUTemperatureLimit, preset.MinValueOffset, preset.MaxValueOffset),
GPUPowerBoost = CreateStepperValue(defaultState.GPUPowerBoost, preset.GPUPowerBoost, preset.MinValueOffset, preset.MaxValueOffset),
GPUConfigurableTGP = CreateStepperValue(defaultState.GPUConfigurableTGP, preset.GPUConfigurableTGP, preset.MinValueOffset, preset.MaxValueOffset),
GPUTemperatureLimit = CreateStepperValue(defaultState.GPUTemperatureLimit, preset.GPUTemperatureLimit, preset.MinValueOffset, preset.MaxValueOffset),
GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline = CreateStepperValue(defaultState.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline,
preset.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline,
preset.MinValueOffset,
preset.MaxValueOffset),
GPUToCPUDynamicBoost = CreateStepperValue(defaultState.GPUToCPUDynamicBoost, preset.GPUToCPUDynamicBoost),
FanTableInfo = await GetFanTableInfoAsync(preset, defaultState.FanTableInfo?.Data).ConfigureAwait(false),
FanFullSpeed = preset.FanFullSpeed,
MinValueOffset = preset.MinValueOffset ?? defaultState.MinValueOffset,
MaxValueOffset = preset.MaxValueOffset ?? defaultState.MaxValueOffset
});
}
return new GodModeState
{
ActivePresetId = store.ActivePresetId,
Presets = states.AsReadOnlyDictionary()
};
}
private static StepperValue? CreateStepperValue(StepperValue? state, StepperValue? store = null, int? minValueOffset = 0, int? maxValueOffset = 0)
{
if (state is not { } stateValue)
return null;
if (stateValue.Steps.Length > 0)
{
var value = store?.Value ?? stateValue.Value;
var steps = stateValue.Steps;
var defaultValue = stateValue.DefaultValue;
if (!steps.Contains(value))
{
var valueTemp = value;
value = steps.MinBy(v => Math.Abs((long)v - valueTemp));
}
return new(value, 0, 0, 0, steps, defaultValue);
}
if (stateValue.Step > 0)
{
var value = store?.Value ?? stateValue.Value;
var min = Math.Max(0, stateValue.Min + (minValueOffset ?? 0));
var max = stateValue.Max + (maxValueOffset ?? 0);
var step = stateValue.Step;
var defaultValue = stateValue.DefaultValue;
value = MathExtensions.RoundNearest(value, step);
if (value < min || value > max)
value = defaultValue ?? Math.Clamp(value, min, max);
return new(value, min, max, step, [], defaultValue);
}
return null;
}
private async Task GetFanTableInfoAsync(GodModeSettings.GodModeSettingsStore.Preset preset, FanTableData[]? fanTableData)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting fan table info...");
if (fanTableData is null)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Fan table data is null");
return null;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Fan table data retrieved: {fanTableData}");
var fanTable = preset.FanTable ?? await GetDefaultFanTableAsync().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Fan table retrieved: {fanTable}");
if (!await IsValidFanTableAsync(fanTable).ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Fan table invalid, replacing with default...");
fanTable = await GetDefaultFanTableAsync().ConfigureAwait(false);
}
return new FanTableInfo(fanTableData, fanTable);
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/GodMode/GodModeController.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Utils;
namespace LenovoLegionToolkit.Lib.Controllers.GodMode;
public class GodModeController(GodModeControllerV1 controllerV1, GodModeControllerV2 controllerV2)
: IGodModeController
{
private IGodModeController ControllerV1 => controllerV1;
private IGodModeController ControllerV2 => controllerV2;
public event EventHandler? PresetChanged
{
add
{
ControllerV1.PresetChanged += value;
ControllerV2.PresetChanged += value;
}
remove
{
ControllerV1.PresetChanged -= value;
ControllerV2.PresetChanged -= value;
}
}
public async Task NeedsVantageDisabledAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false);
return await controller.NeedsVantageDisabledAsync().ConfigureAwait(false);
}
public async Task NeedsLegionZoneDisabledAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false);
return await controller.NeedsLegionZoneDisabledAsync().ConfigureAwait(false);
}
public async Task GetActivePresetIdAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false);
return await controller.GetActivePresetIdAsync().ConfigureAwait(false);
}
public async Task GetActivePresetNameAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false);
return await controller.GetActivePresetNameAsync().ConfigureAwait(false);
}
public async Task GetStateAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false);
return await controller.GetStateAsync().ConfigureAwait(false);
}
public async Task SetStateAsync(GodModeState state)
{
var controller = await GetControllerAsync().ConfigureAwait(false);
await controller.SetStateAsync(state).ConfigureAwait(false);
}
public async Task ApplyStateAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false);
await controller.ApplyStateAsync().ConfigureAwait(false);
}
public async Task GetDefaultFanTableAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false);
return await controller.GetDefaultFanTableAsync().ConfigureAwait(false);
}
public async Task GetMinimumFanTableAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false);
return await controller.GetMinimumFanTableAsync().ConfigureAwait(false);
}
public async Task> GetDefaultsInOtherPowerModesAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false);
return await controller.GetDefaultsInOtherPowerModesAsync().ConfigureAwait(false);
}
public async Task RestoreDefaultsInOtherPowerModeAsync(PowerModeState state)
{
var controller = await GetControllerAsync().ConfigureAwait(false);
await controller.RestoreDefaultsInOtherPowerModeAsync(state).ConfigureAwait(false);
}
private async Task GetControllerAsync()
{
var mi = await Compatibility.GetMachineInformationAsync().ConfigureAwait(false);
if (mi.Properties.SupportsGodModeV1)
return controllerV1;
if (mi.Properties.SupportsGodModeV2)
return controllerV2;
throw new InvalidOperationException("No supported version found");
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/GodMode/GodModeControllerV1.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.Settings;
using LenovoLegionToolkit.Lib.SoftwareDisabler;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
namespace LenovoLegionToolkit.Lib.Controllers.GodMode;
public class GodModeControllerV1(
GodModeSettings settings,
LegionZoneDisabler legionZoneDisabler)
: AbstractGodModeController(settings)
{
public override Task NeedsVantageDisabledAsync() => Task.FromResult(false);
public override Task NeedsLegionZoneDisabledAsync() => Task.FromResult(true);
public override async Task ApplyStateAsync()
{
if (await legionZoneDisabler.GetStatusAsync().ConfigureAwait(false) == SoftwareStatus.Enabled)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Can't correctly apply state when Legion Zone is running.");
return;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying state...");
var (presetId, preset) = await GetActivePresetAsync().ConfigureAwait(false);
var cpuLongTermPowerLimit = preset.CPULongTermPowerLimit;
var cpuShortTermPowerLimit = preset.CPUShortTermPowerLimit;
var cpuPeakPowerLimit = preset.CPUPeakPowerLimit;
var cpuCrossLoadingPowerLimit = preset.CPUCrossLoadingPowerLimit;
var apuSPPTPowerLimit = preset.APUsPPTPowerLimit;
var cpuTemperatureLimit = preset.CPUTemperatureLimit;
var gpuPowerBoost = preset.GPUPowerBoost;
var gpuConfigurableTgp = preset.GPUConfigurableTGP;
var gpuTemperatureLimit = preset.GPUTemperatureLimit;
var fanTable = preset.FanTable ?? await GetDefaultFanTableAsync().ConfigureAwait(false);
var fanFullSpeed = preset.FanFullSpeed ?? false;
if (cpuLongTermPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Long Term Power Limit: {cpuLongTermPowerLimit}");
await SetCPULongTermPowerLimitAsync(cpuLongTermPowerLimit.Value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuLongTermPowerLimit]", ex);
throw;
}
}
if (cpuShortTermPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Short Term Power Limit: {cpuShortTermPowerLimit}");
await SetCPUShortTermPowerLimitAsync(cpuShortTermPowerLimit.Value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuShortTermPowerLimit]", ex);
throw;
}
}
if (cpuPeakPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Peak Power Limit: {cpuPeakPowerLimit}");
await SetCPUPeakPowerLimitAsync(cpuPeakPowerLimit.Value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuPeakPowerLimit]", ex);
throw;
}
}
if (cpuCrossLoadingPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Cross Loading Power Limit: {cpuCrossLoadingPowerLimit}");
await SetCPUCrossLoadingPowerLimitAsync(cpuCrossLoadingPowerLimit.Value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuCrossLoadingPowerLimit]", ex);
throw;
}
}
if (apuSPPTPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying APU sPPT Power Limit: {apuSPPTPowerLimit}");
await SetAPUSPPTPowerLimitAsync(apuSPPTPowerLimit.Value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=apuSPPTPowerLimit]", ex);
throw;
}
}
if (cpuTemperatureLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Temperature Limit: {cpuTemperatureLimit}");
await SetCPUTemperatureLimitAsync(cpuTemperatureLimit.Value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuTemperatureLimit]", ex);
throw;
}
}
if (gpuPowerBoost is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying GPU Power Boost: {gpuPowerBoost}");
await SetGPUPowerBoostAsync(gpuPowerBoost.Value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=gpuPowerBoost]", ex);
}
}
if (gpuConfigurableTgp is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying GPU Configurable TGP: {gpuConfigurableTgp}");
await SetGPUConfigurableTGPAsync(gpuConfigurableTgp.Value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=gpuConfigurableTgp]", ex);
}
}
if (gpuTemperatureLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying GPU Temperature Limit: {gpuTemperatureLimit}");
await SetGPUTemperatureLimitAsync(gpuTemperatureLimit.Value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=gpuTemperatureLimit]", ex);
}
}
if (fanFullSpeed)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying Fan Full Speed {fanFullSpeed}...");
await SetFanFullSpeedAsync(fanFullSpeed).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=fanFullSpeed]", ex);
throw;
}
}
else
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Making sure Fan Full Speed is false...");
await SetFanFullSpeedAsync(false).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=fanFullSpeed]", ex);
throw;
}
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying Fan Table {fanTable}...");
if (!await IsValidFanTableAsync(fanTable).ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Fan table invalid, replacing with default...");
fanTable = await GetDefaultFanTableAsync().ConfigureAwait(false);
}
await SetFanTable(fanTable).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=fanTable]", ex);
throw;
}
}
RaisePresetChanged(presetId);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"State applied. [name={preset.Name}, id={presetId}]");
}
public override Task GetMinimumFanTableAsync()
{
var fanTable = new FanTable([0, 0, 0, 0, 0, 0, 0, 1, 3, 5]);
return Task.FromResult(fanTable);
}
public override async Task> GetDefaultsInOtherPowerModesAsync()
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting defaults in other power modes...");
var result = await GetDefaultValuesInDifferentModeAsync().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
{
Log.Instance.Trace($"Defaults in other power modes retrieved:");
foreach (var (powerMode, defaults) in result)
Log.Instance.Trace($" - {powerMode}: {defaults}");
}
return result;
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to get defaults in other power modes.", ex);
return [];
}
}
public override async Task RestoreDefaultsInOtherPowerModeAsync(PowerModeState state)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Restoring defaults for {state}...");
var result = await GetDefaultValuesInDifferentModeAsync().ConfigureAwait(false);
if (!result.TryGetValue(state, out var defaults))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Defaults for {state} not found. Skipping...");
return;
}
if (defaults.CPULongTermPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Long Term Power Limit: {defaults.CPULongTermPowerLimit}");
await SetCPULongTermPowerLimitAsync(defaults.CPULongTermPowerLimit.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuLongTermPowerLimit]", ex);
throw;
}
}
if (defaults.CPUShortTermPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Short Term Power Limit: {defaults.CPUShortTermPowerLimit}");
await SetCPUShortTermPowerLimitAsync(defaults.CPUShortTermPowerLimit.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuShortTermPowerLimit]", ex);
throw;
}
}
if (defaults.CPUPeakPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Peak Power Limit: {defaults.CPUPeakPowerLimit}");
await SetCPUPeakPowerLimitAsync(defaults.CPUPeakPowerLimit.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuPeakPowerLimit]", ex);
throw;
}
}
if (defaults.CPUCrossLoadingPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Cross Loading Power Limit: {defaults.CPUCrossLoadingPowerLimit}");
await SetCPUCrossLoadingPowerLimitAsync(defaults.CPUCrossLoadingPowerLimit.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuCrossLoadingPowerLimit]", ex);
throw;
}
}
if (defaults.APUsPPTPowerLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying APU sPPT Power Limit: {defaults.APUsPPTPowerLimit}");
await SetAPUSPPTPowerLimitAsync(defaults.APUsPPTPowerLimit.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=apuSPPTPowerLimit]", ex);
throw;
}
}
if (defaults.CPUTemperatureLimit is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying CPU Temperature Limit: {defaults.CPUTemperatureLimit}");
await SetCPUTemperatureLimitAsync(defaults.CPUTemperatureLimit.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=cpuTemperatureLimit]", ex);
throw;
}
}
if (defaults.GPUPowerBoost is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying GPU Power Boost: {defaults.GPUPowerBoost}");
await SetGPUPowerBoostAsync(defaults.GPUPowerBoost.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=gpuPowerBoost]", ex);
throw;
}
}
if (defaults.GPUConfigurableTGP is not null)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying GPU Configurable TGP: {defaults.GPUConfigurableTGP}");
await SetGPUConfigurableTGPAsync(defaults.GPUConfigurableTGP.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=gpuConfigurableTgp]", ex);
throw;
}
}
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to restore defaults for {state}.", ex);
}
}
protected override async Task GetDefaultStateAsync()
{
var fanTableData = await GetFanTableDataAsync().ConfigureAwait(false);
var preset = new GodModePreset
{
Name = "Default",
CPULongTermPowerLimit = await GetCPULongTermPowerLimitAsync().OrNullIfException().ConfigureAwait(false),
CPUShortTermPowerLimit = await GetCPUShortTermPowerLimitAsync().OrNullIfException().ConfigureAwait(false),
CPUPeakPowerLimit = await GetCPUPeakPowerLimitAsync().OrNullIfException().ConfigureAwait(false),
CPUCrossLoadingPowerLimit = await GetCPUCrossLoadingPowerLimitAsync().OrNullIfException().ConfigureAwait(false),
APUsPPTPowerLimit = await GetAPUSPPTPowerLimitAsync().OrNullIfException().ConfigureAwait(false),
CPUTemperatureLimit = await GetCPUTemperatureLimitAsync().OrNullIfException().ConfigureAwait(false),
GPUPowerBoost = await GetGPUPowerBoost().OrNullIfException().ConfigureAwait(false),
GPUConfigurableTGP = await GetGPUConfigurableTGPAsync().OrNullIfException().ConfigureAwait(false),
GPUTemperatureLimit = await GetGPUTemperatureLimitAsync().OrNullIfException().ConfigureAwait(false),
FanTableInfo = fanTableData is null ? null : new FanTableInfo(fanTableData, await GetDefaultFanTableAsync().ConfigureAwait(false)),
FanFullSpeed = await GetFanFullSpeedAsync().ConfigureAwait(false),
MinValueOffset = 0,
MaxValueOffset = 0
};
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Default state retrieved: {preset}");
return preset;
}
#region CPU Long Term Power Limit
private static async Task GetCPULongTermPowerLimitAsync()
{
var defaultValue = await WMI.LenovoCpuMethod.CPUGetDefaultPowerLimitAsync().OrNullIfException().ConfigureAwait(false);
var (value, min, max, step) = await WMI.LenovoCpuMethod.CPUGetLongTermPowerLimitAsync().ConfigureAwait(false);
return new(value, min, max, step, [], defaultValue?.longTerm);
}
private static Task SetCPULongTermPowerLimitAsync(int value) => WMI.LenovoCpuMethod.CPUSetLongTermPowerLimitAsync(value);
#endregion
#region CPU Short Term Power Limit
private static async Task GetCPUShortTermPowerLimitAsync()
{
var defaultValue = await WMI.LenovoCpuMethod.CPUGetDefaultPowerLimitAsync().OrNullIfException().ConfigureAwait(false);
var (value, min, max, step) = await WMI.LenovoCpuMethod.CPUGetShortTermPowerLimitAsync().ConfigureAwait(false);
return new(value, min, max, step, [], defaultValue?.shortTerm);
}
private static Task SetCPUShortTermPowerLimitAsync(int value) => WMI.LenovoCpuMethod.CPUSetShortTermPowerLimitAsync(value);
#endregion
#region CPU Peak Power Limit
private static async Task GetCPUPeakPowerLimitAsync()
{
var (value, min, max, step, defaultValue) = await WMI.LenovoCpuMethod.CPUGetPeakPowerLimitAsync().ConfigureAwait(false);
return new(value, min, max, step, [], defaultValue);
}
private static Task SetCPUPeakPowerLimitAsync(int value) => WMI.LenovoCpuMethod.CPUSetPeakPowerLimitAsync(value);
#endregion
#region CPU Cross Loading Power Limit
private static async Task GetCPUCrossLoadingPowerLimitAsync()
{
var (value, min, max, step, defaultValue) = await WMI.LenovoCpuMethod.CPUGetCrossLoadingPowerLimitAsync().ConfigureAwait(false);
return new(value, min, max, step, [], defaultValue);
}
private static Task SetCPUCrossLoadingPowerLimitAsync(int value) => WMI.LenovoCpuMethod.CPUSetCrossLoadingPowerLimitAsync(value);
#endregion
#region APU sPPT Power Limit
private static async Task GetAPUSPPTPowerLimitAsync()
{
var (value, min, max, step, defaultValue) = await WMI.LenovoCpuMethod.GetAPUSPPTPowerLimitAsync().ConfigureAwait(false);
return new(value, min, max, step, [], defaultValue);
}
private static Task SetAPUSPPTPowerLimitAsync(int value) => WMI.LenovoCpuMethod.SetAPUSPPTPowerLimitAsync(value);
#endregion
#region CPU Temperature Limit
private static async Task GetCPUTemperatureLimitAsync()
{
var (value, min, max, step, defaultValue) = await WMI.LenovoCpuMethod.CPUGetTemperatureControlAsync().ConfigureAwait(false);
return new(value, min, max, step, [], defaultValue);
}
private static Task SetCPUTemperatureLimitAsync(int value) => WMI.LenovoCpuMethod.CPUSetTemperatureControlAsync(value);
#endregion
#region GPU Configurable TGP
private static async Task GetGPUConfigurableTGPAsync()
{
var defaultValue = await WMI.LenovoGpuMethod.GPUGetDefaultPPABcTGPPowerLimit().OrNullIfException().ConfigureAwait(false);
var (value, min, max, step) = await WMI.LenovoGpuMethod.GPUGetCTGPPowerLimitAsync().ConfigureAwait(false);
return new(value, min, max, step, [], defaultValue?.ctgp);
}
private static Task SetGPUConfigurableTGPAsync(int value) => WMI.LenovoGpuMethod.GPUSetCTGPPowerLimitAsync(value);
#endregion
#region GPU Power Boost
private static async Task GetGPUPowerBoost()
{
var defaultValue = await WMI.LenovoGpuMethod.GPUGetDefaultPPABcTGPPowerLimit().OrNullIfException().ConfigureAwait(false);
var (value, min, max, step) = await WMI.LenovoGpuMethod.GPUGetPPABPowerLimitAsync().ConfigureAwait(false);
return new(value, min, max, step, [], defaultValue?.ppab);
}
private static Task SetGPUPowerBoostAsync(int value) => WMI.LenovoGpuMethod.GPUSetPPABPowerLimitAsync(value);
#endregion
#region GPU Temperature Limit
private static async Task GetGPUTemperatureLimitAsync()
{
var (value, min, max, step, defaultValue) = await WMI.LenovoGpuMethod.GPUGetTemperatureLimitAsync().ConfigureAwait(false);
return new(value, min, max, step, [], defaultValue);
}
private static Task SetGPUTemperatureLimitAsync(int value) => WMI.LenovoGpuMethod.GPUSetTemperatureLimitAsync(value);
#endregion
#region Fan Table
private static async Task GetFanTableDataAsync()
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Reading fan table data...");
var data = await WMI.LenovoFanTableData.ReadAsync().ConfigureAwait(false);
var fanTableData = data
.Select(d =>
{
var type = (d.fanId, d.sensorId) switch
{
(0, 3) => FanTableType.CPU,
(1, 4) => FanTableType.GPU,
(0, 0) => FanTableType.CPUSensor,
_ => FanTableType.Unknown,
};
return new FanTableData(type, d.fanId, d.sensorId, d.fanTableData, d.sensorTableData);
})
.ToArray();
if (fanTableData.Length != 3)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Bad fan table length: {fanTableData}");
return null;
}
if (fanTableData.Count(ftd => ftd.FanSpeeds.Length == 10) != 3)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Bad fan table fan speeds length: {fanTableData}");
return null;
}
if (fanTableData.Count(ftd => ftd.Temps.Length == 10) != 3)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Bad fan table temps length: {fanTableData}");
return null;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Fan table data: {fanTableData}");
return fanTableData;
}
private static Task SetFanTable(FanTable fanTable) => WMI.LenovoFanMethod.FanSetTableAsync(fanTable.GetBytes());
#endregion
#region Fan Full Speed
private static Task GetFanFullSpeedAsync() => WMI.LenovoFanMethod.FanGetFullSpeedAsync();
private static Task SetFanFullSpeedAsync(bool enabled) => WMI.LenovoFanMethod.FanSetFullSpeedAsync(enabled ? 1 : 0);
#endregion
#region Default values
private async Task> GetDefaultValuesInDifferentModeAsync()
{
var defaultFanTableAsync = await GetDefaultFanTableAsync().ConfigureAwait(false);
var result = await WMI.LenovoDefaultValueInDifferentModeData.ReadAsync().ConfigureAwait(false);
return result.Select(d =>
{
var powerMode = (PowerModeState)(d.Mode - 1);
var defaults = new GodModeDefaults
{
CPULongTermPowerLimit = d.CPULongTermPowerLimit,
CPUShortTermPowerLimit = d.CPUShortTermPowerLimit,
CPUPeakPowerLimit = d.CPUPeakPowerLimit,
CPUCrossLoadingPowerLimit = d.CPUCrossLoadingPowerLimit,
APUsPPTPowerLimit = d.APUsPPTPowerLimit,
CPUTemperatureLimit = d.CPUTemperatureLimit,
GPUPowerBoost = d.GPUPowerBoost,
GPUConfigurableTGP = d.GPUConfigurableTGP,
GPUTemperatureLimit = d.GPUTemperatureLimit,
FanTable = defaultFanTableAsync,
FanFullSpeed = false
};
return (powerMode, defaults);
})
.Where(d => d.powerMode is PowerModeState.Quiet or PowerModeState.Balance or PowerModeState.Performance)
.DistinctBy(d => d.powerMode)
.ToDictionary(d => d.powerMode, d => d.defaults);
}
#endregion
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/GodMode/GodModeControllerV2.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.Settings;
using LenovoLegionToolkit.Lib.SoftwareDisabler;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
namespace LenovoLegionToolkit.Lib.Controllers.GodMode;
public class GodModeControllerV2(
GodModeSettings settings,
VantageDisabler vantageDisabler,
LegionZoneDisabler legionZoneDisabler)
: AbstractGodModeController(settings)
{
public override Task NeedsVantageDisabledAsync() => Task.FromResult(true);
public override Task NeedsLegionZoneDisabledAsync() => Task.FromResult(true);
public override async Task ApplyStateAsync()
{
if (await vantageDisabler.GetStatusAsync().ConfigureAwait(false) == SoftwareStatus.Enabled)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Can't correctly apply state when Vantage is running.");
return;
}
if (await legionZoneDisabler.GetStatusAsync().ConfigureAwait(false) == SoftwareStatus.Enabled)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Can't correctly apply state when Legion Zone is running.");
return;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying state...");
var (presetId, preset) = await GetActivePresetAsync().ConfigureAwait(false);
var settings = new Dictionary
{
{ CapabilityID.CPULongTermPowerLimit, preset.CPULongTermPowerLimit },
{ CapabilityID.CPUShortTermPowerLimit, preset.CPUShortTermPowerLimit },
{ CapabilityID.CPUPeakPowerLimit, preset.CPUPeakPowerLimit },
{ CapabilityID.CPUCrossLoadingPowerLimit, preset.CPUCrossLoadingPowerLimit },
{ CapabilityID.CPUPL1Tau, preset.CPUPL1Tau },
{ CapabilityID.APUsPPTPowerLimit, preset.APUsPPTPowerLimit },
{ CapabilityID.CPUTemperatureLimit, preset.CPUTemperatureLimit },
{ CapabilityID.GPUPowerBoost, preset.GPUPowerBoost },
{ CapabilityID.GPUConfigurableTGP, preset.GPUConfigurableTGP },
{ CapabilityID.GPUTemperatureLimit, preset.GPUTemperatureLimit },
{ CapabilityID.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline, preset.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline },
{ CapabilityID.GPUToCPUDynamicBoost, preset.GPUToCPUDynamicBoost },
};
var defaultPresets = await GetDefaultsInOtherPowerModesAsync().ConfigureAwait(false);
var defaultPerformancePreset = defaultPresets.GetValueOrNull(PowerModeState.Performance);
var defaultPerformanceSettings = new Dictionary
{
{ CapabilityID.CPULongTermPowerLimit, defaultPerformancePreset?.CPULongTermPowerLimit },
{ CapabilityID.CPUShortTermPowerLimit, defaultPerformancePreset?.CPUShortTermPowerLimit },
{ CapabilityID.CPUPeakPowerLimit, defaultPerformancePreset?.CPUPeakPowerLimit },
{ CapabilityID.CPUCrossLoadingPowerLimit, defaultPerformancePreset?.CPUCrossLoadingPowerLimit },
{ CapabilityID.CPUPL1Tau, defaultPerformancePreset?.CPUPL1Tau },
{ CapabilityID.APUsPPTPowerLimit, defaultPerformancePreset?.APUsPPTPowerLimit },
{ CapabilityID.CPUTemperatureLimit, defaultPerformancePreset?.CPUTemperatureLimit },
{ CapabilityID.GPUPowerBoost, defaultPerformancePreset?.GPUPowerBoost },
{ CapabilityID.GPUConfigurableTGP, defaultPerformancePreset?.GPUConfigurableTGP },
{ CapabilityID.GPUTemperatureLimit, defaultPerformancePreset?.GPUTemperatureLimit },
{ CapabilityID.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline, defaultPerformancePreset?.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline },
{ CapabilityID.GPUToCPUDynamicBoost, defaultPerformancePreset?.GPUToCPUDynamicBoost },
};
var failAllowedSettings = new[]
{
CapabilityID.GPUPowerBoost,
CapabilityID.GPUConfigurableTGP,
CapabilityID.GPUTemperatureLimit,
CapabilityID.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline,
CapabilityID.GPUToCPUDynamicBoost,
};
var fanTable = preset.FanTable ?? await GetDefaultFanTableAsync().ConfigureAwait(false);
var fanFullSpeed = preset.FanFullSpeed ?? false;
foreach (var (id, value) in settings)
{
if (value.HasValue)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying {id}: {value}...");
await SetValueAsync(id, value.Value).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to apply {id}. [value={value}]", ex);
if (!failAllowedSettings.Contains(id))
throw;
}
}
else if (defaultPerformanceSettings.GetValueOrDefault(id) is { } defaultPerformanceValue)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying default {id}: {defaultPerformanceValue}...");
await SetValueAsync(id, defaultPerformanceValue).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to apply default {id}. [value={defaultPerformanceValue}]", ex);
if (!failAllowedSettings.Contains(id))
throw;
}
}
else
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to apply {id}, because neither value nor default value was available.");
}
}
if (fanFullSpeed)
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying Fan Full Speed {fanFullSpeed}...");
await SetFanFullSpeedAsync(fanFullSpeed).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=fanFullSpeed]", ex);
throw;
}
}
else
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Making sure Fan Full Speed is false...");
await SetFanFullSpeedAsync(false).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=fanFullSpeed]", ex);
throw;
}
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Applying Fan Table {fanTable}...");
if (!await IsValidFanTableAsync(fanTable).ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Fan table invalid, replacing with default...");
fanTable = await GetDefaultFanTableAsync().ConfigureAwait(false);
}
await SetFanTable(fanTable).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Apply failed. [setting=fanTable]", ex);
throw;
}
}
RaisePresetChanged(presetId);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"State applied. [name={preset.Name}, id={presetId}]");
}
public override Task GetMinimumFanTableAsync()
{
var fanTable = new FanTable([1, 1, 1, 1, 1, 1, 1, 1, 3, 5]);
return Task.FromResult(fanTable);
}
public override async Task> GetDefaultsInOtherPowerModesAsync()
{
try
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting defaults in other power modes...");
var result = new Dictionary();
var allCapabilityData = await WMI.LenovoCapabilityData01.ReadAsync().ConfigureAwait(false);
allCapabilityData = allCapabilityData.ToArray();
foreach (var powerMode in new[] { PowerModeState.Quiet, PowerModeState.Balance, PowerModeState.Performance })
{
var defaults = new GodModeDefaults
{
CPULongTermPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPULongTermPowerLimit, powerMode),
CPUShortTermPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUShortTermPowerLimit, powerMode),
CPUPeakPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUPeakPowerLimit, powerMode),
CPUCrossLoadingPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUCrossLoadingPowerLimit, powerMode),
CPUPL1Tau = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUPL1Tau, powerMode),
APUsPPTPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.APUsPPTPowerLimit, powerMode),
CPUTemperatureLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUTemperatureLimit, powerMode),
GPUPowerBoost = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUPowerBoost, powerMode),
GPUConfigurableTGP = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUConfigurableTGP, powerMode),
GPUTemperatureLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUTemperatureLimit, powerMode),
GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline, powerMode),
GPUToCPUDynamicBoost = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUToCPUDynamicBoost, powerMode),
FanTable = await GetDefaultFanTableAsync().ConfigureAwait(false),
FanFullSpeed = false
};
result[powerMode] = defaults;
}
if (Log.Instance.IsTraceEnabled)
{
Log.Instance.Trace($"Defaults in other power modes retrieved:");
foreach (var (powerMode, defaults) in result)
Log.Instance.Trace($" - {powerMode}: {defaults}");
}
return result;
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to get defaults in other power modes.", ex);
return [];
}
}
public override Task RestoreDefaultsInOtherPowerModeAsync(PowerModeState _) => Task.CompletedTask;
protected override async Task GetDefaultStateAsync()
{
var allCapabilityData = await WMI.LenovoCapabilityData01.ReadAsync().ConfigureAwait(false);
allCapabilityData = allCapabilityData.ToArray();
var capabilityData = allCapabilityData
.Where(d => Enum.IsDefined(d.Id))
.ToArray();
var allDiscreteData = await WMI.LenovoDiscreteData.ReadAsync().ConfigureAwait(false);
allDiscreteData = allDiscreteData.ToArray();
var discreteData = allDiscreteData
.Where(d => Enum.IsDefined(d.Id))
.GroupBy(d => d.Id, d => d.Value, (id, values) => (id, values))
.ToDictionary(d => d.id, d => d.values.ToArray());
var stepperValues = new Dictionary();
foreach (var c in capabilityData)
{
var value = await GetValueAsync(c.Id).OrNullIfException().ConfigureAwait(false) ?? c.DefaultValue;
var steps = discreteData.GetValueOrDefault(c.Id) ?? [];
if (c.Step == 0 && steps.Length < 1)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Skipping {c.Id}... [idRaw={(int)c.Id:X}, defaultValue={c.DefaultValue}, min={c.Min}, max={c.Max}, step={c.Step}, steps={string.Join(", ", steps)}]");
continue;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Creating StepperValue {c.Id}... [idRaw={(int)c.Id:X}, defaultValue={c.DefaultValue}, min={c.Min}, max={c.Max}, step={c.Step}, steps={string.Join(", ", steps)}]");
var stepperValue = new StepperValue(value, c.Min, c.Max, c.Step, steps, c.DefaultValue);
stepperValues[c.Id] = stepperValue;
}
var fanTableData = await GetFanTableDataAsync().ConfigureAwait(false);
var preset = new GodModePreset
{
Name = "Default",
CPULongTermPowerLimit = stepperValues.GetValueOrNull(CapabilityID.CPULongTermPowerLimit),
CPUShortTermPowerLimit = stepperValues.GetValueOrNull(CapabilityID.CPUShortTermPowerLimit),
CPUPeakPowerLimit = stepperValues.GetValueOrNull(CapabilityID.CPUPeakPowerLimit),
CPUCrossLoadingPowerLimit = stepperValues.GetValueOrNull(CapabilityID.CPUCrossLoadingPowerLimit),
CPUPL1Tau = stepperValues.GetValueOrNull(CapabilityID.CPUPL1Tau),
APUsPPTPowerLimit = stepperValues.GetValueOrNull(CapabilityID.APUsPPTPowerLimit),
CPUTemperatureLimit = stepperValues.GetValueOrNull(CapabilityID.CPUTemperatureLimit),
GPUPowerBoost = stepperValues.GetValueOrNull(CapabilityID.GPUPowerBoost),
GPUConfigurableTGP = stepperValues.GetValueOrNull(CapabilityID.GPUConfigurableTGP),
GPUTemperatureLimit = stepperValues.GetValueOrNull(CapabilityID.GPUTemperatureLimit),
GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline = stepperValues.GetValueOrNull(CapabilityID.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline),
GPUToCPUDynamicBoost = stepperValues.GetValueOrNull(CapabilityID.GPUToCPUDynamicBoost),
FanTableInfo = fanTableData is null ? null : new FanTableInfo(fanTableData, await GetDefaultFanTableAsync().ConfigureAwait(false)),
FanFullSpeed = await GetFanFullSpeedAsync().ConfigureAwait(false),
MinValueOffset = 0,
MaxValueOffset = 0
};
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Default state retrieved: {preset}");
return preset;
}
private static CapabilityID AdjustCapabilityIdForPowerMode(CapabilityID id, PowerModeState powerMode)
{
var idRaw = (uint)id & 0xFFFF00FF;
var powerModeRaw = ((uint)powerMode + 1) << 8;
return (CapabilityID)(idRaw + powerModeRaw);
}
private static int? GetDefaultCapabilityIdValueInPowerMode(IEnumerable capabilities, CapabilityID id, PowerModeState powerMode)
{
var adjustedId = AdjustCapabilityIdForPowerMode(id, powerMode);
var value = capabilities
.Where(c => c.Id == adjustedId)
.Select(c => c.DefaultValue)
.DefaultIfEmpty(-1)
.First();
return value < 0 ? null : value;
}
#region Get/Set Value
private static Task GetValueAsync(CapabilityID id)
{
var idRaw = (uint)id & 0xFFFF00FF;
return WMI.LenovoOtherMethod.GetFeatureValueAsync(idRaw);
}
private static Task SetValueAsync(CapabilityID id, StepperValue value) => SetValueAsync(id, value.Value);
private static Task SetValueAsync(CapabilityID id, int value)
{
var idRaw = (uint)id & 0xFFFF00FF;
return WMI.LenovoOtherMethod.SetFeatureValueAsync(idRaw, value);
}
#endregion
#region Fan Table
private static async Task GetFanTableDataAsync(PowerModeState powerModeState = PowerModeState.GodMode)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Reading fan table data...");
var data = await WMI.LenovoFanTableData.ReadAsync().ConfigureAwait(false);
var fanTableData = data
.Where(d => d.mode == (int)powerModeState + 1)
.Select(d =>
{
var type = (d.fanId, d.sensorId) switch
{
(1, 4) => FanTableType.CPU,
(1, 1) => FanTableType.CPUSensor,
(2, 5) => FanTableType.GPU,
(3, 5) => FanTableType.GPU2,
_ => FanTableType.Unknown,
};
return new FanTableData(type, d.fanId, d.sensorId, d.fanTableData, d.sensorTableData);
})
.ToArray();
var length = fanTableData.Where(ftd => ftd.Type != FanTableType.Unknown).Count();
if (fanTableData.Length != length)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Bad fan table length: {string.Join(", ", fanTableData)}");
return null;
}
if (fanTableData.Count(ftd => ftd.FanSpeeds.Length == 10) != length)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Bad fan table fan speeds length: {string.Join(", ", fanTableData)}");
return null;
}
if (fanTableData.Count(ftd => ftd.Temps.Length == 10) != length)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Bad fan table temps length: {string.Join(", ", fanTableData)}");
return null;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Fan table data: {string.Join(", ", fanTableData)}");
return fanTableData;
}
private static Task SetFanTable(FanTable fanTable) => WMI.LenovoFanMethod.FanSetTableAsync(fanTable.GetBytes());
#endregion
#region Fan Full Speed
private static async Task GetFanFullSpeedAsync()
{
var value = await WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.FanFullSpeed).ConfigureAwait(false);
return value != 0;
}
private static Task SetFanFullSpeedAsync(bool enabled) => WMI.LenovoOtherMethod.SetFeatureValueAsync(CapabilityID.FanFullSpeed, enabled ? 1 : 0);
#endregion
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/GodMode/IGodModeController.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LenovoLegionToolkit.Lib.Controllers.GodMode;
public interface IGodModeController
{
event EventHandler PresetChanged;
Task NeedsVantageDisabledAsync();
Task NeedsLegionZoneDisabledAsync();
Task GetActivePresetIdAsync();
Task GetActivePresetNameAsync();
Task GetStateAsync();
Task SetStateAsync(GodModeState state);
Task ApplyStateAsync();
Task GetDefaultFanTableAsync();
Task GetMinimumFanTableAsync();
Task> GetDefaultsInOtherPowerModesAsync();
Task RestoreDefaultsInOtherPowerModeAsync(PowerModeState state);
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/RGBKeyboardBacklightController.cs
================================================
// #define MOCK_RGB
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.Settings;
using LenovoLegionToolkit.Lib.SoftwareDisabler;
using LenovoLegionToolkit.Lib.System;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
using Microsoft.Win32.SafeHandles;
using NeoSmart.AsyncLock;
using Windows.Win32;
namespace LenovoLegionToolkit.Lib.Controllers
{
public class RGBKeyboardBacklightController(RGBKeyboardSettings settings, VantageDisabler vantageDisabler)
{
private static readonly AsyncLock IoLock = new();
private SafeFileHandle? _deviceHandle;
private SafeFileHandle? DeviceHandle
{
get
{
if (ForceDisable)
return null;
_deviceHandle ??= Devices.GetRGBKeyboard();
return _deviceHandle;
}
}
public bool ForceDisable { get; set; }
public Task IsSupportedAsync()
{
#if MOCK_RGB
return Task.FromResult(true);
#else
return Task.FromResult(DeviceHandle is not null);
#endif
}
public async Task SetLightControlOwnerAsync(bool enable, bool restorePreset = false)
{
using (await IoLock.LockAsync().ConfigureAwait(false))
{
try
{
#if !MOCK_RGB
_ = DeviceHandle ?? throw new InvalidOperationException("RGB Keyboard unsupported");
#endif
await ThrowIfVantageEnabled().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Taking ownership...");
#if !MOCK_RGB
await WMI.LenovoGameZoneData.SetLightControlOwnerAsync(enable ? 1 : 0).ConfigureAwait(false);
#endif
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Ownership set to {enable}, restoring profile...");
if (restorePreset)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Restoring preset...");
await SetCurrentPresetAsync().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Restored preset");
}
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Can't take ownership.", ex);
throw;
}
}
}
public async Task GetStateAsync()
{
using (await IoLock.LockAsync().ConfigureAwait(false))
{
#if !MOCK_RGB
_ = DeviceHandle ?? throw new InvalidOperationException("RGB Keyboard unsupported");
#endif
await ThrowIfVantageEnabled().ConfigureAwait(false);
return settings.Store.State;
}
}
public async Task SetStateAsync(RGBKeyboardBacklightState state)
{
using (await IoLock.LockAsync().ConfigureAwait(false))
{
#if !MOCK_RGB
_ = DeviceHandle ?? throw new InvalidOperationException("RGB Keyboard unsupported");
#endif
await ThrowIfVantageEnabled().ConfigureAwait(false);
settings.Store.State = state;
settings.SynchronizeStore();
var selectedPreset = state.SelectedPreset;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Selected preset: {selectedPreset}");
LENOVO_RGB_KEYBOARD_STATE str;
if (selectedPreset == RGBKeyboardBacklightPreset.Off)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Creating off state.");
str = CreateOffState();
}
else
{
var presetDescription = state.Presets.GetValueOrDefault(selectedPreset, RGBKeyboardBacklightBacklightPresetDescription.Default);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Creating state: {presetDescription}");
str = Convert(presetDescription);
}
await SendToDevice(str).ConfigureAwait(false);
}
}
public async Task SetPresetAsync(RGBKeyboardBacklightPreset preset)
{
using (await IoLock.LockAsync().ConfigureAwait(false))
{
#if !MOCK_RGB
_ = DeviceHandle ?? throw new InvalidOperationException("RGB Keyboard unsupported");
#endif
await ThrowIfVantageEnabled().ConfigureAwait(false);
var state = settings.Store.State;
var presets = state.Presets;
settings.Store.State = new(preset, presets);
settings.SynchronizeStore();
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Preset is {preset}.");
LENOVO_RGB_KEYBOARD_STATE str;
if (preset == RGBKeyboardBacklightPreset.Off)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Creating off state.");
str = CreateOffState();
}
else
{
var presetDescription = state.Presets.GetValueOrDefault(preset, RGBKeyboardBacklightBacklightPresetDescription.Default);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Creating state: {presetDescription}");
str = Convert(presetDescription);
}
await SendToDevice(str).ConfigureAwait(false);
}
}
public async Task SetNextPresetAsync()
{
using (await IoLock.LockAsync().ConfigureAwait(false))
{
#if !MOCK_RGB
_ = DeviceHandle ?? throw new InvalidOperationException("RGB Keyboard unsupported");
#endif
await ThrowIfVantageEnabled().ConfigureAwait(false);
var state = settings.Store.State;
var newPreset = state.SelectedPreset.Next();
var presets = state.Presets;
settings.Store.State = new(newPreset, presets);
settings.SynchronizeStore();
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"New preset is {newPreset}.");
LENOVO_RGB_KEYBOARD_STATE str;
if (newPreset == RGBKeyboardBacklightPreset.Off)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Creating off state.");
str = CreateOffState();
}
else
{
var presetDescription = state.Presets.GetValueOrDefault(newPreset, RGBKeyboardBacklightBacklightPresetDescription.Default);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Creating state: {presetDescription}");
str = Convert(presetDescription);
}
await SendToDevice(str).ConfigureAwait(false);
return newPreset;
}
}
private async Task SetCurrentPresetAsync()
{
#if !MOCK_RGB
_ = DeviceHandle ?? throw new InvalidOperationException("RGB Keyboard unsupported");
#endif
await ThrowIfVantageEnabled().ConfigureAwait(false);
var state = settings.Store.State;
var preset = state.SelectedPreset;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Current preset is {preset}.");
LENOVO_RGB_KEYBOARD_STATE str;
if (preset == RGBKeyboardBacklightPreset.Off)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Creating off state.");
str = CreateOffState();
}
else
{
var presetDescription = state.Presets.GetValueOrDefault(preset, RGBKeyboardBacklightBacklightPresetDescription.Default);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Creating state: {presetDescription}");
str = Convert(presetDescription);
}
await SendToDevice(str).ConfigureAwait(false);
}
private async Task ThrowIfVantageEnabled()
{
var vantageStatus = await vantageDisabler.GetStatusAsync().ConfigureAwait(false);
if (vantageStatus == SoftwareStatus.Enabled)
throw new InvalidOperationException("Can't manage RGB keyboard with Vantage enabled");
}
private unsafe Task SendToDevice(LENOVO_RGB_KEYBOARD_STATE str) => Task.Run(() =>
{
#if !MOCK_RGB
var handle = DeviceHandle ?? throw new InvalidOperationException("RGB Keyboard unsupported");
var ptr = IntPtr.Zero;
try
{
var size = Marshal.SizeOf();
ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, false);
if (!PInvoke.HidD_SetFeature(handle, ptr.ToPointer(), (uint)size))
PInvokeExtensions.ThrowIfWin32Error("HidD_SetFeature");
}
finally
{
Marshal.FreeHGlobal(ptr);
}
#endif
});
private static LENOVO_RGB_KEYBOARD_STATE CreateOffState()
{
return new()
{
Header = [0xCC, 0x16],
Unused = new byte[13],
Padding = 0,
Effect = 0,
WaveLTR = 0,
WaveRTL = 0,
Brightness = 0,
Zone1Rgb = new byte[3],
Zone2Rgb = new byte[3],
Zone3Rgb = new byte[3],
Zone4Rgb = new byte[3],
};
}
private static LENOVO_RGB_KEYBOARD_STATE Convert(RGBKeyboardBacklightBacklightPresetDescription preset)
{
var result = new LENOVO_RGB_KEYBOARD_STATE
{
Header = [0xCC, 0x16],
Unused = new byte[13],
Padding = 0x0,
Zone1Rgb = [0xFF, 0xFF, 0xFF],
Zone2Rgb = [0xFF, 0xFF, 0xFF],
Zone3Rgb = [0xFF, 0xFF, 0xFF],
Zone4Rgb = [0xFF, 0xFF, 0xFF],
Effect = preset.Effect switch
{
RGBKeyboardBacklightEffect.Static => 1,
RGBKeyboardBacklightEffect.Breath => 3,
RGBKeyboardBacklightEffect.WaveRTL => 4,
RGBKeyboardBacklightEffect.WaveLTR => 4,
RGBKeyboardBacklightEffect.Smooth => 6,
_ => 0
},
WaveRTL = (byte)(preset.Effect == RGBKeyboardBacklightEffect.WaveRTL ? 1 : 0),
WaveLTR = (byte)(preset.Effect == RGBKeyboardBacklightEffect.WaveLTR ? 1 : 0),
Brightness = preset.Brightness switch
{
RGBKeyboardBacklightBrightness.Low => 1,
RGBKeyboardBacklightBrightness.High => 2,
_ => 0
}
};
if (preset.Effect != RGBKeyboardBacklightEffect.Static)
{
result.Speed = preset.Speed switch
{
RGBKeyboardBacklightSpeed.Slowest => 1,
RGBKeyboardBacklightSpeed.Slow => 2,
RGBKeyboardBacklightSpeed.Fast => 3,
RGBKeyboardBacklightSpeed.Fastest => 4,
_ => 0
};
}
if (preset.Effect is RGBKeyboardBacklightEffect.Static or RGBKeyboardBacklightEffect.Breath)
{
result.Zone1Rgb = [preset.Zone1.R, preset.Zone1.G, preset.Zone1.B];
result.Zone2Rgb = [preset.Zone2.R, preset.Zone2.G, preset.Zone2.B];
result.Zone3Rgb = [preset.Zone3.R, preset.Zone3.G, preset.Zone3.B];
result.Zone4Rgb = [preset.Zone4.R, preset.Zone4.G, preset.Zone4.B];
}
return result;
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/Sensors/AbstractSensorsController.cs
================================================
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.System;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
using Windows.Win32;
using Windows.Win32.System.Power;
namespace LenovoLegionToolkit.Lib.Controllers.Sensors;
public abstract class AbstractSensorsController(GPUController gpuController) : ISensorsController
{
private readonly struct GPUInfo(
int utilization,
int coreClock,
int maxCoreClock,
int memoryClock,
int maxMemoryClock,
int temperature,
int maxTemperature)
{
public static readonly GPUInfo Empty = new(-1, -1, -1, -1, -1, -1, -1);
public int Utilization { get; } = utilization;
public int CoreClock { get; } = coreClock;
public int MaxCoreClock { get; } = maxCoreClock;
public int MemoryClock { get; } = memoryClock;
public int MaxMemoryClock { get; } = maxMemoryClock;
public int Temperature { get; } = temperature;
public int MaxTemperature { get; } = maxTemperature;
}
private readonly SafePerformanceCounter _percentProcessorPerformanceCounter = new("Processor Information", "% Processor Performance", "_Total");
private readonly SafePerformanceCounter _percentProcessorUtilityCounter = new("Processor Information", "% Processor Utility", "_Total");
private int? _cpuBaseClockCache;
private int? _cpuMaxCoreClockCache;
private int? _cpuMaxFanSpeedCache;
private int? _gpuMaxFanSpeedCache;
public abstract Task IsSupportedAsync();
public Task PrepareAsync()
{
_percentProcessorPerformanceCounter.Reset();
_percentProcessorUtilityCounter.Reset();
return Task.CompletedTask;
}
public async Task GetDataAsync()
{
const int genericMaxUtilization = 100;
const int genericMaxTemperature = 100;
var cpuUtilization = GetCpuUtilization(genericMaxUtilization);
var cpuMaxCoreClock = _cpuMaxCoreClockCache ??= await GetCpuMaxCoreClockAsync().ConfigureAwait(false);
var cpuCoreClock = GetCpuCoreClock();
var cpuCurrentTemperature = await GetCpuCurrentTemperatureAsync().ConfigureAwait(false);
var cpuCurrentFanSpeed = await GetCpuCurrentFanSpeedAsync().ConfigureAwait(false);
var cpuMaxFanSpeed = _cpuMaxFanSpeedCache ??= await GetCpuMaxFanSpeedAsync().ConfigureAwait(false);
var gpuInfo = await GetGPUInfoAsync().ConfigureAwait(false);
var gpuCurrentTemperature = gpuInfo.Temperature >= 0 ? gpuInfo.Temperature : await GetGpuCurrentTemperatureAsync().ConfigureAwait(false);
var gpuMaxTemperature = gpuInfo.MaxTemperature >= 0 ? gpuInfo.MaxTemperature : genericMaxTemperature;
var gpuCurrentFanSpeed = await GetGpuCurrentFanSpeedAsync().ConfigureAwait(false);
var gpuMaxFanSpeed = _gpuMaxFanSpeedCache ??= await GetGpuMaxFanSpeedAsync().ConfigureAwait(false);
var cpu = new SensorData(cpuUtilization,
genericMaxUtilization,
cpuCoreClock,
cpuMaxCoreClock,
-1,
-1,
cpuCurrentTemperature,
genericMaxTemperature,
cpuCurrentFanSpeed,
cpuMaxFanSpeed);
var gpu = new SensorData(gpuInfo.Utilization,
genericMaxUtilization,
gpuInfo.CoreClock,
gpuInfo.MaxCoreClock,
gpuInfo.MemoryClock,
gpuInfo.MaxMemoryClock,
gpuCurrentTemperature,
gpuMaxTemperature,
gpuCurrentFanSpeed,
gpuMaxFanSpeed);
var result = new SensorsData(cpu, gpu);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Current data: {result} [type={GetType().Name}]");
return result;
}
public async Task<(int cpuFanSpeed, int gpuFanSpeed)> GetFanSpeedsAsync()
{
var cpuFanSpeed = await GetCpuCurrentFanSpeedAsync().ConfigureAwait(false);
var gpuFanSpeed = await GetGpuCurrentFanSpeedAsync().ConfigureAwait(false);
return (cpuFanSpeed, gpuFanSpeed);
}
protected abstract Task GetCpuCurrentTemperatureAsync();
protected abstract Task GetGpuCurrentTemperatureAsync();
protected abstract Task GetCpuCurrentFanSpeedAsync();
protected abstract Task GetGpuCurrentFanSpeedAsync();
protected abstract Task GetCpuMaxFanSpeedAsync();
protected abstract Task GetGpuMaxFanSpeedAsync();
private int GetCpuUtilization(int maxUtilization)
{
var result = (int)_percentProcessorUtilityCounter.NextValue();
if (result < 0)
return -1;
return Math.Min(result, maxUtilization);
}
private int GetCpuCoreClock()
{
var baseClock = _cpuBaseClockCache ??= GetCpuBaseClock();
var clock = (int)(baseClock * (_percentProcessorPerformanceCounter.NextValue() / 100f));
if (clock < 1)
return -1;
return clock;
}
private static unsafe int GetCpuBaseClock()
{
var ptr = IntPtr.Zero;
try
{
PInvoke.GetSystemInfo(out var systemInfo);
var numberOfProcessors = Math.Min(32, (int)systemInfo.dwNumberOfProcessors);
var infoSize = Marshal.SizeOf();
var infosSize = numberOfProcessors * infoSize;
ptr = Marshal.AllocHGlobal(infosSize);
var result = PInvoke.CallNtPowerInformation(POWER_INFORMATION_LEVEL.ProcessorInformation,
null,
0,
ptr.ToPointer(),
(uint)infosSize);
if (result != 0)
return 0;
var infos = new PROCESSOR_POWER_INFORMATION[numberOfProcessors];
for (var i = 0; i < infos.Length; i++)
infos[i] = Marshal.PtrToStructure(IntPtr.Add(ptr, i * infoSize));
return (int)infos.Select(p => p.MaxMhz).Max();
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
private static Task GetCpuMaxCoreClockAsync() => WMI.LenovoGameZoneData.GetCPUFrequencyAsync();
private async Task GetGPUInfoAsync()
{
if (gpuController.IsSupported())
await gpuController.StartAsync().ConfigureAwait(false);
if (await gpuController.GetLastKnownStateAsync().ConfigureAwait(false) is GPUState.PoweredOff or GPUState.Unknown)
return GPUInfo.Empty;
try
{
NVAPI.Initialize();
var gpu = NVAPI.GetGPU();
if (gpu is null)
return GPUInfo.Empty;
var utilization = Math.Min(100, Math.Max(gpu.UsageInformation.GPU.Percentage, gpu.UsageInformation.VideoEngine.Percentage));
var currentCoreClock = (int)gpu.CurrentClockFrequencies.GraphicsClock.Frequency / 1000;
var currentMemoryClock = (int)gpu.CurrentClockFrequencies.MemoryClock.Frequency / 1000;
var maxCoreClock = (int)gpu.BoostClockFrequencies.GraphicsClock.Frequency / 1000;
var maxMemoryClock = (int)gpu.BoostClockFrequencies.MemoryClock.Frequency / 1000;
var states = GPUApi.GetPerformanceStates20(gpu.Handle);
var maxCoreClockOffset = states.Clocks[PerformanceStateId.P0_3DPerformance][0].FrequencyDeltaInkHz.DeltaValue / 1000;
var maxMemoryClockOffset = states.Clocks[PerformanceStateId.P0_3DPerformance][1].FrequencyDeltaInkHz.DeltaValue / 1000;
var temperatureSensor = gpu.ThermalInformation.ThermalSensors.FirstOrDefault();
var currentTemperature = temperatureSensor?.CurrentTemperature ?? -1;
var maxTemperature = temperatureSensor?.DefaultMaximumTemperature ?? -1;
return new(utilization,
currentCoreClock,
maxCoreClock + maxCoreClockOffset,
currentMemoryClock,
maxMemoryClock + maxMemoryClockOffset,
currentTemperature,
maxTemperature);
}
catch
{
return GPUInfo.Empty;
}
finally
{
try { NVAPI.Unload(); } catch { /* Ignored */ }
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/Sensors/ISensorsController.cs
================================================
using System.Threading.Tasks;
namespace LenovoLegionToolkit.Lib.Controllers.Sensors;
public interface ISensorsController
{
Task IsSupportedAsync();
Task PrepareAsync();
Task GetDataAsync();
Task<(int cpuFanSpeed, int gpuFanSpeed)> GetFanSpeedsAsync();
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsController.cs
================================================
using System;
using System.Threading.Tasks;
namespace LenovoLegionToolkit.Lib.Controllers.Sensors;
public class SensorsController(
SensorsControllerV1 controllerV1,
SensorsControllerV2 controllerV2,
SensorsControllerV3 controllerV3)
: ISensorsController
{
private ISensorsController? _controller;
public async Task IsSupportedAsync() => await GetControllerAsync().ConfigureAwait(false) is not null;
public async Task PrepareAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false) ?? throw new InvalidOperationException("No supported controller found");
await controller.PrepareAsync().ConfigureAwait(false);
}
public async Task GetDataAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false) ?? throw new InvalidOperationException("No supported controller found");
return await controller.GetDataAsync().ConfigureAwait(false);
}
public async Task<(int cpuFanSpeed, int gpuFanSpeed)> GetFanSpeedsAsync()
{
var controller = await GetControllerAsync().ConfigureAwait(false) ?? throw new InvalidOperationException("No supported controller found");
return await controller.GetFanSpeedsAsync().ConfigureAwait(false);
}
private async Task GetControllerAsync()
{
if (_controller is not null)
return _controller;
if (await controllerV3.IsSupportedAsync().ConfigureAwait(false))
return _controller = controllerV3;
if (await controllerV2.IsSupportedAsync().ConfigureAwait(false))
return _controller = controllerV2;
if (await controllerV1.IsSupportedAsync().ConfigureAwait(false))
return _controller = controllerV1;
return null;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsControllerV1.cs
================================================
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.System.Management;
namespace LenovoLegionToolkit.Lib.Controllers.Sensors;
public class SensorsControllerV1(GPUController gpuController) : AbstractSensorsController(gpuController)
{
private const int CPU_SENSOR_ID = 3;
private const int GPU_SENSOR_ID = 4;
private const int CPU_FAN_ID = 0;
private const int GPU_FAN_ID = 1;
public override async Task IsSupportedAsync()
{
try
{
var result = await WMI.LenovoFanTableData.ExistsAsync(0, CPU_FAN_ID).ConfigureAwait(false);
result &= await WMI.LenovoFanTableData.ExistsAsync(0, GPU_FAN_ID).ConfigureAwait(false);
if (result)
_ = await GetDataAsync().ConfigureAwait(false);
return result;
}
catch
{
return false;
}
}
protected override async Task GetCpuCurrentTemperatureAsync()
{
var t = await WMI.LenovoFanMethod.FanGetCurrentSensorTemperatureAsync(CPU_SENSOR_ID).ConfigureAwait(false);
if (t < 1)
return -1;
return t;
}
protected override async Task GetGpuCurrentTemperatureAsync()
{
var t = await WMI.LenovoFanMethod.FanGetCurrentSensorTemperatureAsync(GPU_SENSOR_ID).ConfigureAwait(false);
if (t < 1)
return -1;
return t;
}
protected override Task GetCpuCurrentFanSpeedAsync() => WMI.LenovoFanMethod.FanGetCurrentFanSpeedAsync(CPU_FAN_ID);
protected override Task GetGpuCurrentFanSpeedAsync() => WMI.LenovoFanMethod.FanGetCurrentFanSpeedAsync(GPU_FAN_ID);
protected override Task GetCpuMaxFanSpeedAsync() => WMI.LenovoFanMethod.GetDefaultFanMaxSpeedAsync(0, CPU_FAN_ID);
protected override Task GetGpuMaxFanSpeedAsync() => WMI.LenovoFanMethod.GetDefaultFanMaxSpeedAsync(0, GPU_FAN_ID);
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsControllerV2.cs
================================================
using System;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
namespace LenovoLegionToolkit.Lib.Controllers.Sensors;
public class SensorsControllerV2(GPUController gpuController) : AbstractSensorsController(gpuController)
{
private const int CPU_SENSOR_ID = 3;
private const int GPU_SENSOR_ID = 4;
private const int CPU_FAN_ID = 0;
private const int GPU_FAN_ID = 1;
public override async Task IsSupportedAsync()
{
try
{
var result = await WMI.LenovoFanTableData.ExistsAsync(CPU_SENSOR_ID, CPU_FAN_ID).ConfigureAwait(false);
result &= await WMI.LenovoFanTableData.ExistsAsync(GPU_SENSOR_ID, GPU_FAN_ID).ConfigureAwait(false);
if (result)
_ = await GetDataAsync().ConfigureAwait(false);
return result;
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Error checking support. [type={GetType().Name}]", ex);
return false;
}
}
protected override async Task GetCpuCurrentTemperatureAsync()
{
var t = await WMI.LenovoFanMethod.FanGetCurrentSensorTemperatureAsync(CPU_SENSOR_ID).ConfigureAwait(false);
if (t < 1)
return -1;
return t;
}
protected override async Task GetGpuCurrentTemperatureAsync()
{
var t = await WMI.LenovoFanMethod.FanGetCurrentSensorTemperatureAsync(GPU_SENSOR_ID).ConfigureAwait(false);
if (t < 1)
return -1;
return t;
}
protected override Task GetCpuCurrentFanSpeedAsync() => WMI.LenovoFanMethod.FanGetCurrentFanSpeedAsync(CPU_FAN_ID);
protected override Task GetGpuCurrentFanSpeedAsync() => WMI.LenovoFanMethod.FanGetCurrentFanSpeedAsync(GPU_FAN_ID);
protected override Task GetCpuMaxFanSpeedAsync() => WMI.LenovoFanMethod.GetCurrentFanMaxSpeedAsync(CPU_SENSOR_ID, CPU_FAN_ID);
protected override Task GetGpuMaxFanSpeedAsync() => WMI.LenovoFanMethod.GetCurrentFanMaxSpeedAsync(GPU_SENSOR_ID, GPU_FAN_ID);
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsControllerV3.cs
================================================
using System;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
namespace LenovoLegionToolkit.Lib.Controllers.Sensors;
public class SensorsControllerV3(GPUController gpuController) : AbstractSensorsController(gpuController)
{
private const int CPU_SENSOR_ID = 4;
private const int GPU_SENSOR_ID = 5;
private const int CPU_FAN_ID = 1;
private const int GPU_FAN_ID = 2;
public override async Task IsSupportedAsync()
{
try
{
var result = await WMI.LenovoFanTableData.ExistsAsync(CPU_SENSOR_ID, CPU_FAN_ID).ConfigureAwait(false);
result &= await WMI.LenovoFanTableData.ExistsAsync(GPU_SENSOR_ID, GPU_FAN_ID).ConfigureAwait(false);
if (result)
_ = await GetDataAsync().ConfigureAwait(false);
return result;
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Error checking support. [type={GetType().Name}]", ex);
return false;
}
}
protected override async Task GetCpuCurrentTemperatureAsync()
{
var value = await WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.CpuCurrentTemperature).ConfigureAwait(false);
return value < 1 ? -1 : value;
}
protected override async Task GetGpuCurrentTemperatureAsync()
{
var value = await WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.GpuCurrentTemperature).ConfigureAwait(false);
return value < 1 ? -1 : value;
}
protected override Task GetCpuCurrentFanSpeedAsync() => WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.CpuCurrentFanSpeed);
protected override Task GetGpuCurrentFanSpeedAsync() => WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.GpuCurrentFanSpeed);
protected override Task GetCpuMaxFanSpeedAsync() => WMI.LenovoFanMethod.GetCurrentFanMaxSpeedAsync(CPU_SENSOR_ID, CPU_FAN_ID);
protected override Task GetGpuMaxFanSpeedAsync() => WMI.LenovoFanMethod.GetCurrentFanMaxSpeedAsync(GPU_SENSOR_ID, GPU_FAN_ID);
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/SmartFnLockController.cs
================================================
using System;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Features;
using LenovoLegionToolkit.Lib.Settings;
using LenovoLegionToolkit.Lib.Utils;
using NeoSmart.AsyncLock;
using Windows.Win32;
using Windows.Win32.UI.Input.KeyboardAndMouse;
using Windows.Win32.UI.WindowsAndMessaging;
namespace LenovoLegionToolkit.Lib.Controllers;
public class SmartFnLockController(FnLockFeature feature, ApplicationSettings settings)
{
private readonly AsyncLock _lock = new();
private bool _ctrlDepressed;
private bool _shiftDepressed;
private bool _altDepressed;
private bool _restoreFnLock;
public void OnKeyboardEvent(nuint wParam, KBDLLHOOKSTRUCT kbStruct)
{
if (settings.Store.SmartFnLockFlags == 0)
return;
Task.Run(async () =>
{
try
{
using (await _lock.LockAsync().ConfigureAwait(false))
await OnKeyboardEventAsync(wParam, kbStruct).ConfigureAwait(false);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to handle keyboard event.", ex);
}
});
}
private async Task OnKeyboardEventAsync(nuint wParam, KBDLLHOOKSTRUCT kbStruct)
{
if (IsModifierKeyPressed(wParam, kbStruct))
{
if (_restoreFnLock)
return;
var state = await feature.GetStateAsync().ConfigureAwait(false);
if (state == FnLockState.Off)
return;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Disabling Fn Lock temporarily...");
await feature.SetStateAsync(FnLockState.Off).ConfigureAwait(false);
_restoreFnLock = true;
}
else if (_restoreFnLock)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Re-enabling Fn Lock...");
await feature.SetStateAsync(FnLockState.On).ConfigureAwait(false);
_restoreFnLock = false;
}
}
private bool IsModifierKeyPressed(nuint wParam, KBDLLHOOKSTRUCT kbStruct)
{
var isKeyDown = wParam is PInvoke.WM_KEYDOWN or PInvoke.WM_SYSKEYDOWN;
var vkKeyCode = (VIRTUAL_KEY)kbStruct.vkCode;
if (vkKeyCode is VIRTUAL_KEY.VK_LCONTROL or VIRTUAL_KEY.VK_RCONTROL)
_ctrlDepressed = isKeyDown;
if (vkKeyCode is VIRTUAL_KEY.VK_LSHIFT or VIRTUAL_KEY.VK_RSHIFT)
_shiftDepressed = isKeyDown;
if (vkKeyCode is VIRTUAL_KEY.VK_LMENU or VIRTUAL_KEY.VK_RMENU)
_altDepressed = isKeyDown;
if (!_ctrlDepressed && !_shiftDepressed && !_altDepressed)
return false;
var result = false;
var flags = settings.Store.SmartFnLockFlags;
if (flags.HasFlag(ModifierKey.Ctrl))
result |= _ctrlDepressed;
if (flags.HasFlag(ModifierKey.Shift))
result |= _shiftDepressed;
if (flags.HasFlag(ModifierKey.Alt))
result |= _altDepressed;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Modifier key is depressed: {result} [ctrl={_ctrlDepressed}, shift={_shiftDepressed}, alt={_altDepressed}, flags={flags}]");
return result;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/SpectrumKeyboardBacklightController.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.Listeners;
using LenovoLegionToolkit.Lib.SoftwareDisabler;
using LenovoLegionToolkit.Lib.System;
using LenovoLegionToolkit.Lib.Utils;
using Microsoft.Win32.SafeHandles;
using NeoSmart.AsyncLock;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Windows.Win32;
namespace LenovoLegionToolkit.Lib.Controllers;
public class SpectrumKeyboardBacklightController
{
public interface IScreenCapture
{
void CaptureScreen(ref RGBColor[,] buffer, int width, int height, CancellationToken token);
}
private readonly struct KeyMap(int width, int height, ushort[,] keyCodes, ushort[] additionalKeyCodes)
{
public static readonly KeyMap Empty = new(0, 0, new ushort[0, 0], []);
public readonly int Width = width;
public readonly int Height = height;
public readonly ushort[,] KeyCodes = keyCodes;
public readonly ushort[] AdditionalKeyCodes = additionalKeyCodes;
}
private static readonly AsyncLock GetDeviceHandleLock = new();
private static readonly object IoLock = new();
private readonly TimeSpan _auroraRefreshInterval = TimeSpan.FromMilliseconds(60);
private readonly SpecialKeyListener _listener;
private readonly VantageDisabler _vantageDisabler;
private readonly IScreenCapture _screenCapture;
private SafeFileHandle? _deviceHandle;
private CancellationTokenSource? _auroraRefreshCancellationTokenSource;
private Task? _auroraRefreshTask;
private readonly JsonSerializerSettings _jsonSerializerSettings = new()
{
Formatting = Formatting.Indented,
TypeNameHandling = TypeNameHandling.Auto,
ObjectCreationHandling = ObjectCreationHandling.Replace,
Converters = [new StringEnumConverter()]
};
public bool ForceDisable { get; set; }
public SpectrumKeyboardBacklightController(SpecialKeyListener listener, VantageDisabler vantageDisabler, IScreenCapture screenCapture)
{
_listener = listener;
_vantageDisabler = vantageDisabler;
_screenCapture = screenCapture;
_listener.Changed += Listener_Changed;
}
private async void Listener_Changed(object? sender, SpecialKeyListener.ChangedEventArgs e)
{
if (!await IsSupportedAsync().ConfigureAwait(false))
return;
if (await _vantageDisabler.GetStatusAsync().ConfigureAwait(false) == SoftwareStatus.Enabled)
return;
switch (e.SpecialKey)
{
case SpecialKey.SpectrumPreset1
or SpecialKey.SpectrumPreset2
or SpecialKey.SpectrumPreset3
or SpecialKey.SpectrumPreset4
or SpecialKey.SpectrumPreset5
or SpecialKey.SpectrumPreset6:
{
await StartAuroraIfNeededAsync().ConfigureAwait(false);
break;
}
}
}
public async Task IsSupportedAsync() => await GetDeviceHandleAsync().ConfigureAwait(false) is not null;
public async Task<(SpectrumLayout, KeyboardLayout, HashSet)> GetKeyboardLayoutAsync()
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Checking keyboard layout...");
var (width, height, keys) = await ReadAllKeyCodesAsync().ConfigureAwait(false);
var mi = await Compatibility.GetMachineInformationAsync().ConfigureAwait(false);
var spectrumLayout = (width, height) switch
{
(22, 9) when mi.Properties.HasAlternativeFullSpectrumLayout => SpectrumLayout.FullAlternative,
(22, 9) => SpectrumLayout.Full,
(20, 8) => SpectrumLayout.KeyboardAndFront,
_ => SpectrumLayout.KeyboardOnly // (20, 7)
};
KeyboardLayout keyboardLayout;
if (keys.Contains(0xA9))
keyboardLayout = KeyboardLayout.Jis;
else if (keys.Contains(0xA8))
keyboardLayout = KeyboardLayout.Iso;
else
keyboardLayout = KeyboardLayout.Ansi;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Layout is {spectrumLayout}, {keyboardLayout}.");
return (spectrumLayout, keyboardLayout, keys);
}
public async Task GetBrightnessAsync()
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting keyboard brightness...");
var input = new LENOVO_SPECTRUM_GET_BRIGHTNESS_REQUEST();
SetAndGetFeature(handle, input, out LENOVO_SPECTRUM_GET_BRIGHTNESS_RESPONSE output);
var result = output.Brightness;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Keyboard brightness is {result}.");
return result;
}
public async Task SetBrightnessAsync(int brightness)
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
if (brightness is < 0 or > 9)
throw new InvalidOperationException("Brightness must be between 0 and 9");
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Setting keyboard brightness to: {brightness}.");
var input = new LENOVO_SPECTRUM_SET_BRIGHTNESS_REQUEST((byte)brightness);
SetFeature(handle, input);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Keyboard brightness set.");
}
public async Task GetLogoStatusAsync()
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting logo status...");
var input = new LENOVO_SPECTRUM_GET_LOGO_STATUS();
SetAndGetFeature(handle, input, out LENOVO_SPECTRUM_GET_LOGO_STATUS_RESPONSE output);
var result = output.IsOn;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Logo status is {result}.");
return result;
}
public async Task SetLogoStatusAsync(bool isOn)
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Setting logo status to: {isOn}.");
var input = new LENOVO_SPECTRUM_SET_LOGO_STATUS_REQUEST(isOn);
SetFeature(handle, input);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Logo status set.");
}
public async Task GetProfileAsync()
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting keyboard profile...");
var input = new LENOVO_SPECTRUM_GET_PROFILE_REQUEST();
SetAndGetFeature(handle, input, out LENOVO_SPECTRUM_GET_PROFILE_RESPONSE output);
var result = output.Profile;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Keyboard profile is {result}.");
return result;
}
public async Task SetProfileAsync(int profile)
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
await StopAuroraIfNeededAsync().ConfigureAwait(false);
if (profile is < 0 or > 6)
throw new InvalidOperationException("Profile must be between 0 and 6");
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Setting keyboard profile to {profile}...");
var input = new LENOVO_SPECTRUM_SET_PROFILE_REQUEST((byte)profile);
SetFeature(handle, input);
await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Keyboard profile set to {profile}.");
await StartAuroraIfNeededAsync(profile).ConfigureAwait(false);
}
public async Task SetProfileDefaultAsync(int profile)
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Setting keyboard profile {profile} to default...");
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Keyboard profile {profile} set to default.");
var input = new LENOVO_SPECTRUM_SET_PROFILE_DEFAULT_REQUEST((byte)profile);
SetFeature(handle, input);
}
public async Task SetProfileDescriptionAsync(int profile, SpectrumKeyboardBacklightEffect[] effects)
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Setting {effects.Length} effect to keyboard profile {profile}...");
effects = Compress(effects);
var bytes = Convert(profile, effects).ToBytes();
SetFeature(handle, bytes);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Set {effects.Length} effect to keyboard profile {profile}.");
await StartAuroraIfNeededAsync(profile).ConfigureAwait(false);
}
public async Task<(int Profile, SpectrumKeyboardBacklightEffect[] Effects)> GetProfileDescriptionAsync(int profile)
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Getting effects for keyboard profile {profile}...");
var input = new LENOVO_SPECTRUM_GET_EFFECT_REQUEST((byte)profile);
SetAndGetFeature(handle, input, out var buffer, 960);
var description = LENOVO_SPECTRUM_EFFECT_DESCRIPTION.FromBytes(buffer);
var result = Convert(description);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Retrieved {result.Effects.Length} effects for keyboard profile {profile}...");
return result;
}
public async Task ImportProfileDescription(int profile, string jsonPath)
{
var json = await File.ReadAllTextAsync(jsonPath).ConfigureAwait(false);
var effects = JsonConvert.DeserializeObject(json)
?? throw new InvalidOperationException("Couldn't deserialize effects");
await SetProfileDescriptionAsync(profile, effects).ConfigureAwait(false);
}
public async Task ExportProfileDescriptionAsync(int profile, string jsonPath)
{
var (_, effects) = await GetProfileDescriptionAsync(profile).ConfigureAwait(false);
var json = JsonConvert.SerializeObject(effects, _jsonSerializerSettings);
await File.WriteAllTextAsync(jsonPath, json).ConfigureAwait(false);
}
public async Task StartAuroraIfNeededAsync(int? profile = null)
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
await StopAuroraIfNeededAsync().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Starting Aurora... [profile={profile}]");
profile ??= await GetProfileAsync().ConfigureAwait(false);
var (_, effects) = await GetProfileDescriptionAsync(profile.Value).ConfigureAwait(false);
if (!effects.Any(e => e.Type == SpectrumKeyboardBacklightEffectType.AuroraSync))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Aurora not needed. [profile={profile}]");
return false;
}
_auroraRefreshCancellationTokenSource = new();
var token = _auroraRefreshCancellationTokenSource.Token;
_auroraRefreshTask = Task.Run(() => AuroraRefreshAsync(profile.Value, token), token);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Aurora started. [profile={profile}]");
return true;
}
public async Task StopAuroraIfNeededAsync()
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Stopping Aurora...");
if (_auroraRefreshCancellationTokenSource is not null)
await _auroraRefreshCancellationTokenSource.CancelAsync().ConfigureAwait(false);
if (_auroraRefreshTask is not null)
await _auroraRefreshTask.ConfigureAwait(false);
_auroraRefreshTask = null;
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Aurora stopped.");
}
public async Task> GetStateAsync(bool skipVantageCheck = false)
{
if (!skipVantageCheck)
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
GetFeature(handle, out LENOVO_SPECTRUM_STATE_RESPONSE state);
var dict = new Dictionary();
foreach (var key in state.Data.Where(k => k.KeyCode > 0))
{
var rgb = new RGBColor(key.Color.R, key.Color.G, key.Color.B);
dict.TryAdd(key.KeyCode, rgb);
}
return dict;
}
private async Task ThrowIfVantageEnabled()
{
var vantageStatus = await _vantageDisabler.GetStatusAsync().ConfigureAwait(false);
if (vantageStatus == SoftwareStatus.Enabled)
throw new InvalidOperationException("Can't manage Spectrum keyboard with Vantage enabled");
}
private async Task<(int Width, int Height, HashSet Keys)> ReadAllKeyCodesAsync()
{
var keyMap = await GetKeyMapAsync().ConfigureAwait(false);
var keyCodes = new HashSet(keyMap.Width * keyMap.Height);
foreach (var keyCode in keyMap.KeyCodes)
if (keyCode > 0)
keyCodes.Add(keyCode);
foreach (var keyCode in keyMap.AdditionalKeyCodes)
if (keyCode > 0)
keyCodes.Add(keyCode);
return (keyMap.Width, keyMap.Height, keyCodes);
}
private async Task GetKeyMapAsync()
{
try
{
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
return KeyMap.Empty;
SetAndGetFeature(handle,
new LENOVO_SPECTRUM_GET_KEY_COUNT_REQUEST(),
out LENOVO_SPECTRUM_GET_KEY_COUNT_RESPONSE keyCountResponse);
var width = keyCountResponse.KeysPerIndex;
var height = keyCountResponse.Indexes;
var keyCodes = new ushort[width, height];
var additionalKeyCodes = new ushort[width];
for (var y = 0; y < height; y++)
{
SetAndGetFeature(handle,
new LENOVO_SPECTRUM_GET_KEY_PAGE_REQUEST((byte)y),
out LENOVO_SPECTRUM_GET_KEY_PAGE_RESPONSE keyPageResponse);
for (var x = 0; x < width; x++)
keyCodes[x, y] = keyPageResponse.Items[x].KeyCode;
}
SetAndGetFeature(handle,
new LENOVO_SPECTRUM_GET_KEY_PAGE_REQUEST(0, true),
out LENOVO_SPECTRUM_GET_KEY_PAGE_RESPONSE secondaryKeyPageResponse);
for (var x = 0; x < width; x++)
additionalKeyCodes[x] = secondaryKeyPageResponse.Items[x].KeyCode;
return new(width, height, keyCodes, additionalKeyCodes);
}
catch
{
return KeyMap.Empty;
}
}
private async Task AuroraRefreshAsync(int profile, CancellationToken token)
{
try
{
await ThrowIfVantageEnabled().ConfigureAwait(false);
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is null)
throw new InvalidOperationException(nameof(handle));
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Aurora refresh starting...");
var keyMap = await GetKeyMapAsync().ConfigureAwait(false);
var width = keyMap.Width;
var height = keyMap.Height;
var colorBuffer = new RGBColor[width, height];
SetFeature(handle, new LENOVO_SPECTRUM_AURORA_START_STOP_REQUEST(true, (byte)profile));
while (!token.IsCancellationRequested)
{
var delay = Task.Delay(_auroraRefreshInterval, token);
try
{
_screenCapture.CaptureScreen(ref colorBuffer, width, height, token);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Screen capture failed. Delaying before next refresh...", ex);
await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false);
}
token.ThrowIfCancellationRequested();
var items = new List(width * height);
var avgR = 0;
var avgG = 0;
var avgB = 0;
for (var x = 0; x < width; x++)
{
for (var y = 0; y < height; y++)
{
var keyCode = keyMap.KeyCodes[x, y];
if (keyCode < 1)
continue;
var color = colorBuffer[x, y];
avgR += color.R;
avgG += color.G;
avgB += color.B;
items.Add(new(keyCode, new(color.R, color.G, color.B)));
}
}
avgR /= items.Count;
avgG /= items.Count;
avgB /= items.Count;
for (var x = 0; x < width; x++)
{
var keyCode = keyMap.AdditionalKeyCodes[x];
if (keyCode < 1)
continue;
items.Add(new(keyCode, new((byte)avgR, (byte)avgB, (byte)avgG)));
}
token.ThrowIfCancellationRequested();
SetFeature(handle, new LENOVO_SPECTRUM_AURORA_SEND_BITMAP_REQUEST([.. items]).ToBytes());
await delay.ConfigureAwait(false);
}
}
catch (OperationCanceledException) { }
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Unexpected exception while refreshing Aurora.", ex);
}
finally
{
var handle = await GetDeviceHandleAsync().ConfigureAwait(false);
if (handle is not null)
{
var currentProfile = await GetProfileAsync().ConfigureAwait(false);
SetFeature(handle, new LENOVO_SPECTRUM_AURORA_START_STOP_REQUEST(false, (byte)currentProfile));
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Aurora refresh stopped.");
}
}
private async Task GetDeviceHandleAsync()
{
if (ForceDisable)
return null;
try
{
using (await GetDeviceHandleLock.LockAsync().ConfigureAwait(false))
{
if (_deviceHandle is not null && IsReady(_deviceHandle))
return _deviceHandle;
SafeFileHandle? newDeviceHandle = null;
const int retries = 3;
const int delay = 50;
for (var i = 0; i < retries; i++)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Refreshing handle... [retry={i + 1}]");
var tempDeviceHandle = Devices.GetSpectrumRGBKeyboard(true);
if (tempDeviceHandle is not null && IsReady(tempDeviceHandle))
{
newDeviceHandle = tempDeviceHandle;
break;
}
await Task.Delay(delay).ConfigureAwait(false);
}
if (newDeviceHandle is null)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Handle couldn't be refreshed.");
return null;
}
SetAndGetFeature(newDeviceHandle,
new LENOVO_SPECTRUM_GET_COMPATIBILITY_REQUEST(),
out LENOVO_SPECTRUM_GET_COMPATIBILITY_RESPONSE res);
if (!res.IsCompatible)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Handle not compatible.");
return null;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Handle refreshed.");
_deviceHandle = newDeviceHandle;
return newDeviceHandle;
}
}
catch
{
return null;
}
}
private static bool IsReady(SafeHandle handle)
{
try
{
var b = new byte[960];
b[0] = 7;
SetFeature(handle, b);
return true;
}
catch
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Keyboard not ready.");
return false;
}
}
private static void SetAndGetFeature(SafeHandle handle, TIn input, out TOut output) where TIn : notnull where TOut : struct
{
lock (IoLock)
{
SetFeature(handle, input);
GetFeature(handle, out output);
}
}
private static void SetAndGetFeature(SafeHandle handle, TIn input, out byte[] output, int size) where TIn : notnull
{
lock (IoLock)
{
SetFeature(handle, input);
GetFeature(handle, out output, size);
}
}
private static unsafe void SetFeature(SafeHandle handle, T str) where T : notnull
{
lock (IoLock)
{
var ptr = IntPtr.Zero;
try
{
int size;
if (str is byte[] bytes)
{
size = bytes.Length;
ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(bytes, 0, ptr, size);
}
else
{
size = Marshal.SizeOf();
ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, false);
}
var result = PInvoke.HidD_SetFeature(handle, ptr.ToPointer(), (uint)size);
if (!result)
PInvokeExtensions.ThrowIfWin32Error(typeof(T).Name);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
}
private static unsafe void GetFeature(SafeHandle handle, out T str) where T : struct
{
lock (IoLock)
{
var ptr = IntPtr.Zero;
try
{
var size = Marshal.SizeOf();
ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(new byte[] { 7 }, 0, ptr, 1);
var result = PInvoke.HidD_GetFeature(handle, ptr.ToPointer(), (uint)size);
if (!result)
PInvokeExtensions.ThrowIfWin32Error(typeof(T).Name);
str = Marshal.PtrToStructure(ptr);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
}
private static unsafe void GetFeature(SafeHandle handle, out byte[] bytes, int size)
{
lock (IoLock)
{
var ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(new byte[] { 7 }, 0, ptr, 1);
var result = PInvoke.HidD_GetFeature(handle, ptr.ToPointer(), (uint)size);
if (!result)
PInvokeExtensions.ThrowIfWin32Error("bytes");
bytes = new byte[size];
Marshal.Copy(ptr, bytes, 0, size);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
}
private static SpectrumKeyboardBacklightEffect[] Compress(SpectrumKeyboardBacklightEffect[] effects)
{
if (effects.Any(e => e.Type.IsAllLightsEffect()))
return [effects.Last(e => e.Type.IsAllLightsEffect())];
var usedKeyCodes = new HashSet();
var newEffects = new List();
foreach (var effect in effects.Reverse())
{
if (effect.Type.IsWholeKeyboardEffect() && usedKeyCodes.Intersect(effect.Keys).Any())
continue;
var newKeyCodes = effect.Keys.Except(usedKeyCodes).ToArray();
foreach (var keyCode in newKeyCodes)
usedKeyCodes.Add(keyCode);
if (newKeyCodes.IsEmpty())
continue;
var newEffect = new SpectrumKeyboardBacklightEffect(effect.Type,
effect.Speed,
effect.Direction,
effect.ClockwiseDirection,
effect.Colors,
newKeyCodes);
newEffects.Add(newEffect);
}
newEffects.Reverse();
return [.. newEffects];
}
private static (int Profile, SpectrumKeyboardBacklightEffect[] Effects) Convert(LENOVO_SPECTRUM_EFFECT_DESCRIPTION description)
{
var profile = description.Profile;
var effects = description.Effects.Select(Convert).ToArray();
return (profile, effects);
}
private static SpectrumKeyboardBacklightEffect Convert(LENOVO_SPECTRUM_EFFECT effect)
{
var effectType = effect.EffectHeader.EffectType switch
{
LENOVO_SPECTRUM_EFFECT_TYPE.Always => SpectrumKeyboardBacklightEffectType.Always,
LENOVO_SPECTRUM_EFFECT_TYPE.LegionAuraSync => SpectrumKeyboardBacklightEffectType.AuroraSync,
LENOVO_SPECTRUM_EFFECT_TYPE.AudioBounceLighting => SpectrumKeyboardBacklightEffectType.AudioBounce,
LENOVO_SPECTRUM_EFFECT_TYPE.AudioRippleLighting => SpectrumKeyboardBacklightEffectType.AudioRipple,
LENOVO_SPECTRUM_EFFECT_TYPE.ColorChange => SpectrumKeyboardBacklightEffectType.ColorChange,
LENOVO_SPECTRUM_EFFECT_TYPE.ColorPulse => SpectrumKeyboardBacklightEffectType.ColorPulse,
LENOVO_SPECTRUM_EFFECT_TYPE.ColorWave => SpectrumKeyboardBacklightEffectType.ColorWave,
LENOVO_SPECTRUM_EFFECT_TYPE.Rain => SpectrumKeyboardBacklightEffectType.Rain,
LENOVO_SPECTRUM_EFFECT_TYPE.ScrewRainbow => SpectrumKeyboardBacklightEffectType.RainbowScrew,
LENOVO_SPECTRUM_EFFECT_TYPE.RainbowWave => SpectrumKeyboardBacklightEffectType.RainbowWave,
LENOVO_SPECTRUM_EFFECT_TYPE.Ripple => SpectrumKeyboardBacklightEffectType.Ripple,
LENOVO_SPECTRUM_EFFECT_TYPE.Smooth => SpectrumKeyboardBacklightEffectType.Smooth,
LENOVO_SPECTRUM_EFFECT_TYPE.TypeLighting => SpectrumKeyboardBacklightEffectType.Type,
_ => throw new ArgumentException(nameof(effect.EffectHeader.EffectType))
};
var speed = effect.EffectHeader.Speed switch
{
LENOVO_SPECTRUM_SPEED.Speed1 => SpectrumKeyboardBacklightSpeed.Speed1,
LENOVO_SPECTRUM_SPEED.Speed2 => SpectrumKeyboardBacklightSpeed.Speed2,
LENOVO_SPECTRUM_SPEED.Speed3 => SpectrumKeyboardBacklightSpeed.Speed3,
_ => SpectrumKeyboardBacklightSpeed.None
};
var direction = effect.EffectHeader.Direction switch
{
LENOVO_SPECTRUM_DIRECTION.LeftToRight => SpectrumKeyboardBacklightDirection.LeftToRight,
LENOVO_SPECTRUM_DIRECTION.RightToLeft => SpectrumKeyboardBacklightDirection.RightToLeft,
LENOVO_SPECTRUM_DIRECTION.BottomToTop => SpectrumKeyboardBacklightDirection.BottomToTop,
LENOVO_SPECTRUM_DIRECTION.TopToBottom => SpectrumKeyboardBacklightDirection.TopToBottom,
_ => SpectrumKeyboardBacklightDirection.None
};
var clockwiseDirection = effect.EffectHeader.ClockwiseDirection switch
{
LENOVO_SPECTRUM_CLOCKWISE_DIRECTION.Clockwise => SpectrumKeyboardBacklightClockwiseDirection.Clockwise,
LENOVO_SPECTRUM_CLOCKWISE_DIRECTION.CounterClockwise => SpectrumKeyboardBacklightClockwiseDirection.CounterClockwise,
_ => SpectrumKeyboardBacklightClockwiseDirection.None
};
var colors = effect.Colors.Select(c => new RGBColor(c.R, c.G, c.B)).ToArray();
var keys = effect.KeyCodes;
if (effect.KeyCodes is [0x65])
keys = [];
return new(effectType, speed, direction, clockwiseDirection, colors, keys);
}
private static LENOVO_SPECTRUM_EFFECT_DESCRIPTION Convert(int profile, SpectrumKeyboardBacklightEffect[] effects)
{
var header = new LENOVO_SPECTRUM_HEADER(LENOVO_SPECTRUM_OPERATION_TYPE.EffectChange, 0); // Size will be set on serialization
var str = effects.Select((e, i) => Convert(i, e)).ToArray();
var result = new LENOVO_SPECTRUM_EFFECT_DESCRIPTION(header, (byte)profile, str);
return result;
}
private static LENOVO_SPECTRUM_EFFECT Convert(int index, SpectrumKeyboardBacklightEffect effect)
{
var effectType = effect.Type switch
{
SpectrumKeyboardBacklightEffectType.Always => LENOVO_SPECTRUM_EFFECT_TYPE.Always,
SpectrumKeyboardBacklightEffectType.AuroraSync => LENOVO_SPECTRUM_EFFECT_TYPE.LegionAuraSync,
SpectrumKeyboardBacklightEffectType.AudioBounce => LENOVO_SPECTRUM_EFFECT_TYPE.AudioBounceLighting,
SpectrumKeyboardBacklightEffectType.AudioRipple => LENOVO_SPECTRUM_EFFECT_TYPE.AudioRippleLighting,
SpectrumKeyboardBacklightEffectType.ColorChange => LENOVO_SPECTRUM_EFFECT_TYPE.ColorChange,
SpectrumKeyboardBacklightEffectType.ColorPulse => LENOVO_SPECTRUM_EFFECT_TYPE.ColorPulse,
SpectrumKeyboardBacklightEffectType.ColorWave => LENOVO_SPECTRUM_EFFECT_TYPE.ColorWave,
SpectrumKeyboardBacklightEffectType.Rain => LENOVO_SPECTRUM_EFFECT_TYPE.Rain,
SpectrumKeyboardBacklightEffectType.RainbowScrew => LENOVO_SPECTRUM_EFFECT_TYPE.ScrewRainbow,
SpectrumKeyboardBacklightEffectType.RainbowWave => LENOVO_SPECTRUM_EFFECT_TYPE.RainbowWave,
SpectrumKeyboardBacklightEffectType.Ripple => LENOVO_SPECTRUM_EFFECT_TYPE.Ripple,
SpectrumKeyboardBacklightEffectType.Smooth => LENOVO_SPECTRUM_EFFECT_TYPE.Smooth,
SpectrumKeyboardBacklightEffectType.Type => LENOVO_SPECTRUM_EFFECT_TYPE.TypeLighting,
_ => throw new ArgumentException(nameof(effect.Type))
};
var speed = effect.Speed switch
{
SpectrumKeyboardBacklightSpeed.Speed1 => LENOVO_SPECTRUM_SPEED.Speed1,
SpectrumKeyboardBacklightSpeed.Speed2 => LENOVO_SPECTRUM_SPEED.Speed2,
SpectrumKeyboardBacklightSpeed.Speed3 => LENOVO_SPECTRUM_SPEED.Speed3,
_ => LENOVO_SPECTRUM_SPEED.None
};
var direction = effect.Direction switch
{
SpectrumKeyboardBacklightDirection.LeftToRight => LENOVO_SPECTRUM_DIRECTION.LeftToRight,
SpectrumKeyboardBacklightDirection.RightToLeft => LENOVO_SPECTRUM_DIRECTION.RightToLeft,
SpectrumKeyboardBacklightDirection.BottomToTop => LENOVO_SPECTRUM_DIRECTION.BottomToTop,
SpectrumKeyboardBacklightDirection.TopToBottom => LENOVO_SPECTRUM_DIRECTION.TopToBottom,
_ => LENOVO_SPECTRUM_DIRECTION.None
};
var clockwiseDirection = effect.ClockwiseDirection switch
{
SpectrumKeyboardBacklightClockwiseDirection.Clockwise => LENOVO_SPECTRUM_CLOCKWISE_DIRECTION.Clockwise,
SpectrumKeyboardBacklightClockwiseDirection.CounterClockwise => LENOVO_SPECTRUM_CLOCKWISE_DIRECTION.CounterClockwise,
_ => LENOVO_SPECTRUM_CLOCKWISE_DIRECTION.None
};
var colorMode = effect.Type switch
{
SpectrumKeyboardBacklightEffectType.Always => LENOVO_SPECTRUM_COLOR_MODE.ColorList,
SpectrumKeyboardBacklightEffectType.ColorChange when effect.Colors.Length != 0 => LENOVO_SPECTRUM_COLOR_MODE.ColorList,
SpectrumKeyboardBacklightEffectType.ColorPulse when effect.Colors.Length != 0 => LENOVO_SPECTRUM_COLOR_MODE.ColorList,
SpectrumKeyboardBacklightEffectType.ColorWave when effect.Colors.Length != 0 => LENOVO_SPECTRUM_COLOR_MODE.ColorList,
SpectrumKeyboardBacklightEffectType.Rain when effect.Colors.Length != 0 => LENOVO_SPECTRUM_COLOR_MODE.ColorList,
SpectrumKeyboardBacklightEffectType.Smooth when effect.Colors.Length != 0 => LENOVO_SPECTRUM_COLOR_MODE.ColorList,
SpectrumKeyboardBacklightEffectType.Ripple when effect.Colors.Length != 0 => LENOVO_SPECTRUM_COLOR_MODE.ColorList,
SpectrumKeyboardBacklightEffectType.Type when effect.Colors.Length != 0 => LENOVO_SPECTRUM_COLOR_MODE.ColorList,
SpectrumKeyboardBacklightEffectType.ColorChange => LENOVO_SPECTRUM_COLOR_MODE.RandomColor,
SpectrumKeyboardBacklightEffectType.ColorPulse => LENOVO_SPECTRUM_COLOR_MODE.RandomColor,
SpectrumKeyboardBacklightEffectType.ColorWave => LENOVO_SPECTRUM_COLOR_MODE.RandomColor,
SpectrumKeyboardBacklightEffectType.Rain => LENOVO_SPECTRUM_COLOR_MODE.RandomColor,
SpectrumKeyboardBacklightEffectType.Smooth => LENOVO_SPECTRUM_COLOR_MODE.RandomColor,
SpectrumKeyboardBacklightEffectType.Ripple => LENOVO_SPECTRUM_COLOR_MODE.RandomColor,
SpectrumKeyboardBacklightEffectType.Type => LENOVO_SPECTRUM_COLOR_MODE.RandomColor,
_ => LENOVO_SPECTRUM_COLOR_MODE.None
};
var header = new LENOVO_SPECTRUM_EFFECT_HEADER(effectType, speed, direction, clockwiseDirection, colorMode);
var colors = effect.Colors.Select(c => new LENOVO_SPECTRUM_COLOR(c.R, c.G, c.B)).ToArray();
var keys = effect.Type.IsAllLightsEffect() ? [0x65] : effect.Keys;
var result = new LENOVO_SPECTRUM_EFFECT(header, index + 1, colors, keys);
return result;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/WindowsPowerModeController.cs
================================================
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.Settings;
using LenovoLegionToolkit.Lib.System;
using LenovoLegionToolkit.Lib.Utils;
using Windows.Win32;
using Windows.Win32.Foundation;
namespace LenovoLegionToolkit.Lib.Controllers;
public partial class WindowsPowerModeController(ApplicationSettings settings, IMainThreadDispatcher mainThreadDispatcher)
{
private const string POWER_SCHEMES_HIVE = "HKEY_LOCAL_MACHINE";
private const string POWER_SCHEMES_SUBKEY = "SYSTEM\\CurrentControlSet\\Control\\Power\\User\\PowerSchemes";
private const string ACTIVE_OVERLAY_AC_POWER_SCHEME_KEY = "ActiveOverlayAcPowerScheme";
private const string ACTIVE_OVERLAY_DC_POWER_SCHEME_KEY = "ActiveOverlayDcPowerScheme";
private static readonly Guid DefaultPowerPlan = Guid.Parse("381b4222-f694-41f0-9685-ff5bb260df2e");
private static readonly Guid BestPowerEfficiency = Guid.Parse("961cc777-2547-4f9d-8174-7d86181b8a7a");
private static readonly Guid BestPerformance = Guid.Parse("ded574b5-45a0-4f42-8737-46345c09c238");
private readonly ThrottleLastDispatcher _dispatcher = new(TimeSpan.FromSeconds(2), nameof(WindowsPowerModeController));
public async Task SetPowerModeAsync(PowerModeState powerModeState)
{
if (settings.Store.PowerModeMappingMode is not PowerModeMappingMode.WindowsPowerMode)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Ignoring... [powerModeMappingMode={settings.Store.PowerModeMappingMode}]");
return;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Activating... [powerModeState={powerModeState}]");
var powerMode = settings.Store.PowerModes.GetValueOrDefault(powerModeState, WindowsPowerMode.Balanced);
var powerModeGuid = GuidForWindowsPowerMode(powerMode);
if (Power.IsBatterySaverEnabled())
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Battery saver is on - will not set overlay scheme.");
return;
}
await _dispatcher.DispatchAsync(() =>
{
ActivateDefaultPowerPlanIfNeeded();
mainThreadDispatcher.Dispatch(() =>
{
var result = PowerSetActiveOverlayScheme(powerModeGuid);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Overlay scheme set. [result={result}]");
});
try
{
UpdateRegistry(powerModeGuid);
}
catch (Exception ex)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Failed to update registry.", ex);
}
return Task.CompletedTask;
}).ConfigureAwait(false);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Power mode {powerMode} activated... [powerModeState={powerModeState}, powerModeGuid={powerModeGuid}]");
}
private static void UpdateRegistry(Guid guid)
{
Registry.SetValue(POWER_SCHEMES_HIVE, POWER_SCHEMES_SUBKEY, ACTIVE_OVERLAY_AC_POWER_SCHEME_KEY, guid, true);
Registry.SetValue(POWER_SCHEMES_HIVE, POWER_SCHEMES_SUBKEY, ACTIVE_OVERLAY_DC_POWER_SCHEME_KEY, guid, true);
}
private static Guid GuidForWindowsPowerMode(WindowsPowerMode windowsPowerMode) => windowsPowerMode switch
{
WindowsPowerMode.BestPowerEfficiency => BestPowerEfficiency,
WindowsPowerMode.BestPerformance => BestPerformance,
_ => Guid.Empty
};
private static unsafe void ActivateDefaultPowerPlanIfNeeded()
{
if (PInvoke.PowerGetActiveScheme(null, out var guid) != WIN32_ERROR.ERROR_SUCCESS)
PInvokeExtensions.ThrowIfWin32Error("PowerGetActiveScheme");
if (DefaultPowerPlan == *guid)
return;
if (PInvoke.PowerSetActiveScheme(null, DefaultPowerPlan) != WIN32_ERROR.ERROR_SUCCESS)
PInvokeExtensions.ThrowIfWin32Error("PowerSetActiveScheme");
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Activated default power plan.");
}
[LibraryImport("powrprof.dll", EntryPoint = "PowerSetActiveOverlayScheme")]
private static partial uint PowerSetActiveOverlayScheme(Guid guid);
}
================================================
FILE: LenovoLegionToolkit.Lib/Controllers/WindowsPowerPlanController.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.Extensions;
using LenovoLegionToolkit.Lib.Settings;
using LenovoLegionToolkit.Lib.SoftwareDisabler;
using LenovoLegionToolkit.Lib.Utils;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.System.Power;
namespace LenovoLegionToolkit.Lib.Controllers;
public class WindowsPowerPlanController(ApplicationSettings settings, VantageDisabler vantageDisabler)
{
private static readonly Guid DefaultPowerPlan = Guid.Parse("381b4222-f694-41f0-9685-ff5bb260df2e");
public IEnumerable GetPowerPlans()
{
var activePowerPlanGuid = GetActivePowerPlanGuid();
foreach (var powerPlanGuid in GetPowerPlanGuids())
{
var powerPlaneName = GetPowerPlanName(powerPlanGuid);
yield return new WindowsPowerPlan(powerPlanGuid, powerPlaneName, powerPlanGuid == activePowerPlanGuid);
}
}
public async Task SetPowerPlanAsync(PowerModeState powerModeState, bool alwaysActivateDefaults = false)
{
if (settings.Store.PowerModeMappingMode is not PowerModeMappingMode.WindowsPowerPlan)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Ignoring... [powerModeMappingMode={settings.Store.PowerModeMappingMode}]");
return;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Activating... [powerModeState={powerModeState}, alwaysActivateDefaults={alwaysActivateDefaults}]");
var powerPlanId = settings.Store.PowerPlans.GetValueOrDefault(powerModeState);
var isDefault = false;
if (powerPlanId == Guid.Empty)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Power plan for power mode {powerModeState} was not found in settings");
powerPlanId = DefaultPowerPlan;
isDefault = true;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Power plan to be activated is {powerPlanId} [isDefault={isDefault}]");
if (!await ShouldSetPowerPlanAsync(alwaysActivateDefaults, isDefault).ConfigureAwait(false))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Power plan {powerPlanId} will not be activated [isDefault={isDefault}]");
return;
}
var powerPlans = GetPowerPlans().ToArray();
if (Log.Instance.IsTraceEnabled)
{
Log.Instance.Trace($"Available power plans:");
foreach (var powerPlan in powerPlans)
Log.Instance.Trace($" - {powerPlan}");
}
var powerPlanToActivate = powerPlans.FirstOrDefault(pp => pp.Guid == powerPlanId);
if (powerPlanToActivate.Equals(default(WindowsPowerPlan)))
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Power plan {powerPlanId} was not found");
return;
}
if (powerPlanToActivate.IsActive)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Power plan {powerPlanToActivate.Guid} is already active. [name={powerPlanToActivate.Name}]");
return;
}
SetActivePowerPlan(powerPlanToActivate.Guid);
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Power plan {powerPlanToActivate.Guid} activated. [name={powerPlanToActivate.Name}]");
}
public void SetPowerPlanParameter(WindowsPowerPlan windowsPowerPlan, Brightness brightness)
{
PInvoke.PowerWriteACValueIndex(NullSafeHandle.Null, windowsPowerPlan.Guid, PInvoke.GUID_VIDEO_SUBGROUP, PInvokeExtensions.DISPLAY_BRIGTHNESS_SETTING_GUID, brightness.Value);
PInvoke.PowerWriteDCValueIndex(NullSafeHandle.Null, windowsPowerPlan.Guid, PInvoke.GUID_VIDEO_SUBGROUP, PInvokeExtensions.DISPLAY_BRIGTHNESS_SETTING_GUID, brightness.Value);
}
private async Task ShouldSetPowerPlanAsync(bool alwaysActivateDefaults, bool isDefault)
{
if (isDefault && alwaysActivateDefaults)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Power plan is default and always active defaults is set");
return true;
}
var status = await vantageDisabler.GetStatusAsync().ConfigureAwait(false);
if (status is SoftwareStatus.NotFound or SoftwareStatus.Disabled)
{
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Vantage is active [status={status}]");
return true;
}
if (Log.Instance.IsTraceEnabled)
Log.Instance.Trace($"Criteria for activation not met [isDefault={isDefault}, alwaysActivateDefaults={alwaysActivateDefaults}, status={status}]");
return false;
}
private static unsafe List GetPowerPlanGuids()
{
var list = new List();
var bufferSize = (uint)Marshal.SizeOf();
var buffer = new byte[bufferSize];
fixed (byte* bufferPtr = buffer)
{
uint index = 0;
while (PInvoke.PowerEnumerate(null, null, null, POWER_DATA_ACCESSOR.ACCESS_SCHEME, index, bufferPtr, ref bufferSize) == WIN32_ERROR.ERROR_SUCCESS)
{
list.Add(new Guid(buffer));
index++;
}
}
return list;
}
private static unsafe string GetPowerPlanName(Guid powerPlanGuid)
{
var nameSize = 2048u;
var namePtr = Marshal.AllocHGlobal((int)nameSize);
try
{
if (PInvoke.PowerReadFriendlyName(null, powerPlanGuid, null, null, (byte*)namePtr.ToPointer(), ref nameSize) != WIN32_ERROR.ERROR_SUCCESS)
PInvokeExtensions.ThrowIfWin32Error("PowerReadFriendlyName");
return Marshal.PtrToStringUni(namePtr) ?? string.Empty;
}
catch
{
return powerPlanGuid.ToString();
}
finally
{
Marshal.FreeHGlobal(namePtr);
}
}
private static unsafe Guid GetActivePowerPlanGuid()
{
if (PInvoke.PowerGetActiveScheme(null, out var guid) != WIN32_ERROR.ERROR_SUCCESS)
PInvokeExtensions.ThrowIfWin32Error("PowerGetActiveScheme");
return *guid;
}
private static void SetActivePowerPlan(Guid powerPlanGuid)
{
if (PInvoke.PowerSetActiveScheme(null, powerPlanGuid) != WIN32_ERROR.ERROR_SUCCESS)
PInvokeExtensions.ThrowIfWin32Error("PowerSetActiveScheme");
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Enums.cs
================================================
using System;
using System.ComponentModel.DataAnnotations;
using LenovoLegionToolkit.Lib.Resources;
namespace LenovoLegionToolkit.Lib;
public enum AlwaysOnUSBState
{
[Display(ResourceType = typeof(Resource), Name = "AlwaysOnUSBState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "AlwaysOnUSBState_OnWhenSleeping")]
OnWhenSleeping,
[Display(ResourceType = typeof(Resource), Name = "AlwaysOnUSBState_OnAlways")]
OnAlways
}
public enum AutorunState
{
[Display(ResourceType = typeof(Resource), Name = "AutorunState_Enabled")]
Enabled,
[Display(ResourceType = typeof(Resource), Name = "AutorunState_EnabledDelayed")]
EnabledDelayed,
[Display(ResourceType = typeof(Resource), Name = "AutorunState_Disabled")]
Disabled
}
public enum BatteryNightChargeState
{
[Display(ResourceType = typeof(Resource), Name = "BatteryNightChargeState_On")]
On,
[Display(ResourceType = typeof(Resource), Name = "BatteryNightChargeState_Off")]
Off
}
public enum BatteryState
{
[Display(ResourceType = typeof(Resource), Name = "BatteryState_Conservation")]
Conservation,
[Display(ResourceType = typeof(Resource), Name = "BatteryState_Normal")]
Normal,
[Display(ResourceType = typeof(Resource), Name = "BatteryState_RapidCharge")]
RapidCharge
}
public enum CapabilityID
{
IGPUMode = 0x00010000,
FlipToStart = 0x00030000,
NvidiaGPUDynamicDisplaySwitching = 0x00040000,
AMDSmartShiftMode = 0x00050001,
AMDSkinTemperatureTracking = 0x00050002,
SupportedPowerModes = 0x00070000,
LegionZoneSupportVersion = 0x00090000,
GodModeFnQSwitchable = 0x00100000,
OverDrive = 0x001A0000,
AIChip = 0x000E0000,
IGPUModeChangeStatus = 0x000F0000,
CPUShortTermPowerLimit = 0x0101FF00,
CPULongTermPowerLimit = 0x0102FF00,
CPUPeakPowerLimit = 0x0103FF00,
CPUTemperatureLimit = 0x0104FF00,
APUsPPTPowerLimit = 0x0105FF00,
CPUCrossLoadingPowerLimit = 0x0106FF00,
CPUPL1Tau = 0x0107FF00,
GPUPowerBoost = 0x0201FF00,
GPUConfigurableTGP = 0x0202FF00,
GPUTemperatureLimit = 0x0203FF00,
GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline = 0x0204FF00,
GPUToCPUDynamicBoost = 0x020BFF00,
GPUStatus = 0x02070000,
GPUDidVid = 0x02090000,
InstantBootAc = 0x03010001,
InstantBootUsbPowerDelivery = 0x03010002,
FanFullSpeed = 0x04020000,
CpuCurrentFanSpeed = 0x04030001,
GpuCurrentFanSpeed = 0x04030002,
CpuCurrentTemperature = 0x05040000,
GpuCurrentTemperature = 0x05050000
}
[Flags]
public enum DriverKey
{
FnF10 = 32,
FnF4 = 256,
FnF8 = 8192,
FnSpace = 4096,
}
public enum FanTableType
{
Unknown,
CPU,
CPUSensor,
GPU,
GPU2
}
public enum FlipToStartState
{
[Display(ResourceType = typeof(Resource), Name = "FlipToStartState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "FlipToStartState_On")]
On
}
public enum FnLockState
{
[Display(ResourceType = typeof(Resource), Name = "FnLockState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "FnLockState_On")]
On
}
public enum GPUState
{
Unknown,
NvidiaGpuNotFound,
MonitorConnected,
Active,
Inactive,
PoweredOff
}
public enum GSyncState
{
Off,
On
}
public enum HDRState
{
[Display(ResourceType = typeof(Resource), Name = "HDRState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "HDRState_On")]
On
}
public enum HybridModeState
{
[Display(ResourceType = typeof(Resource), Name = "HybridModeState_On")]
On,
[Display(ResourceType = typeof(Resource), Name = "HybridModeState_OnIGPUOnly")]
OnIGPUOnly,
[Display(ResourceType = typeof(Resource), Name = "HybridModeState_OnAuto")]
OnAuto,
[Display(ResourceType = typeof(Resource), Name = "HybridModeState_Off")]
Off
}
public enum IGPUModeState
{
Default,
IGPUOnly,
Auto
}
public enum InstantBootState
{
[Display(ResourceType = typeof(Resource), Name = "InstantBootState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "InstantBootState_AcAdapter")]
AcAdapter,
[Display(ResourceType = typeof(Resource), Name = "InstantBootState_UsbPowerDelivery")]
UsbPowerDelivery,
[Display(ResourceType = typeof(Resource), Name = "InstantBootState_AcAdapterAndUsbPowerDelivery")]
AcAdapterAndUsbPowerDelivery
}
public enum KeyboardLayout
{
Ansi,
Iso,
Jis
}
public enum KnownFolder
{
Contacts,
Downloads,
Favorites,
Links,
SavedGames,
SavedSearches
}
public enum LightingChangeState
{
Panel = 0,
Ports = 1,
}
public enum MicrophoneState
{
[Display(ResourceType = typeof(Resource), Name = "MicrophoneState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "MicrophoneState_On")]
On
}
[Flags]
public enum ModifierKey
{
None = 0,
[Display(ResourceType = typeof(Resource), Name = "ModifierKey_Shift")]
Shift = 1,
[Display(ResourceType = typeof(Resource), Name = "ModifierKey_Ctrl")]
Ctrl = 2,
[Display(ResourceType = typeof(Resource), Name = "ModifierKey_Alt")]
Alt = 4
}
public enum NativeWindowsMessage
{
LidOpened,
LidClosed,
MonitorOn,
MonitorOff,
DeviceConnected,
DeviceDisconnected,
MonitorConnected,
MonitorDisconnected,
ExternalMonitorConnected,
ExternalMonitorDisconnected,
OnDisplayDeviceArrival,
BatterySaverEnabled
}
public enum NotificationDuration
{
[Display(ResourceType = typeof(Resource), Name = "NotificationDuration_Short")]
Short,
[Display(ResourceType = typeof(Resource), Name = "NotificationDuration_Normal")]
Normal,
[Display(ResourceType = typeof(Resource), Name = "NotificationDuration_Long")]
Long
}
public enum NotificationType
{
ACAdapterConnected,
ACAdapterConnectedLowWattage,
ACAdapterDisconnected,
AutomationNotification,
CameraOn,
CameraOff,
CapsLockOn,
CapsLockOff,
FnLockOn,
FnLockOff,
MicrophoneOff,
MicrophoneOn,
NumLockOn,
NumLockOff,
PanelLogoLightingOn,
PanelLogoLightingOff,
PortLightingOn,
PortLightingOff,
PowerModeQuiet,
PowerModeBalance,
PowerModePerformance,
PowerModeGodMode,
RefreshRate,
RGBKeyboardBacklightChanged,
RGBKeyboardBacklightOff,
SmartKeyDoublePress,
SmartKeySinglePress,
SpectrumBacklightChanged,
SpectrumBacklightOff,
SpectrumBacklightPresetChanged,
TouchpadOn,
TouchpadOff,
UpdateAvailable,
WhiteKeyboardBacklightChanged,
WhiteKeyboardBacklightOff
}
public enum NotificationPosition
{
[Display(ResourceType = typeof(Resource), Name = "NotificationPosition_BottomRight")]
BottomRight,
[Display(ResourceType = typeof(Resource), Name = "NotificationPosition_BottomCenter")]
BottomCenter,
[Display(ResourceType = typeof(Resource), Name = "NotificationPosition_BottomLeft")]
BottomLeft,
[Display(ResourceType = typeof(Resource), Name = "NotificationPosition_CenterLeft")]
CenterLeft,
[Display(ResourceType = typeof(Resource), Name = "NotificationPosition_TopLeft")]
TopLeft,
[Display(ResourceType = typeof(Resource), Name = "NotificationPosition_TopCenter")]
TopCenter,
[Display(ResourceType = typeof(Resource), Name = "NotificationPosition_TopRight")]
TopRight,
[Display(ResourceType = typeof(Resource), Name = "NotificationPosition_CenterRight")]
CenterRight,
[Display(ResourceType = typeof(Resource), Name = "NotificationPosition_Center")]
Center
}
public enum OneLevelWhiteKeyboardBacklightState
{
[Display(ResourceType = typeof(Resource), Name = "OneLevelWhiteKeyboardBacklightState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "OneLevelWhiteKeyboardBacklightState_On")]
On
}
public enum OS
{
[Display(Name = "Windows 11")]
Windows11,
[Display(Name = "Windows 10")]
Windows10,
[Display(Name = "Windows 8")]
Windows8,
[Display(Name = "Windows 7")]
Windows7
}
public enum OverDriveState
{
[Display(ResourceType = typeof(Resource), Name = "OverdriveState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "OverdriveState_On")]
On
}
public enum PanelLogoBacklightState
{
[Display(ResourceType = typeof(Resource), Name = "PanelLogoBacklightState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "PanelLogoBacklightState_On")]
On
}
public enum PortsBacklightState
{
[Display(ResourceType = typeof(Resource), Name = "PortsBacklightState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "PortsBacklightState_On")]
On
}
public enum PowerAdapterStatus
{
Connected,
ConnectedLowWattage,
Disconnected
}
public enum PowerModeMappingMode
{
[Display(ResourceType = typeof(Resource), Name = "PowerModeMappingMode_Disabled")]
Disabled,
[Display(ResourceType = typeof(Resource), Name = "PowerModeMappingMode_WindowsPowerMode")]
WindowsPowerMode,
[Display(ResourceType = typeof(Resource), Name = "PowerModeMappingMode_WindowsPowerPlan")]
WindowsPowerPlan,
}
public enum PowerModeState
{
[Display(ResourceType = typeof(Resource), Name = "PowerModeState_Quiet")]
Quiet,
[Display(ResourceType = typeof(Resource), Name = "PowerModeState_Balance")]
Balance,
[Display(ResourceType = typeof(Resource), Name = "PowerModeState_Performance")]
Performance,
[Display(ResourceType = typeof(Resource), Name = "PowerModeState_GodMode")]
GodMode = 254
}
public enum PowerStateEvent
{
Unknown = -1,
StatusChange,
Suspend,
Resume,
}
public enum ProcessEventInfoType
{
Started,
Stopped
}
public enum RebootType
{
NotRequired = 0,
Forced = 1,
Requested = 3,
ForcedPowerOff = 4,
Delayed = 5
}
public enum RGBKeyboardBacklightChanged;
public enum RGBKeyboardBacklightBrightness
{
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightBrightness_Low")]
Low,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightBrightness_High")]
High
}
public enum RGBKeyboardBacklightEffect
{
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightEffect_Static")]
Static,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightEffect_Breath")]
Breath,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightEffect_Smooth")]
Smooth,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightEffect_WaveRTL")]
WaveRTL,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightEffect_WaveLTR")]
WaveLTR
}
public enum RGBKeyboardBacklightPreset
{
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightPreset_Off")]
Off = -1,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightPreset_One")]
One = 0,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightPreset_Two")]
Two = 1,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightPreset_Three")]
Three = 2,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightPreset_Four")]
Four = 3
}
public enum RGBKeyboardBacklightSpeed
{
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightSpeed_Slowest")]
Slowest,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightSpeed_Slow")]
Slow,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightSpeed_Fast")]
Fast,
[Display(ResourceType = typeof(Resource), Name = "RGBKeyboardBacklightSpeed_Fastest")]
Fastest
}
public enum SpeakerState
{
[Display(ResourceType = typeof(Resource), Name = "SpeakerState_Mute")]
Mute,
[Display(ResourceType = typeof(Resource), Name = "SpeakerState_Unmute")]
Unmute
}
public enum SoftwareStatus
{
Enabled,
Disabled,
NotFound
}
public enum SpecialKey
{
FnF9 = 1,
FnLockOn = 2,
FnLockOff = 3,
FnPrtSc = 4,
FnPrtSc2 = 45,
CameraOn = 12,
CameraOff = 13,
FnR = 16,
FnR2 = 0x0041002A,
SpectrumBacklightOff = 24,
SpectrumBacklight1 = 25,
SpectrumBacklight2 = 26,
SpectrumBacklight3 = 38,
SpectrumPreset1 = 32,
SpectrumPreset2 = 33,
SpectrumPreset3 = 34,
SpectrumPreset4 = 35,
SpectrumPreset5 = 36,
SpectrumPreset6 = 37,
FnN = 42,
FnF4 = 62,
FnF8 = 63,
WhiteBacklightOff = 64,
WhiteBacklight1 = 65,
WhiteBacklight2 = 66
}
public enum SpectrumKeyboardBacklightBrightness
{
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightBrightness_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightBrightness_Low")]
Low,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightBrightness_Medium")]
Medium,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightBrightness_High")]
High
}
public enum SpectrumKeyboardBacklightClockwiseDirection
{
None,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightDirection_Clockwise")]
Clockwise,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightDirection_CounterClockwise")]
CounterClockwise
}
public enum SpectrumKeyboardBacklightDirection
{
None,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightDirection_BottomToTop")]
BottomToTop,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightDirection_TopToBottom")]
TopToBottom,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightDirection_LeftToRight")]
LeftToRight,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightDirection_RightToLeft")]
RightToLeft
}
public enum SpectrumKeyboardBacklightEffectType
{
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_Always")]
Always,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_RainbowScrew")]
RainbowScrew,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_RainbowWave")]
RainbowWave,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_ColorChange")]
ColorChange,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_ColorWave")]
ColorWave,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_ColorPulse")]
ColorPulse,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_Smooth")]
Smooth,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_Rain")]
Rain,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_Ripple")]
Ripple,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_Type")]
Type,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_AudioBounce")]
AudioBounce,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_AudioRipple")]
AudioRipple,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightEffectType_AuroraSync")]
AuroraSync
}
public enum SpectrumKeyboardBacklightSpeed
{
None,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightSpeed_Speed1")]
Speed1,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightSpeed_Speed2")]
Speed2,
[Display(ResourceType = typeof(Resource), Name = "SpectrumKeyboardBacklightSpeed_Speed3")]
Speed3
}
public enum SpectrumLayout
{
KeyboardOnly,
KeyboardAndFront,
Full,
FullAlternative
}
public enum Theme
{
[Display(ResourceType = typeof(Resource), Name = "Theme_System")]
System,
[Display(ResourceType = typeof(Resource), Name = "Theme_Light")]
Light,
[Display(ResourceType = typeof(Resource), Name = "Theme_Dark")]
Dark
}
public enum AccentColorSource
{
[Display(ResourceType = typeof(Resource), Name = "AccentColorSource_System")]
System,
[Display(ResourceType = typeof(Resource), Name = "AccentColorSource_Custom")]
Custom
}
public enum TemperatureUnit
{
C,
F
}
public enum ThermalModeState
{
Unknown,
Quiet,
Balance,
Performance,
GodMode = 255
}
public enum TouchpadLockState
{
[Display(ResourceType = typeof(Resource), Name = "TouchpadLockState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "TouchpadLockState_On")]
On
}
public enum UpdateCheckFrequency
{
[Display(ResourceType = typeof(Resource), Name = "UpdateCheckFrequency_PerHour")]
PerHour,
[Display(ResourceType = typeof(Resource), Name = "UpdateCheckFrequency_PerThreeHours")]
PerThreeHours,
[Display(ResourceType = typeof(Resource), Name = "UpdateCheckFrequency_PerTwelveHours")]
PerTwelveHours,
[Display(ResourceType = typeof(Resource), Name = "UpdateCheckFrequency_PerDay")]
PerDay,
[Display(ResourceType = typeof(Resource), Name = "UpdateCheckFrequency_PerWeek")]
PerWeek,
[Display(ResourceType = typeof(Resource), Name = "UpdateCheckFrequency_PerMonth")]
PerMonth
}
public enum UpdateCheckStatus
{
Success,
RateLimitReached,
Error
}
public enum WhiteKeyboardBacklightState
{
[Display(ResourceType = typeof(Resource), Name = "WhiteKeyboardBacklightState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "WhiteKeyboardBacklightState_Low")]
Low,
[Display(ResourceType = typeof(Resource), Name = "WhiteKeyboardBacklightState_High")]
High
}
public enum WindowsPowerMode
{
[Display(Name = "Best power efficiency")]
BestPowerEfficiency,
[Display(Name = "Balanced")]
Balanced,
[Display(Name = "Best performance")]
BestPerformance
}
public enum WinKeyState
{
[Display(ResourceType = typeof(Resource), Name = "WinKeyState_Off")]
Off,
[Display(ResourceType = typeof(Resource), Name = "WinKeyState_On")]
On
}
public enum WinKeyChanged;
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/AssemblyExtensions.cs
================================================
using System;
using System.Globalization;
using System.Reflection;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class AssemblyExtensions
{
public static DateTime? GetBuildDateTime(this Assembly assembly)
{
const string buildVersionMetadataPrefix = "+build";
var attribute = assembly.GetCustomAttribute();
if (attribute?.InformationalVersion is null)
return null;
var value = attribute.InformationalVersion;
var index = value.IndexOf(buildVersionMetadataPrefix, StringComparison.InvariantCultureIgnoreCase);
if (index <= 0)
return null;
value = value[(index + buildVersionMetadataPrefix.Length)..];
// ReSharper disable once StringLiteralTypo
if (DateTime.TryParseExact(value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var result))
return result;
return null;
}
public static string? GetBuildDateTimeString(this Assembly assembly)
{
// ReSharper disable once StringLiteralTypo
return GetBuildDateTime(assembly)?.ToString("yyyyMMddHHmmss");
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/ContainerBuilderExtensions.cs
================================================
using Autofac;
using Autofac.Builder;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class ContainerBuilderExtensions
{
public static IRegistrationBuilder Register(this ContainerBuilder cb, bool selfOnly = false) where T : notnull
{
var registration = cb.RegisterType().AsSelf();
if (!selfOnly)
registration = registration.AsImplementedInterfaces();
return registration.SingleInstance();
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/DateTimeExtensions.cs
================================================
using System;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class DateTimeExtensions
{
public static DateTime UtcFrom(int hours, int minutes)
{
var now = DateTime.UtcNow;
return new(now.Year, now.Month, now.Day, hours, minutes, 0, DateTimeKind.Utc);
}
public static DateTime LocalFrom(int hours, int minutes)
{
var now = DateTime.Now;
return new(now.Year, now.Month, now.Day, hours, minutes, 0, DateTimeKind.Local);
}
public static DateTime UtcDayFrom(DayOfWeek targetDay, int hours, int minutes)
{
var now = DateTime.UtcNow;
var date = new DateTime(now.Year, now.Month, now.Day, hours, minutes, now.Second, DateTimeKind.Utc);
var daysUntilDayOfWeek = ((int)targetDay - (int)date.DayOfWeek + 7) % 7;
return date.AddDays(daysUntilDayOfWeek);
}
public static DateTime LocalDayFrom(DayOfWeek targetDay, int hours, int minutes)
{
var now = DateTime.Now;
var date = new DateTime(now.Year, now.Month, now.Day, hours, minutes, now.Second, DateTimeKind.Local);
var daysUntilDayOfWeek = ((int)targetDay - (int)date.DayOfWeek + 7) % 7;
return date.AddDays(daysUntilDayOfWeek);
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/DictionaryExtensions.cs
================================================
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class DictionaryExtensions
{
public static ReadOnlyDictionary AsReadOnlyDictionary(this IDictionary source) where TKey : notnull
{
return new ReadOnlyDictionary(source);
}
public static void AddRange(this IDictionary source, IDictionary items)
{
foreach (var keyValuePair in items)
source.Add(keyValuePair.Key, keyValuePair.Value);
}
public static TValue? GetValueOrNull(this IReadOnlyDictionary dictionary, TKey key) where TValue : struct
{
return !dictionary.TryGetValue(key, out var obj) ? null : obj;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/DisplayExtensions.cs
================================================
using System.Linq;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Devices.Display;
using WindowsDisplayAPI;
using WindowsDisplayAPI.DisplayConfig;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class DisplayExtensions
{
public static void SetSettingsUsingPathInfo(this Display display, DisplaySetting displaySetting)
{
// Use display path APIs to change internal display resolution & refresh rate.
// Compared to Display.SetSettings(), these APIs can change the Active Signal Mode and not just the Desktop mode.
// Setting 60Hz will change the Active Signal Mode to 60Hz instead of leaving it at the max refresh rate,
// which lets the display consume less power for more battery life.
var displaySource = display.ToPathDisplaySource();
var pathInfos = PathInfo.GetActivePaths();
for (var i = 0; i < pathInfos.Length; i++)
{
var pathInfo = pathInfos[i];
if (pathInfo.DisplaySource == displaySource)
{
var targetsInfo = pathInfo.TargetsInfo;
var pathTargetInfos = targetsInfo
.Select(targetInfo => new PathTargetInfo(targetInfo.DisplayTarget,
new PathTargetSignalInfo(displaySetting, displaySetting.Resolution),
targetInfo.Rotation,
targetInfo.Scaling))
.ToArray();
pathInfos[i] = new PathInfo(
pathInfo.DisplaySource,
pathInfo.Position,
displaySetting.Resolution,
pathInfo.PixelFormat,
pathTargetInfos
);
}
}
PathInfo.ApplyPathInfos(pathInfos);
}
public static DisplayAdvancedColorInfo GetAdvancedColorInfo(this Display display)
{
var pathDisplayAdapter = display.Adapter.ToPathDisplayAdapter();
var pathDisplayTarget = display.ToPathDisplayTarget();
if (pathDisplayTarget is null || pathDisplayAdapter is null)
return default;
var getAdvancedColorInfo = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
getAdvancedColorInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
getAdvancedColorInfo.header.size = (uint)Marshal.SizeOf(typeof(DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO));
getAdvancedColorInfo.header.adapterId.HighPart = pathDisplayAdapter.AdapterId.HighPart;
getAdvancedColorInfo.header.adapterId.LowPart = pathDisplayAdapter.AdapterId.LowPart;
getAdvancedColorInfo.header.id = pathDisplayTarget.TargetId;
if (PInvoke.DisplayConfigGetDeviceInfo(ref getAdvancedColorInfo.header) != 0)
PInvokeExtensions.ThrowIfWin32Error("GetAdvancedColorInfo");
return new(getAdvancedColorInfo.Anonymous.value.GetNthBit(0),
getAdvancedColorInfo.Anonymous.value.GetNthBit(1),
getAdvancedColorInfo.Anonymous.value.GetNthBit(2),
getAdvancedColorInfo.Anonymous.value.GetNthBit(3));
}
public static void SetAdvancedColorState(this Display display, bool state)
{
var pathDisplayAdapter = display.Adapter.ToPathDisplayAdapter();
var pathDisplayTarget = display.ToPathDisplayTarget();
if (pathDisplayTarget is null || pathDisplayAdapter is null)
return;
var setAdvancedColorState = new DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE();
setAdvancedColorState.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE;
setAdvancedColorState.header.size = (uint)Marshal.SizeOf();
setAdvancedColorState.header.adapterId.HighPart = pathDisplayAdapter.AdapterId.HighPart;
setAdvancedColorState.header.adapterId.LowPart = pathDisplayAdapter.AdapterId.LowPart;
setAdvancedColorState.header.id = pathDisplayTarget.TargetId;
setAdvancedColorState.Anonymous.value = setAdvancedColorState.Anonymous.value.SetNthBit(0, state);
if (PInvoke.DisplayConfigSetDeviceInfo(setAdvancedColorState.header) != 0)
PInvokeExtensions.ThrowIfWin32Error("SetAdvancedColorState");
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/DisplayPossibleSettingExtensions.cs
================================================
using System;
using WindowsDisplayAPI;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class DisplayPossibleSettingExtensions
{
public static bool IsTooSmall(this DisplayPossibleSetting dps) => Math.Max(dps.Resolution.Width, dps.Resolution.Height) < 1000;
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/DisplaySettingExtensions.cs
================================================
using WindowsDisplayAPI;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class DisplaySettingExtensions
{
public static string ToExtendedString(this DisplaySetting displaySetting)
{
return $"{displaySetting.Resolution.Width}x{displaySetting.Resolution.Height}{(displaySetting.IsInterlaced ? "i" : "p")} @ {displaySetting.Frequency}Hz @ {displaySetting.ColorDepth} ({displaySetting.Position}, {displaySetting.Orientation}, {displaySetting.OutputScalingMode})";
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/EnumExtensions.cs
================================================
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class EnumExtensions
{
public static string GetDisplayName(this Enum enumValue)
{
var displayAttribute = enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttributes(false)
.OfType()
.FirstOrDefault();
if (displayAttribute?.Name is null)
return enumValue.ToString();
if (displayAttribute.ResourceType?.GetProperty(displayAttribute.Name, BindingFlags.Static | BindingFlags.Public)?.GetValue(null) is string str)
return str;
return displayAttribute.Name;
}
public static string GetFlagsDisplayName(this Enum enumValue, Enum? excluding = null)
{
var values = Enum.GetValues(enumValue.GetType()).Cast();
if (excluding is not null)
values = values.Where(v => !v.Equals(excluding));
var names = values.Where(enumValue.HasFlag).Select(GetDisplayName);
return string.Join(", ", names);
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/EnumerableExtensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class EnumerableExtensions
{
public static bool IsEmpty(this IEnumerable source)
{
if (source is ICollection collection)
return collection.Count == 0;
return !source.Any();
}
public static void ForEach(this IEnumerable enumeration, Action action)
{
foreach (var item in enumeration)
action(item);
}
public static IEnumerable> Split(this IEnumerable source, int size)
{
var enumerable = source as T[] ?? source.ToArray();
return enumerable
.Select((_, i) => enumerable.Skip(i * size).Take(size))
.Where(a => a.Any());
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/HttpClientExtensions.cs
================================================
using System;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class HttpClientExtensions
{
public static async Task DownloadAsync(this HttpClient client, string requestUri, Stream destination, IProgress? progress = null, CancellationToken cancellationToken = default)
{
using var response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var contentLength = response.Content.Headers.ContentLength;
await using var download = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
if (progress is null || !contentLength.HasValue)
{
await download.CopyToAsync(destination, cancellationToken).ConfigureAwait(false);
return;
}
progress.Report(0);
var relativeProgress = new Progress(totalBytes => progress.Report((float)totalBytes / contentLength.Value));
await download.CopyToAsync(destination, 81920, relativeProgress, cancellationToken).ConfigureAwait(false);
progress.Report(1);
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/IntExtensions.cs
================================================
namespace LenovoLegionToolkit.Lib.Extensions;
public static class IntExtensions
{
public static bool IsBitSet(this int value, int position) => (value & (1 << position)) != 0;
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/ListExtensions.cs
================================================
using System.Collections;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class ListExtensions
{
public static object[] ToArray(this IList source)
{
var array = new object[source.Count];
source.CopyTo(array, 0);
return array;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/LogoInfoFormatExtensions.cs
================================================
using System.Collections.Generic;
using System.Drawing.Imaging;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class LogoInfoFormatExtensions
{
public static IEnumerable ImageFormats(this BootLogoFormat format)
{
if (format.HasFlag(BootLogoFormat.Bmp))
yield return ImageFormat.Bmp;
if (format.HasFlag(BootLogoFormat.Jpeg))
yield return ImageFormat.Jpeg;
if (format.HasFlag(BootLogoFormat.Png))
yield return ImageFormat.Png;
}
public static IEnumerable ExtensionFilters(this BootLogoFormat format)
{
if (format.HasFlag(BootLogoFormat.Bmp))
yield return "*.bmp";
if (format.HasFlag(BootLogoFormat.Png))
yield return "*.png";
if (format.HasFlag(BootLogoFormat.Jpeg))
{
yield return "*.jpeg";
yield return "*.jpg";
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/ManagementObjectSearcherExtensions.cs
================================================
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Threading.Tasks;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class ManagementObjectSearcherExtensions
{
public static Task> GetAsync(this ManagementObjectSearcher mos) => Task.Run(() => mos.Get().Cast());
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/MathExtensions.cs
================================================
using System;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class MathExtensions
{
public static int RoundNearest(int value, int factor)
{
return (int)Math.Round(value / (double)factor, MidpointRounding.AwayFromZero) * factor;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/OSExtensions.cs
================================================
using System;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class OSExtensions
{
public static OS GetCurrent()
{
var os = Environment.OSVersion;
if (os.Version >= new Version(10, 0, 22000, 0)) // Windows 11
return OS.Windows11;
else if (os.Version >= new Version(10, 0, 0, 0)) // Windows 10
return OS.Windows10;
else if (os.Version >= new Version(6, 2, 0, 0)) // Windows 8
return OS.Windows8;
else if (os.Version >= new Version(6, 1, 0, 0)) // Windows 7
return OS.Windows7;
else
return OS.Windows11;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/PInvokeExtensions.cs
================================================
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using Windows.Win32;
namespace LenovoLegionToolkit.Lib.Extensions;
// ReSharper disable InconsistentNaming
// ReSharper disable IdentifierTypo
public static class PInvokeExtensions
{
public enum CONSOLE_DISPLAY_STATE
{
Off = 0,
On = 1,
Dimmed = 2
}
public const int ERROR_SUCCESS = 0;
public const int ERROR_NO_MORE_ITEMS = 259;
public const uint KF_FLAG_DEFAULT = 0;
public const uint VARIABLE_ATTRIBUTE_BOOTSERVICE_ACCESS = 2;
public const uint VARIABLE_ATTRIBUTE_NON_VOLATILE = 1;
public const uint VARIABLE_ATTRIBUTE_RUNTIME_ACCESS = 7;
public static readonly Guid DISPLAY_BRIGTHNESS_SETTING_GUID = Guid.Parse("aded5e82-b909-4619-9949-f5d71dac0bcb");
public static unsafe bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, TIn inVal, out TOut outVal) where TIn : struct where TOut : struct
{
var lpInBuffer = IntPtr.Zero;
var lpOutBuffer = IntPtr.Zero;
try
{
var nInBufferSize = Marshal.SizeOf();
var nOutBufferSize = Marshal.SizeOf();
lpInBuffer = Marshal.AllocHGlobal(nInBufferSize);
lpOutBuffer = Marshal.AllocHGlobal(nOutBufferSize);
Marshal.StructureToPtr(inVal, lpInBuffer, false);
var ret = PInvoke.DeviceIoControl(hDevice,
dwIoControlCode,
lpInBuffer.ToPointer(),
(uint)nInBufferSize,
lpOutBuffer.ToPointer(),
(uint)nOutBufferSize,
null,
null);
outVal = ret ? Marshal.PtrToStructure(lpOutBuffer) : default;
return ret;
}
finally
{
Marshal.FreeHGlobal(lpInBuffer);
Marshal.FreeHGlobal(lpOutBuffer);
}
}
public static void ThrowIfWin32Error(string description)
{
var errorCode = Marshal.GetLastWin32Error();
ThrowIfWin32Error(errorCode, description);
}
public static void ThrowIfWin32Error(int errorCode, string description)
{
if (errorCode != 0)
throw Marshal.GetExceptionForHR(errorCode) ?? throw new Exception($"Unknown Win32 error code {errorCode} in {description}");
throw new Exception($"{description} failed but Win32 didn't catch an error");
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/PhyscialGPUExtensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using NvAPIWrapper.GPU;
using NvAPIWrapper.Native;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class NVAPIExtensions
{
private static readonly string[] Exclusions =
[
"dwm.exe",
"explorer.exe",
];
public static List GetActiveProcesses(PhysicalGPU gpu)
{
var processes = new List();
var apps = GPUApi.QueryActiveApps(gpu.Handle).Where(app => !Exclusions.Contains(app.ProcessName, StringComparer.InvariantCultureIgnoreCase));
foreach (var app in apps)
{
try
{
var process = Process.GetProcessById(app.ProcessId);
processes.Add(process);
}
catch (ArgumentException) { }
}
return processes;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/ProcessExtensions.cs
================================================
using System.Diagnostics;
using Windows.Win32;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class ProcessExtensions
{
public static string? GetFileName(this Process process, int maxLength = 512)
{
var chars = new char[maxLength];
return PInvoke.K32GetModuleFileNameEx(process.SafeHandle, null, chars) == 0
? null
: chars.ToString();
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/PropertyDataCollectionExtensions.cs
================================================
using System.Management;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class PropertyDataCollectionExtensions
{
public static bool Contains(this PropertyDataCollection pdc, string name)
{
// ReSharper disable once NotDisposedResource
var enumerator = pdc.GetEnumerator();
while (enumerator.MoveNext())
if (enumerator.Current.Name == name)
return true;
return false;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/RGBKeyboardBacklightPresetExtensions.cs
================================================
namespace LenovoLegionToolkit.Lib.Extensions;
public static class RGBKeyboardBacklightPresetExtensions
{
public static RGBKeyboardBacklightPreset Next(this RGBKeyboardBacklightPreset preset) => preset switch
{
RGBKeyboardBacklightPreset.Off => RGBKeyboardBacklightPreset.One,
RGBKeyboardBacklightPreset.One => RGBKeyboardBacklightPreset.Two,
RGBKeyboardBacklightPreset.Two => RGBKeyboardBacklightPreset.Three,
RGBKeyboardBacklightPreset.Three => RGBKeyboardBacklightPreset.Four,
_ => RGBKeyboardBacklightPreset.Off,
};
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/RegistrationBuilderExtensions.cs
================================================
using System;
using Autofac;
using Autofac.Builder;
using LenovoLegionToolkit.Lib.Listeners;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class RegistrationBuilderExtensions
{
public static void AutoActivateListener(this IRegistrationBuilder, ConcreteReflectionActivatorData, SingleRegistrationStyle> registration) where T : EventArgs
{
registration.OnActivating(e => e.Instance.StartAsync().AsValueTask()).AutoActivate();
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/ServiceControllerExtension.cs
================================================
using System.Runtime.InteropServices;
using System.ServiceProcess;
using Windows.Win32;
using Windows.Win32.System.Services;
namespace LenovoLegionToolkit.Lib.Extensions;
internal static class ServiceControllerExtension
{
public static unsafe void ChangeStartMode(this ServiceController svc, bool enabled)
{
using var scManagerHandle = PInvoke.OpenSCManager(null as string, null, PInvoke.SC_MANAGER_ALL_ACCESS);
if (scManagerHandle.IsInvalid)
throw new ExternalException("Open Service Manager Error");
using var serviceHandle = PInvoke.OpenService(scManagerHandle, svc.ServiceName, PInvoke.SERVICE_CHANGE_CONFIG);
if (serviceHandle.IsInvalid)
throw new ExternalException("Open Service Error");
var result = PInvoke.ChangeServiceConfig(serviceHandle,
(ENUM_SERVICE_TYPE)PInvoke.SERVICE_NO_CHANGE,
enabled ? SERVICE_START_TYPE.SERVICE_AUTO_START : SERVICE_START_TYPE.SERVICE_DISABLED,
SERVICE_ERROR.SERVICE_ERROR_NORMAL,
null,
null,
null,
null,
null,
null,
null);
if (result)
return;
PInvokeExtensions.ThrowIfWin32Error($"Could not change service: {svc.ServiceName}");
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/SpectrumKeyboardBacklightEffectTypeExtensions.cs
================================================
namespace LenovoLegionToolkit.Lib.Extensions;
public static class SpectrumKeyboardBacklightEffectTypeExtensions
{
public static bool IsAllLightsEffect(this SpectrumKeyboardBacklightEffectType type) => type switch
{
SpectrumKeyboardBacklightEffectType.AudioBounce => true,
SpectrumKeyboardBacklightEffectType.AudioRipple => true,
SpectrumKeyboardBacklightEffectType.AuroraSync => true,
_ => false
};
public static bool IsWholeKeyboardEffect(this SpectrumKeyboardBacklightEffectType type) => type switch
{
SpectrumKeyboardBacklightEffectType.Type => true,
SpectrumKeyboardBacklightEffectType.Ripple => true,
_ => false
};
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/StreamExtensions.cs
================================================
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace LenovoLegionToolkit.Lib.Extensions;
// ReSharper disable LocalizableElement
public static class StreamExtensions
{
public static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress? progress = null, CancellationToken cancellationToken = default)
{
if (!source.CanRead)
throw new ArgumentException("Has to be readable", nameof(source));
if (!destination.CanWrite)
throw new ArgumentException("Has to be writable", nameof(destination));
var buffer = new byte[bufferSize];
long totalBytesRead = 0;
int bytesRead;
while ((bytesRead = await source.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) != 0)
{
await destination.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false);
totalBytesRead += bytesRead;
progress?.Report(totalBytesRead);
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/StringExtensions.cs
================================================
using System;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class StringExtensions
{
public static string GetUntilOrEmpty(this string text, string stopAt)
{
if (string.IsNullOrWhiteSpace(text))
return string.Empty;
var charLocation = text.IndexOf(stopAt, StringComparison.Ordinal);
if (charLocation > 0)
return text[..charLocation];
return string.Empty;
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/TaskExtensions.cs
================================================
using System.Threading.Tasks;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class TaskExtensions
{
public static ValueTask AsValueTask(this Task task) => new(task);
public static Task OrNullIfException(this Task task) where T : struct
{
return task.ContinueWith(t => t.IsCompletedSuccessfully ? (T?)t.Result : null);
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/TimeExtensions.cs
================================================
using System;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class TimeExtensions
{
public static Time UtcNow
{
get
{
var utcNow = DateTime.UtcNow;
return new(utcNow.Hour, utcNow.Minute);
}
}
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/UintExtensions.cs
================================================
using System;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class UintExtensions
{
public static uint ReverseEndianness(this uint state)
{
var bytes = BitConverter.GetBytes(state);
Array.Reverse(bytes, 0, bytes.Length);
return BitConverter.ToUInt32(bytes, 0);
}
public static bool GetNthBit(this uint num, int n) => (num & (1 << n)) != 0;
public static uint SetNthBit(this uint num, int n, bool state) => state ? num | (1U << n) : num & ~(1U << n);
}
================================================
FILE: LenovoLegionToolkit.Lib/Extensions/VersionExtensions.cs
================================================
using System;
namespace LenovoLegionToolkit.Lib.Extensions;
public static class VersionExtensions
{
public static bool IsBeta(this Version version) => version switch
{
{ Major: 0, Minor: 0, Build: 1, Revision: 0 } => true,
{ Build: 99 } => true,
_ => false
};
}
================================================
FILE: LenovoLegionToolkit.Lib/Features/AbstractCapabilityFeature.cs
================================================
using System;
using System.Threading.Tasks;
using LenovoLegionToolkit.Lib.System.Management;
using LenovoLegionToolkit.Lib.Utils;
namespace LenovoLegionToolkit.Lib.Features;
public abstract class AbstractCapabilityFeature(CapabilityID capabilityID)
: IFeature where T : struct, Enum, IComparable, IConvertible
{
public async Task IsSupportedAsync()
{
try
{
var mi = await Compatibility.GetMachineInformationAsync().ConfigureAwait(false);
return mi.Features.Source == MachineInformation.FeatureData.SourceType.CapabilityData && mi.Features[capabilityID];
}
catch
{
return false;
}
}
public Task GetAllStatesAsync() => Task.FromResult(Enum.GetValues());
public async Task