Skip to content

Repository files navigation

HdrAutoSwitch

Turns Windows HDR on while a listed game runs, and back off when it exits. A tray app, one executable, no driver hooks and no injection.

build license

Windows leaves HDR as a global display setting, so leaving it on all the time washes out SDR content, and turning it on per session means a trip to Settings before and after every game. This watches for the games that actually use HDR and flips the setting around them.

It also handles the games that check for HDR once while they start and never look again, which is the case that makes most auto-switchers useless. See Games that decide at startup.

Install

  1. Download HdrAutoSwitch.zip from Releases.
  2. Right-click the zip, choose Properties, tick Unblock, then extract it anywhere.
  3. Open PowerShell in that folder and run:
powershell -ExecutionPolicy Bypass -File .\install.ps1

The -ExecutionPolicy Bypass is needed because Windows blocks downloaded scripts by default. It applies to that one command and changes nothing on your system.

The installer registers the app under HKCU\...\Run so it starts at logon, then launches it. No elevation, no UAC prompt: switching HDR through the DisplayConfig API is a per-user operation. uninstall.ps1 reverses it.

Prefer not to run a script? Just run HdrAutoSwitch.exe, then tick Start with Windows on its tray menu. It is portable and writes only to its own folder plus that one registry value.

Requires .NET Framework 4, which every supported version of Windows already has, and an HDR capable display. Built and tested on Windows 11 (build 26200).

Using it

The tray icon is under the ^ arrow next to the clock. Green means HDR is on right now, gray means off, amber means automatic switching is paused.

Right-click it for:

Item What it does
Turn HDR on now / off now Switches the displays you ticked, and drops automatic ownership
Automatic switching Master on/off. Double-clicking the tray icon does the same
Games Tick the programs that should turn HDR on. Add a running one, or browse for an exe
Displays Tick which monitors get switched. Monitors without HDR are grayed out
Start with Windows Adds or removes the logon entry
Reload settings Re-reads config.ini after a hand edit

The game list starts with Cyberpunk 2077 and STALKER 2, each as two entries: the game (Cyberpunk2077.exe, Stalker2-Win64-Shipping.exe) and its launcher (REDprelauncher.exe, Stalker2.exe). Listing the launcher as well buys the switch a head start, which some games want. Delete them if you do not own them. The primary display is ticked if it supports HDR.

Games that decide at startup

Some engines check once, while starting, whether the display can do HDR, and never look again. Unreal Engine is one: if Windows HDR was off at that instant, the game's HDR option stays hidden for the whole session. STALKER 2 behaves this way, and its launcher hands off to the game immediately, so a switch that merely starts when the game appears is too late.

So by default the game is paused while the display switches. When a listed program appears and HDR has to change, every listed process is suspended, HDR is switched on, LaunchSettleMs passes so the change has finished everywhere, and the processes are resumed. The game loses about two seconds of loading and then does its real startup with HDR already on.

Measured on Windows 11 build 26200, with a test program that timestamps its own first instruction:

Event Time after the process is created
Process suspended under 100 ms, while the runtime is still loading
HDR reads back as on 361 ms
Process resumed, its own first instruction runs 2,213 ms

The pause uses NtSuspendProcess, the call Process Explorer's Suspend uses. It needs only PROCESS_SUSPEND_RESUME on a process owned by the same user, so no elevation is involved. PauseGameWhileSwitching=0 turns it off.

A game with kernel anti-cheat may object to being suspended. For those, switch the pause off and make the launch itself wait instead. In Steam, open the game's Properties, General, Launch Options, and enter this, with the path to wherever you extracted it:

"C:\Tools\HdrAutoSwitch\HdrAutoSwitch.exe" --run %command%

--run turns HDR on for the ticked displays, waits LaunchSettleMs for the switch to finish, starts the game with Steam's own command line and environment, and turns HDR back off once the game and anything else on the game list have exited. It works with the watcher running: the watcher sees HDR already on and leaves it alone. Outside Steam, the same form works from a shortcut: HdrAutoSwitch.exe --run "C:\Games\Game.exe" -arg.

Command line

For a hotkey or another script:

HdrAutoSwitch.exe --on       # HDR on for the ticked displays
HdrAutoSwitch.exe --off
HdrAutoSwitch.exe --toggle
HdrAutoSwitch.exe --status   # lists every display with its HDR state
HdrAutoSwitch.exe --run <program> [args]   # HDR on, run the program, HDR off when it is gone
HdrAutoSwitch.exe --quit     # asks a running instance to exit cleanly

Exit code 0 means every ticked display reached (or, for --status, is in) the requested state. --status returns 1 if any ticked display is off and 2 if none are ticked. --run returns the program's own exit code.

This is a windowed application, so a shell does not wait for it and $LASTEXITCODE will be whatever came before. To read the exit code, wait for it:

$p = Start-Process HdrAutoSwitch.exe '--status' -Wait -PassThru -NoNewWindow
$p.ExitCode

What it will not do

It only turns a display off again if it was the one that turned it on. If HDR was already on when the game started, or you switched it by hand from the tray, closing the game leaves it alone.

config.ini

Key Default Meaning
Enabled 1 Master switch for the automatic part
PollIntervalMs 100 How often the game list is checked
ExitDelaySeconds 5 Grace period after the last game closes, so a relaunch does not flap
RevertOnExit 1 Put HDR back the way it was
ReapplyWhileRunning 1 Re-enable HDR if a driver reset or a resume drops it mid-game
Notifications 1 Balloon tip on each switch
Log 1 Write HdrAutoSwitch.log next to the exe, trimmed to 400 lines at startup
PauseGameWhileSwitching 1 Suspend listed processes until the switch has finished (see above)
LaunchSettleMs 1500 How long the switch is given to finish before the game runs, for the pause and for --run

[Displays] holds one line per monitor, keyed on the monitor's friendly name.

Notes

  • HDR is switched through DisplayConfigSetDeviceInfo with SET_ADVANCED_COLOR_STATE, the same call the Settings app makes. It needs no elevation. The new state is read back rather than trusted, because the call can report success and change nothing, so a failure lands in the log instead of passing silently.
  • Detection is by process name, checked every 100 ms. Listed processes are paused while the switch happens (see above), so a game cannot read the display state mid-switch. If a title still comes up in SDR, add its launcher to the game list too, so the switch happens while the launcher is on screen.
  • Switching HDR is a display mode change. Some games in exclusive fullscreen minimize when one happens, which is why the switch is made at process start rather than when a window appears.
  • The friendly name is the display key, so two identical monitors are treated as one entry and switch together.

Files

File What it is
src\Native.cs DisplayConfig interop, enumerate and set
src\Config.cs The two ini files
src\TrayIcons.cs The three tray icon states, drawn at runtime
src\Program.cs Tray app, watcher loop, menu, the process pause, and the one-shot modes
install.ps1 Registers the logon entry and starts the app
uninstall.ps1 Removes the logon entry and stops the app

config.ini and games.ini are written by the app on first run, so they are not in the repository.

Build from source

powershell -ExecutionPolicy Bypass -File .\build.ps1

It compiles with the C# compiler that ships inside C:\Windows\Microsoft.NET, so no SDK or Visual Studio is needed. A running instance is asked to quit first (which reverts any HDR it switched), then relaunched.

License

MIT, see LICENSE.

About

Turns Windows HDR on while a game runs and off when it exits. Pauses the game while the display switches, so engines that check for HDR once at startup still see it. One exe, no injection.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages