Skip to content

Commit

Permalink
Preliminary HDR support
Browse files Browse the repository at this point in the history
  • Loading branch information
xanderfrangos committed Oct 3, 2024
1 parent 017249f commit 01766b4
Show file tree
Hide file tree
Showing 12 changed files with 386 additions and 3 deletions.
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"suncalc": "^1.9.0",
"win32-displayconfig": "^0.1.0",
"windows-accent-colors": "^1.0.1",
"windows-hdr": "file:src/modules/windows-hdr",
"wmi-bridge": "file:src/modules/wmi-bridge",
"wmi-client": "^0.5.0"
},
Expand Down
58 changes: 58 additions & 0 deletions src/Monitors.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ console.log = (...args) => { args.unshift(tag); oLog(...args) }
console.log("Monitors.js starting. If you see this again, something bad happened!")
const w32disp = require("win32-displayconfig");
const wmibridge = require("wmi-bridge");
const hdr = require("windows-hdr");
const { exec } = require('child_process');
require("os").setPriority(0, require("os").constants.priority.PRIORITY_BELOW_NORMAL)

Expand Down Expand Up @@ -37,6 +38,8 @@ process.on('message', async (data) => {
})
} else if (data.type === "brightness") {
setBrightness(data.brightness, data.id)
} else if (data.type === "sdr") {
setSDRBrightness(data.brightness, data.id)
} else if (data.type === "settings") {
settings = data.settings

Expand Down Expand Up @@ -187,6 +190,17 @@ refreshMonitors = async (fullRefresh = false, ddcciType = "default", alwaysSendU
}
}

// HDR
if (settings.enableHDR) {
try {
startTime = process.hrtime.bigint()
monitorsHDR = await getHDRDisplays(monitors);
console.log(`getHDRDisplays() Total: ${(startTime - process.hrtime.bigint()) / BigInt(-1000000)}ms`)
} catch (e) {
console.log("\x1b[41m" + "getHDRDisplays() failed!" + "\x1b[0m", e)
}
}

