4

Windows 10 has a feature to change the screen's color temperature named Night Light. This is a blue light reduction feature.

I would like to implement a clone of this feature in C++, using windows API. But have no idea how to do so.

  • How do I access the screen and change what it displays system wide using win api? It must be resources efficient.
  • And can we apply it only on a given window, not the whole screen?
Julien__
  • 1,962
  • 1
  • 15
  • 25
  • 2
    _"...What is the canonical way to access the screen..."_ C++ has no direct way to access the screen you would have to use a 3rd party API/library. For the WinAPI use https://learn.microsoft.com/en-us/windows/win32/api/highlevelmonitorconfigurationapi/nf-highlevelmonitorconfigurationapi-setmonitorcolortemperature – Richard Critten Oct 02 '19 at 16:01
  • even using windows API? The os should be able to access the screen – Julien__ Oct 02 '19 at 16:02
  • I did an internet search using the keywords "windows 10 night light api", and came up with [Get status of night light mode in Windows 10](https://stackoverflow.com/questions/43340619/get-status-of-night-light-mode-in-windows-10). Have you searched the internet lately? – Thomas Matthews Oct 02 '19 at 17:31
  • @ThomasMatthews, have you read the actual question and answers' comments? ;-) Nothing usable in there. – Julien__ Oct 02 '19 at 18:30

3 Answers3

4

It's not always a valid expectation that the OS will allow you to do what it itself does. Just because "the os should be able to access the screen" doesn't mean that you (in userland) should be able to do that. And most certainly, under Windows you have no unfettered screen access, not least because of DRM: there is a protected media path (PMP) for protected video and audio content, and you won't be able to sniff it from an arbitrary process.

So: whatever night light you may implement by accessing the screen contents, won't work as soon as any protected content is displayed, e.g. from Netflix, Hulu, Youtube Red, system DVD player, BluRay player, etc. To get around PMP you'd need to write a driver, sign it using an EV code signing certificate, and then submit it for automated attestation signing by Microsoft. And you'd not dare put it on the web, because Microsoft would blacklist that driver (i.e. its presence in the kernel would cause PMP-using applications to refuse to play protected content), and perhaps quickly at that.

With that out of the way, there are several ways that Windows could implement it, but we don't care because we're not writing a direct replacement for the Windows Night Light component. All we have access to is userland. Here's what we got to work with, then:

  1. Windows itself performs monitor colorspace calibration using the "gamma ramp" system: a lookup table, historically used mostly for linearization of the monitor response, and subsequently used as a kitchen sink. There are three generations of those APIs:

    • The most legacy-compatible way would be to use the Windows Color System APIs, supported since Windows 2000. The function to use is SetDeviceGammaRamp. There is a caveat: Windows doesn't allow compressing the color too much, and it's quite arbitrary about what it allows. This family of APIs may fail if you try to do "too much".

    • Another highly compatible API would be within Direct3D 9 (available since Windows 98 and XP). It offers SetGammaRamp, with same data table format as that of SetDeviceGammaRamp above.

    • Yet another highly compatible API would be within Direct3D 10-12's DirectX Graphics Interface - DXGI, specifically IDXGIOutput::SetGammaControl. This one was available since Windows Vista, and thus is available on currently (2020) supported Windows versions.

  2. The next most compatible approach would be to use the Magnification API.

  3. The last approach, working only on your own application's window, would be to apply a shader to your window.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
2

This can be emulated using color correction scheme. There is this OpenSource project, DisplayCAL. It's a calibrator which does it for other purposes and also allows to use various calibrator devices. Essentially there is a digital filter in place by design for all graphical output devices, which converts source RGB into screen RGB and there is possibility to change it. Linux have something similar in some distros.

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42
0

Microsoft provides the Monitor Configuration functions which use the Display Data Channel Command Interface (DDC/CI) to send commands to a monitor. While I'm not sure this is how they are doing it, it seems to be the most likely approach.

This API is used with a physical monitor handle which implies that it is for the entire monitor's screen and not individual windows displayed on the monitor.

You can use the monitor configuration functions to get information from a monitor and to change a monitor's settings. You can use these functions to :

  • Change a monitor's geometry settings, such as the width and height of the display.
  • Change image settings, such as brightness and contrast.
  • Reset a monitor's settings to their factory defaults.
  • Degauss the monitor.

Internally, the monitor configuration functions use the Display Data Channel Command Interface (DDC/CI) to send commands to the monitor.

The Monitor Configuration topic mentions:

To develop Monitor Configuration, you need these headers:

Looking at the Windows App Development topic Monitor Configuration Functions which contains a list of functions, there are several that you may find useful.

All of the above High Level Monitor Configuration API functions appear to have requirements of:

Minimum supported client Windows Vista [desktop apps only]

Minimum supported server Windows Server 2008 [desktop apps only]

Target Platform Windows

Header highlevelmonitorconfigurationapi.h

Library Dxva2.lib

DLL Dxva2.dll

They all require a handle to a physical monitor which is obtained through the functions GetPhysicalMonitorsFromHMONITOR() or GetPhysicalMonitorsFromIDirect3DDevice9().

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106