Processing Ajax...

Title
Close Dialog

Message

Confirm
Close Dialog

Confirm
Close Dialog

Confirm
Close Dialog

User Image
overcookedTOFU
2 discussion posts
DisplayFusion does a great job with monitor profiles, but adding support for automatically adjusting monitor brightness would make it even better.

My home office is in a fairly bright room, so during the day, I often need to turn up the monitor brightness. Doing it for each of three monitors can be a pain. At night, the monitor brightness must be turned down again. If DisplayFusion supported DDC/CI monitor controls, I could set them all simultaneously with a single click or hotkey. Please consider implementing support for DDC/CI monitor brightness in the next version of DisplayFusion.

Thanks!
Apr 21, 2017  • #1
PabloMartinez's profile on WallpaperFusion.com
Yes, that would be great. Another option is to change the brightness by time of day as implemented in f.lux to change the color temperature. In the meantime, I can offer a script.

Code

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;

public static class DisplayFusionFunction
{
    public static void Run(IntPtr windowHandle)
    {
        Application.EnableVisualStyles();
        Application.Run(new MainForm(windowHandle));
    }
}

public class MainForm : Form
{
    private readonly BrightnessControl monitorControl;

    public MainForm(IntPtr hWnd)
    {
        AutoScaleMode = AutoScaleMode.Font;
        ClientSize = new Size(315, 140);
        StartPosition = FormStartPosition.CenterScreen;
        FormBorderStyle = FormBorderStyle.Fixed3D;
        MaximizeBox = false;
        MinimizeBox = false;
        Text = "DDC/CI Monitor Control";

        var butt = new Button
        {
            Location = new Point(230, 110),
            Size = new Size(75, 23),
            Text = "OK"
        };
        butt.Click += (s, e) => Dispose();
        Controls.Add(butt);

        monitorControl = new BrightnessControl(hWnd);
        var monitorCount = monitorControl.GetMonitors();
        for (var i = 0; i < monitorCount; ++i)
        {
            TrackBarBright(i);
            //Comment next line if you don't want to use Contrast
            TrackBarContrast(i);
        }
    }
    // Brightness
    private void TrackBarBright(int monitorNumber)
    {
        var mInfo = monitorControl.GetBrightnessCapabilities(monitorNumber);

        // Check monitor support DDC/CI
        if (mInfo.Current == -1)
        {
            BFS.Dialog.ShowMessageInfo("Error. One of your monitors does not support DDC/CI");
            return;
        }
        var trackBarB = new TrackBar
        {
            Name = "M" + monitorNumber,
            Location = new Point(5, 20),
            Size = new Size(300, 40),
            Minimum = mInfo.Minimum,
            Maximum = mInfo.Maximum,
            Value = mInfo.Current
        };
        var labelB = new Label
        {
            Location = new Point(10, 5),
            Size = new Size(60, 15),
            Text = "Brightness: "
        };
        var labelBValue = new Label
        {
            Location = new Point(70, 5),
            Size = new Size(25, 15),
            Text = trackBarB.Value.ToString()
        };
        trackBarB.ValueChanged += (s, e) =>
        {
            monitorNumber = int.Parse(trackBarB.Name.Substring(1));
            if (monitorControl == null) return;
            monitorControl.SetBrightness((short)trackBarB.Value, monitorNumber);
            labelBValue.Text = trackBarB.Value.ToString();
        };
        Controls.Add(labelB);
        Controls.Add(labelBValue);
        Controls.Add(trackBarB);
    }

    // Contrast
    private void TrackBarContrast(int monitorNumber)
    {
        var mInfo = monitorControl.GetContrastCapabilities(monitorNumber);
        var trackBarC = new TrackBar
        {
            Name = "M" + monitorNumber,
            Location = new Point(5, 80),
            Size = new Size(300, 40),
            Minimum = mInfo.Minimum,
            Maximum = mInfo.Maximum,
            Value = mInfo.Current
        };
        var labelC = new Label
        {
            Location = new Point(10, 65),
            Size = new Size(60, 15),
            Text = "Contrast: "
        };
        var labelCValue = new Label
        {
            Location = new Point(70, 65),
            Size = new Size(25, 15),
            Text = trackBarC.Value.ToString()
        };
        trackBarC.ValueChanged += (s, e) =>
        {
            monitorNumber = int.Parse(trackBarC.Name.Substring(1));
            if (monitorControl == null) return;
            monitorControl.SetContrast((short)trackBarC.Value, monitorNumber);
            labelCValue.Text = trackBarC.Value.ToString();
        };
        Controls.Add(labelC);
        Controls.Add(labelCValue);
        Controls.Add(trackBarC);
    }
}

