在 Windows 11 中使用支持 HDR 的显示器时,我们可以使用“设置”>“系统”>“显示”>“HDR”中的“SDR 内容亮度”滑块来控制屏幕上常规非 HDR 元素的亮度。
例如如果显示器的最大亮度为 400nit,并且滑块设置为 60%,则 SDR 内容将以 240nit 亮度显示。
Windows 10 也有类似的东西。
我希望能够以编程方式更改滑块的值,这样我就可以在白天拥有更亮的桌面,在晚上拥有更暗的桌面。
通过 WMI 或 DDC/CI 更改亮度的“旧”方法不适用于启用 HDR 的显示器。
我使用 ProcessMonitor 来查看滑块的作用,但它生成了太多条目,我能看到的唯一相关位是它更改了注册表项
Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\MonitorDataStore\DELA1E4#G7IYMxgwAAgX_10_07E6_A1\SDRWhiteLevel
。
在我的显示屏上,值从 1000 (0%) 到 3500 (50%) 到 6000 (100%)(十进制),其中 1000 等于 80nit。
SystemSettings.exe 更改注册表值后,它会调用 D3D12 中的某些内容来实际应用更改。
翻遍微软关于Win32 API的文档,找不到任何相关信息。
有人知道如何让它工作吗?任何语言都可以,PowerShell、C#、C++、Python...
谢谢你。
经过一番挖掘,我发现了 SDR 亮度是如何设置的:
dwmapi.dll
有一个函数 HRESULT DwmpSDRToHDRBoost(HMONITOR monitor, double brightness)
,由序数 171
导出,其中 brightness
的范围可以是 1.0
- 6.0
。
设置应用程序还设置了您提到的注册表项,但是我没有找到任何引用该键的内容。
这是一个最小的例子:
#include <Windows.h>
using DwmpSDRToHDRBoostPtr = HRESULT(__stdcall *)(HMONITOR, double);
HMONITOR GetPrimaryMonitor(){
return MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
}
int main()
{
double brightness = 6.0;
HMODULE hmodule_dwmapi = LoadLibraryW(L"dwmapi.dll");
DwmpSDRToHDRBoostPtr DwmpSDRToHDRBoost = reinterpret_cast<DwmpSDRToHDRBoostPtr>(GetProcAddress(hmodule_dwmapi, MAKEINTRESOURCE(171)));
DwmpSDRToHDRBoost(GetPrimaryMonitor(), brightness);
}
请记住,这是未记录的 API,序数和行为将来可能会发生变化。
更新:
至少在最新的 Windows 11 内部预览中,使用
DwmpSdrToHdrBoost
设置 SDR 亮度不会再更新 Windows 设置中的滑块。 DisplayAdvancedColorInfo.SdrWhiteLevelInNits
报告的值也不会更新。他们可能将值缓存在某处或从注册表中读取。
这是我根据lulle2007200的答案制作的C#版本:
using System;
using System.Runtime.InteropServices;
namespace ScreenBrightnessSetter
{
class Program
{
[DllImport("user32.dll")]
static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
[DllImport("kernel32", CharSet = CharSet.Unicode)]
static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, int address);
private delegate void DwmpSDRToHDRBoostPtr(IntPtr monitor, double brightness);
static void Main(string[] args)
{
var primaryMonitor = MonitorFromWindow(IntPtr.Zero, 1);
var hmodule_dwmapi = LoadLibrary("dwmapi.dll");
DwmpSDRToHDRBoostPtr changeBrightness = Marshal.GetDelegateForFunctionPointer<DwmpSDRToHDRBoostPtr>(GetProcAddress(hmodule_dwmapi, 171));
double brightness = 1.0;
changeBrightness(primaryMonitor, brightness);
}
}
}