brightctrl 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +135 -30
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,13 +12,28 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
12
12
|
import { execFile } from "node:child_process";
|
|
13
13
|
import { promisify } from "node:util";
|
|
14
14
|
var execFileAsync = promisify(execFile);
|
|
15
|
+
var isWindows = process.platform === "win32";
|
|
16
|
+
var isMac = process.platform === "darwin";
|
|
15
17
|
function ddcutil(args, timeout = 8000) {
|
|
16
18
|
return execFileAsync("ddcutil", args, {
|
|
17
19
|
timeout,
|
|
18
20
|
encoding: "utf-8"
|
|
19
21
|
}).then((r) => r.stdout);
|
|
20
22
|
}
|
|
23
|
+
function powerShell(script, timeout = 8000) {
|
|
24
|
+
return execFileAsync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], { timeout, encoding: "utf-8" }).then((r) => r.stdout.trim());
|
|
25
|
+
}
|
|
21
26
|
async function checkDdcutil() {
|
|
27
|
+
if (isWindows) {
|
|
28
|
+
try {
|
|
29
|
+
const out = await powerShell("Get-CimInstance -Namespace root/WMI -ClassName WmiMonitorBrightness | ConvertTo-Json -Depth 3", 5000);
|
|
30
|
+
return out.length > 0 && out !== "null";
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (isMac)
|
|
36
|
+
return false;
|
|
22
37
|
try {
|
|
23
38
|
await execFileAsync("which", ["ddcutil"]);
|
|
24
39
|
return true;
|
|
@@ -26,7 +41,7 @@ async function checkDdcutil() {
|
|
|
26
41
|
return false;
|
|
27
42
|
}
|
|
28
43
|
}
|
|
29
|
-
async function
|
|
44
|
+
async function detectMonitorsLinux() {
|
|
30
45
|
const stdout = await ddcutil(["detect", "--brief"], 15000);
|
|
31
46
|
const monitors = [];
|
|
32
47
|
let current = null;
|
|
@@ -37,8 +52,9 @@ async function detectMonitors() {
|
|
|
37
52
|
if (current?.index != null)
|
|
38
53
|
monitors.push(current);
|
|
39
54
|
const m = t.match(/Display\s+(\d+)/);
|
|
55
|
+
const idxStr = m?.[1];
|
|
40
56
|
current = {
|
|
41
|
-
index:
|
|
57
|
+
index: idxStr ? Number.parseInt(idxStr, 10) : monitors.length + 1,
|
|
42
58
|
name: "Unknown Monitor",
|
|
43
59
|
bus: ""
|
|
44
60
|
};
|
|
@@ -56,16 +72,64 @@ async function detectMonitors() {
|
|
|
56
72
|
monitors.push(current);
|
|
57
73
|
return monitors;
|
|
58
74
|
}
|
|
59
|
-
async function
|
|
75
|
+
async function detectMonitorsWindows() {
|
|
76
|
+
const ps = `$b=Get-CimInstance -Namespace root/WMI -ClassName WmiMonitorBrightness; $r=@(); $i=0; foreach($m in $b){$i++; $r+=[PSCustomObject]@{index=$i;name=[string]($m.InstanceName -replace '.*\\\\([^\\\\]+)\\\\.*','$1');bus=$m.InstanceName}}; $r | ConvertTo-Json -Depth 3`;
|
|
77
|
+
const stdout = await powerShell(ps, 1e4);
|
|
78
|
+
if (!stdout || stdout === "null")
|
|
79
|
+
return [];
|
|
80
|
+
const data = JSON.parse(stdout);
|
|
81
|
+
const arr = Array.isArray(data) ? data : [data];
|
|
82
|
+
return arr.map((d, i) => ({
|
|
83
|
+
index: i + 1,
|
|
84
|
+
name: typeof d.name === "string" && d.name ? d.name : "Monitor",
|
|
85
|
+
bus: typeof d.bus === "string" ? d.bus : ""
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
async function detectMonitorsMac() {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
async function getBrightnessMac(_displayIndex) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
async function setBrightnessMac(_displayIndex, _value) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
async function detectMonitors() {
|
|
98
|
+
if (isWindows)
|
|
99
|
+
return detectMonitorsWindows();
|
|
100
|
+
if (isMac)
|
|
101
|
+
return detectMonitorsMac();
|
|
102
|
+
return detectMonitorsLinux();
|
|
103
|
+
}
|
|
104
|
+
async function getBrightnessLinux(displayIndex) {
|
|
60
105
|
try {
|
|
61
106
|
const stdout = await ddcutil(["getvcp", "10", `--display=${displayIndex}`], 5000);
|
|
62
107
|
const m = stdout.match(/current value\s*=\s*(\d+)/);
|
|
63
|
-
|
|
108
|
+
const val = m?.[1];
|
|
109
|
+
return val ? Number.parseInt(val, 10) : null;
|
|
64
110
|
} catch {
|
|
65
111
|
return null;
|
|
66
112
|
}
|
|
67
113
|
}
|
|
68
|
-
async function
|
|
114
|
+
async function getBrightnessWindows(displayIndex) {
|
|
115
|
+
try {
|
|
116
|
+
const idx = Math.max(0, displayIndex - 1);
|
|
117
|
+
const ps = `$b=Get-CimInstance -Namespace root/WMI -ClassName WmiMonitorBrightness; if($b -and $b.Count -ge ${idx + 1}){$b[${idx}].CurrentBrightness}else{-1}`;
|
|
118
|
+
const stdout = await powerShell(ps, 5000);
|
|
119
|
+
const v = Number.parseInt(stdout, 10);
|
|
120
|
+
return Number.isNaN(v) || v < 0 ? null : v;
|
|
121
|
+
} catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function getBrightness(displayIndex) {
|
|
126
|
+
if (isWindows)
|
|
127
|
+
return getBrightnessWindows(displayIndex);
|
|
128
|
+
if (isMac)
|
|
129
|
+
return getBrightnessMac(displayIndex);
|
|
130
|
+
return getBrightnessLinux(displayIndex);
|
|
131
|
+
}
|
|
132
|
+
async function setBrightnessLinux(displayIndex, value) {
|
|
69
133
|
try {
|
|
70
134
|
await ddcutil(["setvcp", "10", String(Math.round(value)), `--display=${displayIndex}`], 5000);
|
|
71
135
|
return true;
|
|
@@ -73,9 +137,26 @@ async function setBrightness(displayIndex, value) {
|
|
|
73
137
|
return false;
|
|
74
138
|
}
|
|
75
139
|
}
|
|
140
|
+
async function setBrightnessWindows(displayIndex, value) {
|
|
141
|
+
try {
|
|
142
|
+
const idx = Math.max(0, displayIndex - 1);
|
|
143
|
+
const ps = `$m=Get-CimInstance -Namespace root/WMI -ClassName WmiMonitorBrightnessMethods; if($m -and $m.Count -ge ${idx + 1}){$m[${idx}].WmiSetBrightness(1,${Math.round(value)})}`;
|
|
144
|
+
await powerShell(ps, 5000);
|
|
145
|
+
return true;
|
|
146
|
+
} catch {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function setBrightness(displayIndex, value) {
|
|
151
|
+
if (isWindows)
|
|
152
|
+
return setBrightnessWindows(displayIndex, value);
|
|
153
|
+
if (isMac)
|
|
154
|
+
return setBrightnessMac(displayIndex, value);
|
|
155
|
+
return setBrightnessLinux(displayIndex, value);
|
|
156
|
+
}
|
|
76
157
|
|
|
77
158
|
// src/app.tsx
|
|
78
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
159
|
+
import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
|
|
79
160
|
function BrightnessBar({
|
|
80
161
|
value,
|
|
81
162
|
width = 25
|
|
@@ -152,6 +233,9 @@ function MonitorCard({
|
|
|
152
233
|
}, undefined, true, undefined, this);
|
|
153
234
|
}
|
|
154
235
|
function ErrorPanel() {
|
|
236
|
+
const plat = process.platform;
|
|
237
|
+
if (plat === "darwin")
|
|
238
|
+
return null;
|
|
155
239
|
return /* @__PURE__ */ jsxDEV(Box, {
|
|
156
240
|
flexDirection: "column",
|
|
157
241
|
marginTop: 1,
|
|
@@ -160,26 +244,41 @@ function ErrorPanel() {
|
|
|
160
244
|
color: "yellow",
|
|
161
245
|
children: "Troubleshooting:"
|
|
162
246
|
}, undefined, false, undefined, this),
|
|
163
|
-
/* @__PURE__ */ jsxDEV(
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}, undefined,
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
247
|
+
plat === "win32" ? /* @__PURE__ */ jsxDEV(Fragment, {
|
|
248
|
+
children: [
|
|
249
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
250
|
+
color: "gray",
|
|
251
|
+
children: "Some GPUs/monitors don't expose brightness via WMI."
|
|
252
|
+
}, undefined, false, undefined, this),
|
|
253
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
254
|
+
color: "gray",
|
|
255
|
+
children: "Try installing MonitorController from Windows Store."
|
|
256
|
+
}, undefined, false, undefined, this)
|
|
257
|
+
]
|
|
258
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV(Fragment, {
|
|
259
|
+
children: [
|
|
260
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
261
|
+
color: "gray",
|
|
262
|
+
children: " sudo pacman -S ddcutil"
|
|
263
|
+
}, undefined, false, undefined, this),
|
|
264
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
265
|
+
color: "gray",
|
|
266
|
+
children: " sudo usermod -aG i2c $USER"
|
|
267
|
+
}, undefined, false, undefined, this),
|
|
268
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
269
|
+
color: "gray",
|
|
270
|
+
children: " sudo modprobe i2c-dev"
|
|
271
|
+
}, undefined, false, undefined, this),
|
|
272
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
273
|
+
color: "gray",
|
|
274
|
+
children: "echo 'i2c-dev' | sudo tee /etc/modules-load.d/i2c.conf"
|
|
275
|
+
}, undefined, false, undefined, this),
|
|
276
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
277
|
+
color: "gray",
|
|
278
|
+
children: " (log out and in for group change)"
|
|
279
|
+
}, undefined, false, undefined, this)
|
|
280
|
+
]
|
|
281
|
+
}, undefined, true, undefined, this)
|
|
183
282
|
]
|
|
184
283
|
}, undefined, true, undefined, this);
|
|
185
284
|
}
|
|
@@ -211,10 +310,16 @@ function App() {
|
|
|
211
310
|
setLoading(true);
|
|
212
311
|
setError(null);
|
|
213
312
|
setStatus("Checking ddcutil...");
|
|
214
|
-
const
|
|
215
|
-
if (!
|
|
216
|
-
|
|
217
|
-
|
|
313
|
+
const hasBackend = await checkDdcutil();
|
|
314
|
+
if (!hasBackend) {
|
|
315
|
+
if (process.platform === "win32") {
|
|
316
|
+
setError("No monitors with WMI brightness control found");
|
|
317
|
+
} else if (process.platform === "darwin") {
|
|
318
|
+
setError("macOS is not supported at this moment");
|
|
319
|
+
} else {
|
|
320
|
+
setError("ddcutil not found. Install: sudo pacman -S ddcutil");
|
|
321
|
+
}
|
|
322
|
+
setStatus("backend unavailable");
|
|
218
323
|
setLoading(false);
|
|
219
324
|
return;
|
|
220
325
|
}
|