public class BrightnessInfo
{
    public int Minimum { get; set; }
    public int Maximum { get; set; }
    public int Current { get; set; }
}

public static class NativeConstants
{
    public const int MonitorDefaultToNull = 0;
    public const int MonitorDefaultToPrimary = 1;
    public const int MonitorDefaultToNearest = 2;
}

public static class NativeStructures
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct PhysicalMonitor
    {
        public IntPtr hPhysicalMonitor;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string szPhysicalMonitorDescription;
    }
    public enum McDisplayTechnologyType
    {
        McShadowMaskCathodeRayTube,
        McApertureGrillCathodeRayTube,
        McThinFilmTransistor,
        McLiquidCrystalOnSilicon,
        McPlasma,
        McOrganicLightEmittingDiode,
        McElectroluminescent,
        McMicroelectromechanical,
        McFieldEmissionDevice,
    }
}

public static class NativeCalls
{
    [DllImport("user32.dll")]
    public static extern IntPtr MonitorFromWindow([In] IntPtr hwnd, uint dwFlags);

    [DllImport("dxva2.dll")]
    public static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);

    [DllImport("dxva2.dll")]
    public static extern bool GetPhysicalMonitorsFromHMONITOR(IntPtr hMonitor,
        uint dwPhysicalMonitorArraySize, [Out] NativeStructures.PhysicalMonitor[] pPhysicalMonitorArray);

    [DllImport("dxva2.dll")]
    public static extern bool DestroyPhysicalMonitors(uint dwPhysicalMonitorArraySize,
        [Out] NativeStructures.PhysicalMonitor[] pPhysicalMonitorArray);

    [DllImport("dxva2.dll")]
    public static extern bool GetMonitorTechnologyType(IntPtr hMonitor,
        ref NativeStructures.McDisplayTechnologyType pdtyDisplayTechnologyType);

    [DllImport("dxva2.dll")]
    public static extern bool GetMonitorCapabilities(IntPtr hMonitor, ref uint pdwMonitorCapabilities,
        ref uint pdwSupportedColorTemperatures);

    [DllImport("dxva2.dll")]
    public static extern bool SetMonitorBrightness(IntPtr hMonitor, short brightness);

    [DllImport("dxva2.dll")]
    public static extern bool SetMonitorContrast(IntPtr hMonitor, short contrast);

    [DllImport("dxva2.dll")]
    public static extern bool GetMonitorBrightness(IntPtr hMonitor, ref short pdwMinimumBrightness,
        ref short pdwCurrentBrightness, ref short pdwMaximumBrightness);

    [DllImport("dxva2.dll")]
    public static extern bool GetMonitorContrast(IntPtr hMonitor, ref short pwdMinimumContrast,
        ref short pwdCurrentContrast, ref short pwdMaximumContrast);
}

public class BrightnessControl
{
    private readonly IntPtr hWnd;
    private NativeStructures.PhysicalMonitor[] pPhysicalMonitorArray;
    private uint pdwNumberOfPhysicalMonitors;

    public BrightnessControl(IntPtr hWnd)
    {
        hWnd = hWnd;
        SetupMonitors();
    }

