This script uses PowerShell to change Windows System Color Index 5 (Canvas 5) from the glaring white to any color of your choosing. This changes the the default white canvas in word, excel, outlook, and many other programs , therefore it should be USED WITH CAUTION. It may change interfaces that you don't expect, but it is very easy to change back.
P.s. It will not work if you run Powershell with restricted language settings.
The script is invoked through the user command "BackgroundModes"
// BackgroundModes.js
// J.Fourie
// Directory Opus Script Add-in (JScript)
//
// What is “canvas 5”:
// This script changes Windows system color index 5, also called COLOR_WINDOW.
// COLOR_WINDOW is the classic Win32 “window background” system color.
//
// What it affects:
// It can affect classic Windows controls that use the system window background:
// - Word, Excel, Outlook, and therefore the Preview Pane in DOPUS for these documents.
// - older Win32 dialog backgrounds
// - some Directory Opus surfaces if they inherit COLOR_WINDOW
//
// It may not affect modern apps, browsers, Electron apps, UWP apps, or heavily
// themed programs because they often draw their own backgrounds.
//
// How it works:
// This script writes a temporary PowerShell helper, then PowerShell uses P/Invoke
// to call:
// - GetSysColor(5)
// - SetSysColors(5)
// - SendMessageTimeout(WM_SYSCOLORCHANGE)
//
// Safety model:
// The script changes only COLOR_WINDOW, not COLOR_WINDOWTEXT.
// Since text is assumed to remain black, all built-in colors are deliberately
// light but visibly non-white.
// SetSysColors affects the current Windows session; it is not written as a
// permanent Windows theme setting.
//
// Commands:
// BackgroundModes
// BackgroundModes MODE=Nord
// BackgroundModes MODE=Gruvbox
// BackgroundModes MODE=Normal
// BackgroundModes MODE=Custom HEX=D8F3DC
// BackgroundModes MODE=SetCustom
var VAR_ORIGINAL = "BackgroundModes.OriginalColorRef";
var VAR_CURRENT = "BackgroundModes.CurrentMode";
var VAR_CUSTOMHEX = "BackgroundModes.CustomHex";
var COLOR_WINDOW_INDEX = 5;
var DEFAULT_CUSTOM_HEX = "#D8F3DC";
// Minimum contrast ratio against black text.
var MIN_BLACK_TEXT_CONTRAST = 4.5;
function OnInit(initData)
{
initData.name = "Background Modes";
initData.version = "1.4";
initData.desc = "Switch Windows COLOR_WINDOW background colors.";
initData.default_enable = true;
initData.min_version = "12.0";
if (!initData.vars.Exists(VAR_CURRENT))
initData.vars.Set(VAR_CURRENT, "Normal");
if (!initData.vars.Exists(VAR_CUSTOMHEX)) {
initData.vars.Set(VAR_CUSTOMHEX, DEFAULT_CUSTOM_HEX);
initData.vars(VAR_CUSTOMHEX).persist = true;
}
var cmd = initData.AddCommand();
cmd.name = "BackgroundModes";
cmd.method = "OnBackgroundModes";
cmd.desc = "Set or restore Windows COLOR_WINDOW background color.";
cmd.label = "Background Modes";
cmd.template = "MODE/O,HEX/O";
cmd.icon = "prefs";
}
function OnShutdown(shutdownData)
{
restoreOriginalQuietly("shutdown");
}
function OnBackgroundModes(data)
{
try {
ensureOriginalCaptured();
var args = data.func.argsmap;
var mode = "";
var hex = "";
if (args.exists("MODE"))
mode = String(args("MODE"));
if (args.exists("HEX"))
hex = String(args("HEX"));
if (mode == "") {
mode = showModeMenu(data.func);
if (mode == "")
return;
}
mode = canonicalMode(mode);
if (mode == "SetCustom") {
setCustomHex(data.func, hex);
return;
}
if (mode == "Custom" && hex != "") {
setCustomHex(data.func, hex);
return;
}
applyMode(mode);
}
catch (e) {
showError(data.func, e);
}
}
function modeDefs()
{
var customHex = getCustomHex();
return [
{ name:"Normal", label:"Normal (restore defaults)", color:null },
// Practical distinct light backgrounds.
{ name:"SoftGreen", label:"Soft Green (#D8F3DC)", color:colorRef("#D8F3DC") },
{ name:"Mint", label:"Mint (#CDEAC0)", color:colorRef("#CDEAC0") },
{ name:"Sage", label:"Sage (#DDE5B6)", color:colorRef("#DDE5B6") },
{ name:"Sand", label:"Sand (#EAD7BB)", color:colorRef("#EAD7BB") },
{ name:"Sepia", label:"Sepia (#E8DCC8)", color:colorRef("#E8DCC8") },
{ name:"Parchment", label:"Parchment (#F5DEB3)", color:colorRef("#F5DEB3") },
{ name:"Peach", label:"Peach (#FFD6BA)", color:colorRef("#FFD6BA") },
{ name:"Apricot", label:"Apricot (#F4C2A1)", color:colorRef("#F4C2A1") },
{ name:"Blush", label:"Blush (#F2C6C2)", color:colorRef("#F2C6C2") },
{ name:"Lavender", label:"Lavender (#D8CCF1)", color:colorRef("#D8CCF1") },
{ name:"Sky", label:"Sky (#C7DDF2)", color:colorRef("#C7DDF2") },
{ name:"PowderBlue", label:"Powder Blue (#BFD7EA)", color:colorRef("#BFD7EA") },
// Popular scheme-inspired, but adjusted to be visibly non-white.
{ name:"Nord", label:"Nord Frost Light (#C8D9E8)", color:colorRef("#C8D9E8") },
{ name:"Dracula", label:"Dracula Soft Pink (#E9C7D9)", color:colorRef("#E9C7D9") },
{ name:"Gruvbox", label:"Gruvbox Warm Light (#EBDBB2)", color:colorRef("#EBDBB2") },
{ name:"Solarized", label:"Solarized Cream (#EEE8D5)", color:colorRef("#EEE8D5") },
{ name:"Catppuccin", label:"Catppuccin Peach Light (#F2CDCD)", color:colorRef("#F2CDCD") },
{ name:"RosePine", label:"Rosé Pine Dawn Iris (#DFD7F4)", color:colorRef("#DFD7F4") },
{ name:"Kanagawa", label:"Kanagawa Lotus (#E6C384)", color:colorRef("#E6C384") },
{ name:"Custom", label:"Custom (" + customHex + ")", color:colorRef(customHex) }
];
}
function applyMode(mode)
{
if (mode == "Normal") {
restoreOriginal();
setCurrentMode("Normal");
return;
}
var defs = modeDefs();
for (var i = 0; i < defs.length; i++) {
if (defs[i].name == mode) {
setColorRef(defs[i].color);
setCurrentMode(mode);
return;
}
}
throw "Unknown mode: " + mode;
}
function restoreOriginal()
{
if (!Script.vars.Exists(VAR_ORIGINAL))
throw "No original COLOR_WINDOW value has been captured yet.";
setColorRef(Number(Script.vars.Get(VAR_ORIGINAL)));
}
function restoreOriginalQuietly(context)
{
try {
if (Script.vars.Exists(VAR_ORIGINAL))
setColorRef(Number(Script.vars.Get(VAR_ORIGINAL)));
}
catch (e) {
DOpus.Output("Background Modes " + context + " restore failed: " + e);
}
}
function ensureOriginalCaptured()
{
if (!Script.vars.Exists(VAR_ORIGINAL))
Script.vars.Set(VAR_ORIGINAL, getColorRef());
}
function setCurrentMode(mode)
{
Script.vars.Set(VAR_CURRENT, mode);
}
function getCurrentMode()
{
if (Script.vars.Exists(VAR_CURRENT))
return String(Script.vars.Get(VAR_CURRENT));
return "Normal";
}
function showModeMenu(func)
{
var defs = modeDefs();
var current = getCurrentMode();
var choices = [];
var flags = [];
for (var i = 0; i < defs.length; i++) {
choices.push(defs[i].label);
flags.push(defs[i].name == current ? 4 : 0);
}
choices.push("-");
flags.push(0);
choices.push("Set Custom...");
flags.push(0);
var dlg = func.Dlg();
dlg.title = "Background Modes";
dlg.choices = choices;
dlg.menu = flags;
var result = dlg.Show();
if (result == 0)
return "";
if (result == choices.length)
return "SetCustom";
return defs[result - 1].name;
}
function setCustomHex(func, suppliedHex)
{
var hex = suppliedHex;
if (hex == "") {
var dlg = func.Dlg();
dlg.title = "Custom COLOR_WINDOW";
dlg.message = "Enter a light RGB hex color suitable for black text, e.g. #D8F3DC";
dlg.buttons = "OK|Cancel";
dlg.max = 7;
dlg.defvalue = getCustomHex();
dlg.select = true;
if (dlg.Show() != 1)
return;
hex = dlg.input;
}
saveCustomHex(hex);
applyMode("Custom");
}
function saveCustomHex(hex)
{
hex = normalizeHex(hex);
assertReadableWithBlackText(hex);
Script.vars.Set(VAR_CUSTOMHEX, hex);
Script.vars(VAR_CUSTOMHEX).persist = true;
}
function getCustomHex()
{
if (Script.vars.Exists(VAR_CUSTOMHEX)) {
try {
return normalizeHex(String(Script.vars.Get(VAR_CUSTOMHEX)));
}
catch (e) {
return DEFAULT_CUSTOM_HEX;
}
}
return DEFAULT_CUSTOM_HEX;
}
function canonicalMode(mode)
{
var key = String(mode).replace(/^\s+|\s+$/g, "").toLowerCase();
if (key == "setcustom" || key == "set custom" || key == "setcustomcolor")
return "SetCustom";
var aliases = {
// Previous basic names.
"morning": "SoftGreen",
"day": "Sage",
// Direct aliases.
"softgreen": "SoftGreen",
"soft green": "SoftGreen",
"powderblue": "PowderBlue",
"powder blue": "PowderBlue",
// Popular scheme aliases.
"nordfrost": "Nord",
"nord frost": "Nord",
"draculalight": "Dracula",
"dracula light": "Dracula",
"gruvboxlight": "Gruvbox",
"gruvbox light": "Gruvbox",
"solarizedlight": "Solarized",
"solarized light": "Solarized",
"catppuccinlatte": "Catppuccin",
"catppuccin latte": "Catppuccin",
"rosepine": "RosePine",
"rose pine": "RosePine",
"rosepinedawn": "RosePine",
"rose pine dawn": "RosePine",
"rosé pine": "RosePine",
"rosé pine dawn": "RosePine",
"kanagawalotus": "Kanagawa",
"kanagawa lotus": "Kanagawa",
// Old dark/night names redirected to light readable colors.
"night": "Sky",
"evening": "Sepia",
"midnight": "PowderBlue",
"twilight": "Lavender",
"nighttime": "Sand",
"night time": "Sand",
// Removed/old names redirected, but not shown in the menu.
"burlywood": "Sand",
"daytime": "Parchment",
"day time": "Parchment",
"careeye": "Sepia",
"care eye": "Sepia"
};
if (aliases[key])
return aliases[key];
var defs = modeDefs();
for (var i = 0; i < defs.length; i++) {
if (defs[i].name.toLowerCase() == key)
return defs[i].name;
}
throw "Unknown mode: " + mode;
}
function normalizeHex(hex)
{
hex = String(hex).replace(/^\s+|\s+$/g, "");
if (hex.charAt(0) == "#")
hex = hex.substr(1);
if (!/^[0-9a-fA-F]{6}$/.test(hex))
throw "Invalid color. Use #RRGGBB, e.g. #D8F3DC.";
return "#" + hex.toUpperCase();
}
function colorRef(hex)
{
return rgbHexToBgr(hex);
}
function rgbHexToBgr(hex)
{
hex = normalizeHex(hex).substr(1);
var r = parseInt(hex.substr(0, 2), 16);
var g = parseInt(hex.substr(2, 2), 16);
var b = parseInt(hex.substr(4, 2), 16);
return (b << 16) | (g << 8) | r;
}
function assertReadableWithBlackText(hex)
{
var contrast = contrastAgainstBlack(hex);
if (contrast < MIN_BLACK_TEXT_CONTRAST) {
throw "Custom color " + normalizeHex(hex) +
" is too dark for black text. Use a lighter color.";
}
}
function contrastAgainstBlack(hex)
{
var luminance = relativeLuminance(hex);
// Black luminance is 0.
return (luminance + 0.05) / 0.05;
}
function relativeLuminance(hex)
{
hex = normalizeHex(hex).substr(1);
var r = parseInt(hex.substr(0, 2), 16);
var g = parseInt(hex.substr(2, 2), 16);
var b = parseInt(hex.substr(4, 2), 16);
var rl = linearRgbChannel(r);
var gl = linearRgbChannel(g);
var bl = linearRgbChannel(b);
return (0.2126 * rl) + (0.7152 * gl) + (0.0722 * bl);
}
function linearRgbChannel(value)
{
var c = value / 255;
if (c <= 0.03928)
return c / 12.92;
return Math.pow((c + 0.055) / 1.055, 2.4);
}
function getColorRef()
{
var out = runPowerShellHelper("get", 0);
out = String(out).replace(/^\s+|\s+$/g, "");
if (!/^\d+$/.test(out))
throw "Could not read COLOR_WINDOW. PowerShell returned: " + out;
return Number(out);
}
function setColorRef(colorRef)
{
runPowerShellHelper("set", Number(colorRef));
}
function runPowerShellHelper(action, colorRef)
{
var shell = new ActiveXObject("WScript.Shell");
var psPath = "";
var stdout = "";
var stderr = "";
var exitCode = 0;
try {
psPath = writePowerShellHelper(shell);
var cmd = "powershell.exe -NoProfile -ExecutionPolicy Bypass -NonInteractive" +
" -File " + quoteArg(psPath) +
" -Action " + quoteArg(action) +
" -Color " + String(Number(colorRef));
var exec = shell.Exec(cmd);
while (exec.Status == 0)
DOpus.Delay(10);
stdout = exec.StdOut.ReadAll();
stderr = exec.StdErr.ReadAll();
exitCode = exec.ExitCode;
if (exitCode != 0)
throw "PowerShell helper failed: " + stderr;
return stdout;
}
finally {
if (psPath != "")
deleteFileQuietly(psPath);
}
}
function writePowerShellHelper(shell)
{
var fso = new ActiveXObject("Scripting.FileSystemObject");
var temp = shell.ExpandEnvironmentStrings("%TEMP%");
var name = "DOpus_BackgroundModes_" + String(new Date().getTime()) + "_" + String(Math.floor(Math.random() * 1000000)) + ".ps1";
var path = temp + "\\" + name;
var ps =
"param(\r\n" +
" [Parameter(Mandatory=$true)][ValidateSet('get','set')][string]$Action,\r\n" +
" [UInt32]$Color = 0\r\n" +
")\r\n" +
"$ErrorActionPreference = 'Stop'\r\n" +
"$src = @'\r\n" +
"using System;\r\n" +
"using System.Runtime.InteropServices;\r\n" +
"public static class DOpusBackgroundModesWin32 {\r\n" +
" [DllImport(\"user32.dll\")]\r\n" +
" public static extern uint GetSysColor(int nIndex);\r\n" +
" [DllImport(\"user32.dll\", SetLastError=true)]\r\n" +
" public static extern bool SetSysColors(int cElements, int[] lpaElements, uint[] lpaRgbValues);\r\n" +
" [DllImport(\"user32.dll\", SetLastError=true, CharSet=CharSet.Auto)]\r\n" +
" public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);\r\n" +
"}\r\n" +
"'@\r\n" +
"Add-Type -TypeDefinition $src\r\n" +
"$idx = " + String(COLOR_WINDOW_INDEX) + " # COLOR_WINDOW\r\n" +
"if ($Action -eq 'get') {\r\n" +
" [DOpusBackgroundModesWin32]::GetSysColor($idx)\r\n" +
" exit 0\r\n" +
"}\r\n" +
"$ok = [DOpusBackgroundModesWin32]::SetSysColors(1, [int[]]@($idx), [uint32[]]@($Color))\r\n" +
"if (-not $ok) { throw 'SetSysColors failed.' }\r\n" +
"$result = [UIntPtr]::Zero\r\n" +
"[DOpusBackgroundModesWin32]::SendMessageTimeout([IntPtr]0xffff, [uint32]0x0015, [UIntPtr]::Zero, [IntPtr]::Zero, [uint32]0x0002, [uint32]250, [ref]$result) | Out-Null\r\n";
var file = fso.CreateTextFile(path, true, false);
file.Write(ps);
file.Close();
return path;
}
function deleteFileQuietly(path)
{
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (fso.FileExists(path))
fso.DeleteFile(path, true);
}
catch (ignored) {
}
}
function quoteArg(s)
{
return '"' + String(s) + '"';
}
function showError(func, e)
{
var message = String(e);
DOpus.Output("Background Modes error: " + message);
try {
var dlg = func.Dlg();
dlg.title = "Background Modes";
dlg.message = message;
dlg.buttons = "OK";
dlg.icon = "error";
dlg.Show();
}
catch (ignored) {
}
}