// Hide internal
if (settings?.hideClosedLid) {
const wmiMonitor = Object.values(monitors).find(mon => mon.type === "wmi")
Expand Down Expand Up @@ -363,6 +377,17 @@ getAllMonitors = async (ddcciMethod = "default") => {
console.log("getBrightnessWMI() skipped due to previous failure.")
}

// HDR
if (settings.enableHDR) {
try {
startTime = process.hrtime.bigint()
monitorsHDR = await getHDRDisplays(foundMonitors);
console.log(`getHDRDisplays() Total: ${(startTime - process.hrtime.bigint()) / BigInt(-1000000)}ms`)
} catch (e) {
console.log("\x1b[41m" + "getHDRDisplays() failed!" + "\x1b[0m", e)
}
}

// Hide internal
if (settings?.hideClosedLid) {
const wmiMonitor = Object.values(foundMonitors).find(mon => mon.type === "wmi")
Expand Down Expand Up @@ -447,6 +472,29 @@ setStudioDisplayBrightness = async (serial, brightness) => {
}
}

getHDRDisplays = async (monitors) => {
try {
const displays = hdr.getDisplays()
for(const display of displays) {
const hwid = display.path.split("#")
updateDisplay(monitors, hwid[2], {
name: display.name,
key: hwid[2],
id: display.path,
hwid,
sdrNits: display.nits,
sdrLevel: parseInt((display.nits - 80) / 4),
hdr: "supported"
});
displays[hwid[2]] = display
}
} catch(e) {
console.log("\x1b[41m" + "getHDRDisplays(): failed to access displays" + "\x1b[0m", e)
}

return monitors
}

let wmiFailed = false
getMonitorsWMI = () => {
return new Promise(async (resolve, reject) => {
Expand Down Expand Up @@ -825,6 +873,16 @@ updateDisplay = (monitors, hwid2, info = {}) => {
return true
}

function setSDRBrightness(brightness, id) {
if(!settings.enableHDR) return false;
try {
console.log("sdr", brightness, id)
hdr.setSDRBrightness(id, (brightness * 0.01 * 400) + 80)
} catch(e) {
console.log(`Couldn't update SDR brightness! [${id}]`, e);
}
}

function setBrightness(brightness, id) {
try {
if (id) {
Expand Down
18 changes: 18 additions & 0 deletions src/components/MonitorInfo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default function MonitorInfo(props) {
const [contrast, setContrast] = useState(monitor?.features?.["0x12"] ? monitor?.features?.["0x12"][0] : 50)
const [volume, setVolume] = useState(monitor?.features?.["0x62"] ? monitor?.features?.["0x62"][0] : 50)
const [powerState, setPowerState] = useState(monitor?.features?.["0xD6"] ? monitor?.features?.["0xD6"][0] : 50)
const [sdr, setSDR] = useState(monitor.sdrLevel >= 0 ? monitor.sdrLevel : 50)
const [manualVCP, setManualVCP] = useState("")
const [manualValue, setManualValue] = useState("")

Expand Down Expand Up @@ -75,6 +76,14 @@ export default function MonitorInfo(props) {
</div>
)

// SDR test
extraHTML.push(
<div className="feature-row" key="sdrLevel">
<div className="feature-icon">SDR</div>
<Slider type="sdrLevel" monitorID={monitor.id} level={sdr} monitorName={monitor.name} max={100} monitortype={monitor.type} onChange={val => { setSDR(val); setSDRBrightness(monitor.id, val) }} scrolling={false} />
</div>
)

return (
<div key={monitor.key}>
<br />
Expand All @@ -101,6 +110,15 @@ function setVCP(monitor, code, value) {
}))
}

function setSDRBrightness(monitor, value) {
window.dispatchEvent(new CustomEvent("set-sdr-brightness", {
detail: {
monitor,
value
}
}))
}

function getDebugMonitorType(type) {
if (type == "none") {
return (<><b>None</b> <span className="icon red vfix">&#xEB90;</span></>)
Expand Down
1 change: 1 addition & 0 deletions src/components/SettingsWindow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,7 @@ export default class SettingsWindow extends PureComponent {
<SettingsOption title="Use GUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS events" input={this.renderToggle("useGuidBrightnessEvent")} />
<SettingsOption title="Reload tray icon on hardware events" input={this.renderToggle("reloadTray")} />
<SettingsOption title="Reload flyout panel on hardware events" input={this.renderToggle("reloadFlyout")} />
<SettingsOption title="Enable HDR support" input={this.renderToggle("enableHDR")} />
<SettingsOption title="Show console window (requires restart)" input={this.renderToggle("showConsole")} />
<SettingsOption title="Use Taskbar Registry" input={this.renderToggle("useTaskbarRegistry")} />
<SettingsOption title="Disable Mouse Events (requires restart)" input={this.renderToggle("disableMouseEvents")} />
Expand Down
21 changes: 18 additions & 3 deletions src/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ const defaultSettings = {
disableWMIC: false,
disableWMI: false,
disableWin32: false,
enableHDR: false,
autoDisabledWMI: false,
useWin32Event: true,
useElectronEvents: true,
Expand Down Expand Up @@ -1875,7 +1876,12 @@ let ignoreBrightnessEventTimeout = false
function updateBrightness(index, newLevel, useCap = true, vcpValue = "brightness", clearTransition = true) {
try {
let level = newLevel
let vcp = (vcpValue === "brightness" ? "brightness" : `0x${parseInt(vcpValue).toString(16)}`)
let vcp = "brightness"
switch(vcpValue) {
case "brightness": vcp = "brightness"; break;
case "sdr": vcp = "sdr"; break;
default: vcp = `0x${parseInt(vcpValue).toString(16)}`;
}

let monitor = false
if (typeof index == "string" && index * 1 != index) {
Expand Down Expand Up @@ -1909,9 +1915,15 @@ function updateBrightness(index, newLevel, useCap = true, vcpValue = "brightness
return false
}

const normalized = normalizeBrightness(level, false, (useCap ? monitor.min : 0), (useCap ? monitor.max : 100))
const normalized = normalizeBrightness(level, false, 0, 100)

if (monitor.type == "ddcci") {
if (vcp === "sdr") {
monitorsThread.send({
type: "sdr",
brightness: normalized,
id: monitor.id
})
} else if (monitor.type == "ddcci") {
if (vcp === "brightness") {
monitor.brightness = level
monitor.brightnessRaw = normalized
Expand Down Expand Up @@ -2295,6 +2307,9 @@ ipcMain.on('sleep-display', (e, hwid) => turnOffDisplayDDC(hwid, true))
ipcMain.on('set-vcp', (e, values) => {
updateBrightnessThrottle(values.monitor, values.value, false, true, values.code)
})
ipcMain.on('set-sdr-brightness', (e, values) => {
updateBrightnessThrottle(values.monitor, values.value, false, true, "sdr")
})

ipcMain.on('get-window-history', () => sendToAllWindows('window-history', windowHistory))

Expand Down
5 changes: 5 additions & 0 deletions src/modules/windows-hdr/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
*.log*
build
.vscode/ipch
.history
18 changes: 18 additions & 0 deletions src/modules/windows-hdr/binding.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"targets": [
{
"target_name": "windows-hdr",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"conditions": [
["OS=='win'", {
"sources": [ "windows-hdr.cc" ]
}],
],
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"
],
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
}
]
}
6 changes: 6 additions & 0 deletions src/modules/windows-hdr/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use strict";
const addon = require("bindings")("windows-hdr");
module.exports = {
getDisplays: addon.getDisplays,
setSDRBrightness: addon.setSDRBrightness
}
25 changes: 25 additions & 0 deletions src/modules/windows-hdr/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "windows-hdr",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npm run rebuild",
"rebuild": "node-gyp rebuild",
"install": "npm run rebuild"
},
"keywords": [],
"author": "xanderfrangos",
"license": "MIT",
"bugs": {},
"homepage": "",
"dependencies": {
"bindings": "1.5.0",
"node-addon-api": "^7.0.0"
},
"files": [
"index.js",
"binding.gyp",
"windows-hdr.cc"
]
}
Loading

0 comments on commit 01766b4

Please sign in to comment.