    private void SetupMonitors()
    {
        var hMonitor = NativeCalls.MonitorFromWindow(hWnd, NativeConstants.MonitorDefaultToPrimary);
        var numberOfPhysicalMonitorsFromHmonitor = NativeCalls.GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, ref pdwNumberOfPhysicalMonitors);
        pPhysicalMonitorArray = new NativeStructures.PhysicalMonitor[pdwNumberOfPhysicalMonitors];
        var physicalMonitorsFromHmonitor = NativeCalls.GetPhysicalMonitorsFromHMONITOR(hMonitor, pdwNumberOfPhysicalMonitors, pPhysicalMonitorArray);
    }

    private void GetMonitorCapabilities(int monitorNumber)
    {
        var pdwMonitorCapabilities = 0u;
        var pdwSupportedColorTemperatures = 0u;
        var monitorCapabilities = NativeCalls.GetMonitorCapabilities(pPhysicalMonitorArray[monitorNumber].hPhysicalMonitor,
            ref pdwMonitorCapabilities, ref pdwSupportedColorTemperatures);
        var type = NativeStructures.McDisplayTechnologyType.McShadowMaskCathodeRayTube;
        var monitorTechnologyType = NativeCalls.GetMonitorTechnologyType(pPhysicalMonitorArray[monitorNumber].hPhysicalMonitor, ref type);
    }

    public bool SetBrightness(short brightness, int monitorNumber)
    {
        var brightnessWasSet = NativeCalls.SetMonitorBrightness(pPhysicalMonitorArray[monitorNumber].hPhysicalMonitor, brightness);
        return brightnessWasSet;
    }

    public BrightnessInfo GetBrightnessCapabilities(int monitorNumber)
    {
        short current = -1, minimum = -1, maximum = -1;
        var getBrightness = NativeCalls.GetMonitorBrightness(pPhysicalMonitorArray[monitorNumber].hPhysicalMonitor, ref minimum, ref current, ref maximum);
        return new BrightnessInfo { Minimum = minimum, Maximum = maximum, Current = current };
    }

    public bool SetContrast(short contrast, int monitorNumber)
    {
        var contrastWasSet = NativeCalls.SetMonitorContrast(pPhysicalMonitorArray[monitorNumber].hPhysicalMonitor, contrast);
        return contrastWasSet;
    }

    public BrightnessInfo GetContrastCapabilities(int monitorNumber)
    {
        short current = -1, minimum = -1, maximum = -1;
        var getContrast = NativeCalls.GetMonitorContrast(pPhysicalMonitorArray[monitorNumber].hPhysicalMonitor, ref minimum, ref current, ref maximum);
        return new BrightnessInfo { Minimum = minimum, Maximum = maximum, Current = current };
    }

    public uint GetMonitors() { return pdwNumberOfPhysicalMonitors; }
}
Apr 23, 2017  • #2
User Image
overcookedTOFU
2 discussion posts
Great idea! I love the script, though for some reason the dialog box layout code doesn't seem to work quite right for my resolution and monitor setup (all three monitor sliders are drawn on top of one another). For my use, all I need is a way to set all three monitors to the same brightness. I will see if I can figure out how to edit your script to do that, but any suggestions are welcome.

As to flux, as I am sure you already know, flux works in software to dim the signal sent to the monitor. DDC/CI monitor controls actually change the hardware brightness on the monitors. When one needs the maximum brightness and contrast available from your monitor, flux simply constrains the available range. Also, as of the "creators update" to windows 10, flux is no longer necessary to change the display color temperature, as windows 10 now has a built in "night light" feature with the same functionality.

In any case, I hope DisplayFusion can incorporate this functionality into the monitor profiles feature.
Apr 23, 2017  • #3
PabloMartinez's profile on WallpaperFusion.com
The night light in Win 10 "CU" is weak to replace f.lux. :(
I only wrote about using f.lux algorithm (day/night-time cycle) to change the brightness in DF. Sorry for misunderstanding, English isn't my native.

I changed the script, it now allows to select from the available values, without dialog boxes for each monitor. You can completely discard dialog boxes and set a value directly, but it will need multiple copies of the script for different values. See comments in the code.

Code

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;

public static class DisplayFusionFunction
{
    public static void Run(IntPtr windowHandle)
    {
        short bValue;
        var monitorControl = new BrightnessControl(windowHandle);
        var monitorCount = monitorControl.GetMonitors();

        // This dialog and if statement may be delete
        var brightList = BFS.Dialog.GetUserInputList("Select brightness you need", new string[] {"0", "25", "50", "75", "100"});
        if (!short.TryParse(brightList, out bValue))
            bValue = 0;

        for (var monNum = 0; monNum < monitorCount; ++monNum)
        {
            var mInfo = monitorControl.GetBrightnessCapabilities(monNum);
            if (mInfo.Current == -1)
            {
                BFS.Dialog.ShowMessageInfo("Error. One of your monitors does not supported DDC/CI");
                return;
            }
            // If you delete a dialog, the direct value of bValue 0-100 must be set
            monitorControl.SetBrightness(bValue, monNum);
        }
    }
}

public class BrightnessInfo
{
    public int Minimum { get; set; }
    public int Maximum { get; set; }
    public int Current { get; set; }
}

public static class NativeConstants
{
    public const int MonitorDefaultToNull = 0;
    public const int MonitorDefaultToPrimary = 1;
    public const int MonitorDefaultToNearest = 2;
}

public static class NativeStructures
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct PhysicalMonitor
    {
        public IntPtr hPhysicalMonitor;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string szPhysicalMonitorDescription;
    }
}

