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.
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.
- Download
HdrAutoSwitch.zipfrom Releases. - Right-click the zip, choose Properties, tick Unblock, then extract it anywhere.
- Open PowerShell in that folder and run:
powershell -ExecutionPolicy Bypass -File .\install.ps1The -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).
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.
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.
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 cleanlyExit 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.ExitCodeIt 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.
| 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.
- HDR is switched through
DisplayConfigSetDeviceInfowithSET_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.
| 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.
powershell -ExecutionPolicy Bypass -File .\build.ps1It 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.
MIT, see LICENSE.