在 Windows 11 中以编程方式控制 SDR 内容亮度

问题描述 投票:0回答:2

在 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...

谢谢你。

windows brightness hdr
2个回答
5
投票

经过一番挖掘,我发现了 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
报告的值也不会更新。他们可能将值缓存在某处或从注册表中读取。


3
投票

这是我根据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);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.