public static class NativeCalls
{
    [DllImport("user32.dll")]
    public static extern IntPtr MonitorFromWindow([In] IntPtr hwnd, uint dwFlags);

    [DllImport("dxva2.dll")]
    public static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);

    [DllImport("dxva2.dll")]
    public static extern bool GetPhysicalMonitorsFromHMONITOR(IntPtr hMonitor,
        uint dwPhysicalMonitorArraySize, [Out] NativeStructures.PhysicalMonitor[] pPhysicalMonitorArray);

    [DllImport("dxva2.dll")]
    public static extern bool GetMonitorCapabilities(IntPtr hMonitor, ref uint pdwMonitorCapabilities,
        ref uint pdwSupportedColorTemperatures);

    [DllImport("dxva2.dll")]
    public static extern bool SetMonitorBrightness(IntPtr hMonitor, short brightness);

    [DllImport("dxva2.dll")]
    public static extern bool GetMonitorBrightness(IntPtr hMonitor, ref short pdwMinimumBrightness,
        ref short pdwCurrentBrightness, ref short pdwMaximumBrightness);
}

public class BrightnessControl
{
    private readonly IntPtr hWnd;
    private NativeStructures.PhysicalMonitor[] pPhysicalMonitorArray;
    private uint pdwNumberOfPhysicalMonitors;

    public BrightnessControl(IntPtr hWnd)
    {
        this.hWnd = hWnd;
        SetupMonitors();
    }

    private void SetupMonitors()
    {
        var hMonitor = NativeCalls.MonitorFromWindow(hWnd, NativeConstants.MonitorDefaultToPrimary);
        var numberOfPhysicalMonitorsFromHmonitor = NativeCalls.GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, ref pdwNumberOfPhysicalMonitors);
        pPhysicalMonitorArray = new NativeStructures.PhysicalMonitor[pdwNumberOfPhysicalMonitors];
        var physicalMonitorsFromHmonitor = NativeCalls.GetPhysicalMonitorsFromHMONITOR(hMonitor, pdwNumberOfPhysicalMonitors, pPhysicalMonitorArray);
    }

    public bool SetBrightness(short brightness, int monitorNumber)
    {
        var brightnessWasSet = NativeCalls.SetMonitorBrightness(pPhysicalMonitorArray[monitorNumber].hPhysicalMonitor, brightness);
        return brightnessWasSet;
    }

    public BrightnessInfo GetBrightnessCapabilities(int monitorNumber)
    {
        short current = -1, minimum = -1, maximum = -1;
        var getBrightness = NativeCalls.GetMonitorBrightness(pPhysicalMonitorArray[monitorNumber].hPhysicalMonitor, ref minimum, ref current, ref maximum);
        return new BrightnessInfo { Minimum = minimum, Maximum = maximum, Current = current };
    }

    public uint GetMonitors() { return pdwNumberOfPhysicalMonitors; }
}
Apr 24, 2017 (modified Apr 24, 2017)  • #4
Keith Lammers (BFS)'s profile on WallpaperFusion.com
Thanks for providing the script, Pablo!

@overcooked: We do have an open request on our list for DDC/CI controls, so I've added your vote to it.
Apr 25, 2017  • #5
PabloMartinez's profile on WallpaperFusion.com
For one monitor, this is a good solution, but for a multi-monitors, is not the best choice, because it only works on the monitor on which it was called. I'll try to rework it later to be able to change brightness to the all monitors at once.
Apr 25, 2017  • #6
Subscribe to this discussion topic using RSS
Was this helpful?  Login to Vote(1)  Login to Vote(-)