manageos 2.3.0 → 2.3.1
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/Android/adb.d.ts +221 -0
- package/dist/Android/adb.d.ts.map +1 -0
- package/dist/Android/adb.js +1150 -0
- package/dist/Android/adb.js.map +1 -0
- package/dist/Android/dependencies/AdbWinApi.dll +0 -0
- package/dist/Android/dependencies/AdbWinUsbApi.dll +0 -0
- package/dist/Android/dependencies/adb.exe +0 -0
- package/dist/Android/dependencies/cmd-here.exe +0 -0
- package/dist/Android/dependencies/fastboot.exe +0 -0
- package/dist/Android/fastboot.d.ts +48 -0
- package/dist/Android/fastboot.d.ts.map +1 -0
- package/dist/Android/fastboot.js +173 -0
- package/dist/Android/fastboot.js.map +1 -0
- package/dist/Android/index.d.ts +7 -0
- package/dist/Android/index.d.ts.map +1 -0
- package/dist/Android/index.js +7 -0
- package/dist/Android/index.js.map +1 -0
- package/dist/Mouse/index.d.ts +38 -0
- package/dist/Mouse/index.d.ts.map +1 -0
- package/dist/Mouse/index.js +165 -0
- package/dist/Mouse/index.js.map +1 -0
- package/dist/Mouse/mouse.exe +0 -0
- package/dist/PsExec/dependencies/PsExec.exe +0 -0
- package/dist/PsExec/dependencies/PsExec64.exe +0 -0
- package/dist/PsExec/dependencies/PsGetsid.exe +0 -0
- package/dist/PsExec/dependencies/PsGetsid64.exe +0 -0
- package/dist/PsExec/dependencies/PsInfo.exe +0 -0
- package/dist/PsExec/dependencies/PsInfo64.exe +0 -0
- package/dist/PsExec/dependencies/psfile.exe +0 -0
- package/dist/PsExec/index.d.ts +11 -0
- package/dist/PsExec/index.d.ts.map +1 -0
- package/dist/PsExec/index.js +11 -0
- package/dist/PsExec/index.js.map +1 -0
- package/dist/PsExec/psexec.d.ts +39 -0
- package/dist/PsExec/psexec.d.ts.map +1 -0
- package/dist/PsExec/psexec.js +118 -0
- package/dist/PsExec/psexec.js.map +1 -0
- package/dist/PsExec/psfile.d.ts +30 -0
- package/dist/PsExec/psfile.d.ts.map +1 -0
- package/dist/PsExec/psfile.js +92 -0
- package/dist/PsExec/psfile.js.map +1 -0
- package/dist/PsExec/psgetsid.d.ts +29 -0
- package/dist/PsExec/psgetsid.d.ts.map +1 -0
- package/dist/PsExec/psgetsid.js +85 -0
- package/dist/PsExec/psgetsid.js.map +1 -0
- package/dist/PsExec/psinfo.d.ts +33 -0
- package/dist/PsExec/psinfo.d.ts.map +1 -0
- package/dist/PsExec/psinfo.js +101 -0
- package/dist/PsExec/psinfo.js.map +1 -0
- package/dist/antivirus.d.ts +23 -0
- package/dist/antivirus.d.ts.map +1 -0
- package/dist/antivirus.js +124 -0
- package/dist/antivirus.js.map +1 -0
- package/dist/audio.d.ts +38 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/audio.js +172 -0
- package/dist/audio.js.map +1 -0
- package/dist/auditpolicy.d.ts +24 -0
- package/dist/auditpolicy.d.ts.map +1 -0
- package/dist/auditpolicy.js +115 -0
- package/dist/auditpolicy.js.map +1 -0
- package/dist/bitlocker.d.ts +43 -0
- package/dist/bitlocker.d.ts.map +1 -0
- package/dist/bitlocker.js +212 -0
- package/dist/bitlocker.js.map +1 -0
- package/dist/camera.d.ts +34 -0
- package/dist/camera.d.ts.map +1 -0
- package/dist/camera.js +172 -0
- package/dist/camera.js.map +1 -0
- package/dist/certificates.d.ts +30 -0
- package/dist/certificates.d.ts.map +1 -0
- package/dist/certificates.js +143 -0
- package/dist/certificates.js.map +1 -0
- package/dist/clipboard.d.ts +16 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +50 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/encryption.d.ts +16 -0
- package/dist/encryption.d.ts.map +1 -0
- package/dist/encryption.js +47 -0
- package/dist/encryption.js.map +1 -0
- package/dist/eventlogs.d.ts +34 -0
- package/dist/eventlogs.d.ts.map +1 -0
- package/dist/eventlogs.js +125 -0
- package/dist/eventlogs.js.map +1 -0
- package/dist/filesystem.d.ts +30 -0
- package/dist/filesystem.d.ts.map +1 -0
- package/dist/filesystem.js +150 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/firewall.d.ts +39 -0
- package/dist/firewall.d.ts.map +1 -0
- package/dist/firewall.js +113 -0
- package/dist/firewall.js.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/dist/localization.d.ts +22 -0
- package/dist/localization.d.ts.map +1 -0
- package/dist/localization.js +102 -0
- package/dist/localization.js.map +1 -0
- package/dist/microphone.d.ts +39 -0
- package/dist/microphone.d.ts.map +1 -0
- package/dist/microphone.js +94 -0
- package/dist/microphone.js.map +1 -0
- package/dist/msconfig.d.ts +32 -0
- package/dist/msconfig.d.ts.map +1 -0
- package/dist/msconfig.js +192 -0
- package/dist/msconfig.js.map +1 -0
- package/dist/network.d.ts +82 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +349 -0
- package/dist/network.js.map +1 -0
- package/dist/notification.d.ts +81 -0
- package/dist/notification.d.ts.map +1 -0
- package/dist/notification.js +140 -0
- package/dist/notification.js.map +1 -0
- package/dist/power.d.ts +18 -0
- package/dist/power.d.ts.map +1 -0
- package/dist/power.js +62 -0
- package/dist/power.js.map +1 -0
- package/dist/printer.d.ts +51 -0
- package/dist/printer.d.ts.map +1 -0
- package/dist/printer.js +170 -0
- package/dist/printer.js.map +1 -0
- package/dist/regedit.d.ts +11 -0
- package/dist/regedit.d.ts.map +1 -0
- package/dist/regedit.js +57 -0
- package/dist/regedit.js.map +1 -0
- package/dist/scheduler.d.ts +39 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +116 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/screen.d.ts +234 -0
- package/dist/screen.d.ts.map +1 -0
- package/dist/screen.js +942 -0
- package/dist/screen.js.map +1 -0
- package/dist/secpol.d.ts +22 -0
- package/dist/secpol.d.ts.map +1 -0
- package/dist/secpol.js +88 -0
- package/dist/secpol.js.map +1 -0
- package/dist/services.d.ts +60 -0
- package/dist/services.d.ts.map +1 -0
- package/dist/services.js +286 -0
- package/dist/services.js.map +1 -0
- package/dist/shell.d.ts +49 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +212 -0
- package/dist/shell.js.map +1 -0
- package/dist/systeminfo.d.ts +19 -0
- package/dist/systeminfo.d.ts.map +1 -0
- package/dist/systeminfo.js +19 -0
- package/dist/systeminfo.js.map +1 -0
- package/dist/taskmgr.d.ts +29 -0
- package/dist/taskmgr.d.ts.map +1 -0
- package/dist/taskmgr.js +167 -0
- package/dist/taskmgr.js.map +1 -0
- package/dist/taskscheduler.d.ts +58 -0
- package/dist/taskscheduler.d.ts.map +1 -0
- package/dist/taskscheduler.js +332 -0
- package/dist/taskscheduler.js.map +1 -0
- package/dist/uac.d.ts +28 -0
- package/dist/uac.d.ts.map +1 -0
- package/dist/uac.js +66 -0
- package/dist/uac.js.map +1 -0
- package/dist/usb.d.ts +29 -0
- package/dist/usb.d.ts.map +1 -0
- package/dist/usb.js +161 -0
- package/dist/usb.js.map +1 -0
- package/dist/users.d.ts +62 -0
- package/dist/users.d.ts.map +1 -0
- package/dist/users.js +320 -0
- package/dist/users.js.map +1 -0
- package/dist/windowsupdate.d.ts +26 -0
- package/dist/windowsupdate.d.ts.map +1 -0
- package/dist/windowsupdate.js +120 -0
- package/dist/windowsupdate.js.map +1 -0
- package/package.json +1 -1
package/dist/screen.js
ADDED
|
@@ -0,0 +1,942 @@
|
|
|
1
|
+
import { getCurrentResolution, getAvailableResolution, getCurrentDisplayMode, getAvailableDisplayMode, } from "win-screen-resolution";
|
|
2
|
+
import si from "systeminformation";
|
|
3
|
+
import screenshot from "screenshot-desktop";
|
|
4
|
+
import { exec } from "child_process";
|
|
5
|
+
export default class Screen {
|
|
6
|
+
static rotationHistory = [];
|
|
7
|
+
static resolutionHistory = [];
|
|
8
|
+
// --- Propiedad auxiliar para capturas/comparaciones ---
|
|
9
|
+
static lastScreenshotBuffer = null;
|
|
10
|
+
// 1) Obtener serial del monitor (si está disponible)
|
|
11
|
+
static async getMonitorSerial(displayIndex = 0) {
|
|
12
|
+
const g = await si.graphics();
|
|
13
|
+
return g.displays[displayIndex]?.serial || null;
|
|
14
|
+
}
|
|
15
|
+
// 2) Obtener fabricante del monitor (manufacturer)
|
|
16
|
+
static async getManufacturer(displayIndex = 0) {
|
|
17
|
+
const g = await si.graphics();
|
|
18
|
+
const model = g.displays[displayIndex]?.model;
|
|
19
|
+
if (!model)
|
|
20
|
+
return null;
|
|
21
|
+
// Ejemplo simple: extraer palabra inicial del modelo
|
|
22
|
+
return model.split(" ")[0];
|
|
23
|
+
}
|
|
24
|
+
// 3) Buscar índice de monitor por nombre/modelo (first match)
|
|
25
|
+
static async getMonitorIndexByName(name) {
|
|
26
|
+
const g = await si.graphics();
|
|
27
|
+
const idx = g.displays.findIndex((d) => (d.model || "").toLowerCase().includes(name.toLowerCase()));
|
|
28
|
+
return idx >= 0 ? idx : null;
|
|
29
|
+
}
|
|
30
|
+
// 4) Comprobar si la orientación actual es portrait para un display (usa resolución)
|
|
31
|
+
static async isOrientationPortrait(displayIndex = 0) {
|
|
32
|
+
const g = await si.graphics();
|
|
33
|
+
const d = g.displays[displayIndex];
|
|
34
|
+
if (!d ||
|
|
35
|
+
typeof d.currentResX !== "number" ||
|
|
36
|
+
typeof d.currentResY !== "number")
|
|
37
|
+
return null;
|
|
38
|
+
return d.currentResY > d.currentResX;
|
|
39
|
+
}
|
|
40
|
+
// 5) Area total en píxeles combinada (suma width*height de cada display)
|
|
41
|
+
static async getTotalScreenArea() {
|
|
42
|
+
const g = await si.graphics();
|
|
43
|
+
return g.displays.reduce((acc, d) => {
|
|
44
|
+
const w = d.currentResX || 0;
|
|
45
|
+
const h = d.currentResY || 0;
|
|
46
|
+
return acc + w * h;
|
|
47
|
+
}, 0);
|
|
48
|
+
}
|
|
49
|
+
// 6) Resolución combinada (bounding box) - total ancho máximo x suma de alturas (approx)
|
|
50
|
+
static async getCombinedResolution() {
|
|
51
|
+
const g = await si.graphics();
|
|
52
|
+
const width = g.displays.reduce((m, d) => Math.max(m, d.currentResX || 0), 0);
|
|
53
|
+
const height = g.displays.reduce((s, d) => s + (d.currentResY || 0), 0);
|
|
54
|
+
return { width, height };
|
|
55
|
+
}
|
|
56
|
+
// 7) Normalizar una resolución a la más cercana soportada (devuelve la resolución soportada más parecida)
|
|
57
|
+
static normalizeToSupportedResolution(width, height) {
|
|
58
|
+
const all = this.getAllResolutions();
|
|
59
|
+
if (!all.length)
|
|
60
|
+
return null;
|
|
61
|
+
let best = all[0];
|
|
62
|
+
let bestDist = Math.abs(best.width - width) + Math.abs(best.height - height);
|
|
63
|
+
for (const r of all) {
|
|
64
|
+
const d = Math.abs(r.width - width) + Math.abs(r.height - height);
|
|
65
|
+
if (d < bestDist) {
|
|
66
|
+
bestDist = d;
|
|
67
|
+
best = r;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { width: best.width, height: best.height };
|
|
71
|
+
}
|
|
72
|
+
// 8) Sugerir porcentaje de escala (DPI) aproximado para un PPI objetivo
|
|
73
|
+
static async suggestScaleForPPI(targetPpi) {
|
|
74
|
+
const ppi = await this.getPPI();
|
|
75
|
+
if (!ppi)
|
|
76
|
+
return null;
|
|
77
|
+
// Windows scale roughly: scale% = (target / actual) * 100
|
|
78
|
+
const scale = Math.round((targetPpi / ppi) * 100);
|
|
79
|
+
// limitar entre 100 y 400
|
|
80
|
+
return Math.min(400, Math.max(100, scale));
|
|
81
|
+
}
|
|
82
|
+
// 9) Tamaño físico aproximado en pulgadas (width, height, diagonal) para un display
|
|
83
|
+
static async getPhysicalSizeInInches(displayIndex = 0) {
|
|
84
|
+
const g = await si.graphics();
|
|
85
|
+
const d = g.displays[displayIndex];
|
|
86
|
+
if (!d || typeof d.sizeX !== "number" || typeof d.sizeY !== "number")
|
|
87
|
+
return null;
|
|
88
|
+
const widthIn = d.sizeX;
|
|
89
|
+
const heightIn = d.sizeY;
|
|
90
|
+
const diagonalIn = Math.sqrt(widthIn * widthIn + heightIn * heightIn);
|
|
91
|
+
return { widthIn, heightIn, diagonalIn };
|
|
92
|
+
}
|
|
93
|
+
// 10) Formatear resolución como string "WIDTHxHEIGHT"
|
|
94
|
+
static formatResolution(width, height) {
|
|
95
|
+
return `${width}x${height}`;
|
|
96
|
+
}
|
|
97
|
+
// 11) Encontrar refresh rate disponible más cercano al solicitado
|
|
98
|
+
static findClosestRefreshRate(targetHz, displayIndex = 0) {
|
|
99
|
+
const rates = this.getAvailableRefreshRates(displayIndex);
|
|
100
|
+
if (!rates.length)
|
|
101
|
+
return null;
|
|
102
|
+
let best = rates[0];
|
|
103
|
+
let bestDiff = Math.abs(best - targetHz);
|
|
104
|
+
for (const r of rates) {
|
|
105
|
+
const d = Math.abs(r - targetHz);
|
|
106
|
+
if (d < bestDiff) {
|
|
107
|
+
bestDiff = d;
|
|
108
|
+
best = r;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return best;
|
|
112
|
+
}
|
|
113
|
+
// 12) Comprobar si una resolución está soportada por cualquier display
|
|
114
|
+
static isResolutionSupportedOnAnyDisplay(width, height) {
|
|
115
|
+
return this.getAllResolutions().some((r) => r.width === width && r.height === height);
|
|
116
|
+
}
|
|
117
|
+
// 13) Establecer resolución temporal por una duración (ms) y luego restaurar
|
|
118
|
+
static setTemporaryResolution(width, height, durationMs) {
|
|
119
|
+
const prev = this.getCurrentResolution();
|
|
120
|
+
this.setResolutionSafe(width, height);
|
|
121
|
+
const id = setTimeout(() => {
|
|
122
|
+
this.setResolutionSafe(prev.width, prev.height);
|
|
123
|
+
}, durationMs);
|
|
124
|
+
// @ts-ignore
|
|
125
|
+
return id;
|
|
126
|
+
}
|
|
127
|
+
// 14) Vigilar cambios de brillo y ejecutar callback (devuelve id)
|
|
128
|
+
static watchBrightnessChange(callback, interval = 2000) {
|
|
129
|
+
let last = null;
|
|
130
|
+
const id = setInterval(async () => {
|
|
131
|
+
const b = await this.getBrightness();
|
|
132
|
+
if (b !== last) {
|
|
133
|
+
last = b;
|
|
134
|
+
callback(b);
|
|
135
|
+
}
|
|
136
|
+
}, interval);
|
|
137
|
+
// @ts-ignore
|
|
138
|
+
return id;
|
|
139
|
+
}
|
|
140
|
+
// 15) Captura y compara con la última captura (simple diff por bytes) -> devuelve % distinto
|
|
141
|
+
static async captureAndCompareLast() {
|
|
142
|
+
try {
|
|
143
|
+
const buf = await screenshot();
|
|
144
|
+
if (!buf)
|
|
145
|
+
return null;
|
|
146
|
+
if (!this.lastScreenshotBuffer) {
|
|
147
|
+
this.lastScreenshotBuffer = buf;
|
|
148
|
+
return { diffPercent: 100 };
|
|
149
|
+
}
|
|
150
|
+
const a = this.lastScreenshotBuffer;
|
|
151
|
+
const b = buf;
|
|
152
|
+
const len = Math.min(a.length, b.length);
|
|
153
|
+
let diff = 0;
|
|
154
|
+
for (let i = 0; i < len; i++)
|
|
155
|
+
if (a[i] !== b[i])
|
|
156
|
+
diff++;
|
|
157
|
+
// si tamaños diferentes, contar la diferencia restante
|
|
158
|
+
diff += Math.abs(a.length - b.length);
|
|
159
|
+
const denom = Math.max(a.length, b.length) || 1;
|
|
160
|
+
const percent = (diff / denom) * 100;
|
|
161
|
+
this.lastScreenshotBuffer = buf;
|
|
162
|
+
return { diffPercent: percent };
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// 16) Guardar última captura en disco (si existe), o capturar y guardar
|
|
169
|
+
static async saveLastScreenshotTo(path) {
|
|
170
|
+
const fs = require("fs");
|
|
171
|
+
try {
|
|
172
|
+
if (!this.lastScreenshotBuffer) {
|
|
173
|
+
this.lastScreenshotBuffer = (await screenshot());
|
|
174
|
+
}
|
|
175
|
+
fs.writeFileSync(path, this.lastScreenshotBuffer);
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 17) Listar displays agrupados por tipo de conexión (HDMI/DP/VGA/unknown)
|
|
183
|
+
static async listDisplaysByConnectionType() {
|
|
184
|
+
const g = await si.graphics();
|
|
185
|
+
const map = new Map();
|
|
186
|
+
g.displays.forEach((d) => {
|
|
187
|
+
const key = d.connection && d.connection !== "" ? d.connection : "unknown";
|
|
188
|
+
if (!map.has(key))
|
|
189
|
+
map.set(key, []);
|
|
190
|
+
map.get(key).push(d);
|
|
191
|
+
});
|
|
192
|
+
return Array.from(map.entries()).map(([connection, displays]) => ({
|
|
193
|
+
connection,
|
|
194
|
+
displays,
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
static async getDisplayByUUID(displayIndex = 0) {
|
|
198
|
+
const g = await si.graphics();
|
|
199
|
+
const d = g.displays[displayIndex];
|
|
200
|
+
if (!d)
|
|
201
|
+
return null;
|
|
202
|
+
return d.uuid || `${d.model || "display"}-${displayIndex}`;
|
|
203
|
+
}
|
|
204
|
+
// 19) Promedio de PPI entre todos los displays (si se puede calcular)
|
|
205
|
+
static async getAveragePPIAcrossDisplays() {
|
|
206
|
+
const g = await si.graphics();
|
|
207
|
+
const ppis = [];
|
|
208
|
+
for (const d of g.displays) {
|
|
209
|
+
if (typeof d.currentResX === "number" &&
|
|
210
|
+
typeof d.currentResY === "number" &&
|
|
211
|
+
typeof d.sizeX === "number" &&
|
|
212
|
+
typeof d.sizeY === "number") {
|
|
213
|
+
const diagPx = Math.sqrt(d.currentResX * d.currentResX + d.currentResY * d.currentResY);
|
|
214
|
+
const diagIn = Math.sqrt(d.sizeX * d.sizeX + d.sizeY * d.sizeY);
|
|
215
|
+
if (diagIn > 0)
|
|
216
|
+
ppis.push(diagPx / diagIn);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!ppis.length)
|
|
220
|
+
return null;
|
|
221
|
+
return ppis.reduce((a, b) => a + b, 0) / ppis.length;
|
|
222
|
+
}
|
|
223
|
+
// --- 20 métodos nuevos (no repetidos) ---
|
|
224
|
+
// 1) Listar modelos de monitores (únicos)
|
|
225
|
+
static async listMonitorModels() {
|
|
226
|
+
const g = await si.graphics();
|
|
227
|
+
const models = g.displays.map((d) => (d.model || "unknown").trim());
|
|
228
|
+
return Array.from(new Set(models));
|
|
229
|
+
}
|
|
230
|
+
// 2) Obtener índices válidos de displays [0,1,2,...]
|
|
231
|
+
static async getDisplayIndexes() {
|
|
232
|
+
const g = await si.graphics();
|
|
233
|
+
return g.displays.map((_, i) => i);
|
|
234
|
+
}
|
|
235
|
+
// 3) Buscar índice de display por serial (si existe) - usa cast a any para seriales no tipadas
|
|
236
|
+
static async findDisplayBySerial(serial) {
|
|
237
|
+
const g = await si.graphics();
|
|
238
|
+
const idx = g.displays.findIndex((d) => (d.serial || "").toString() === serial);
|
|
239
|
+
return idx >= 0 ? idx : null;
|
|
240
|
+
}
|
|
241
|
+
// 4) Comprobar si un display es el primario (por índice)
|
|
242
|
+
static async isDisplayPrimary(displayIndex = 0) {
|
|
243
|
+
const g = await si.graphics();
|
|
244
|
+
return !!g.displays[displayIndex]?.main;
|
|
245
|
+
}
|
|
246
|
+
// 5) Activar/desactivar Night Light (stub — suele requerir Windows API o utilidades)
|
|
247
|
+
static async toggleNightLight(enable) {
|
|
248
|
+
console.warn("toggleNightLight: implementación completa requiere APIs de Windows. Este método es un stub.");
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
// 6) Programar Night Light entre horas (devuelve id para cancelar)
|
|
252
|
+
static scheduleNightLight(onHour, offHour, checkIntervalMs = 60000) {
|
|
253
|
+
const id = setInterval(async () => {
|
|
254
|
+
const h = new Date().getHours();
|
|
255
|
+
const shouldBeOn = onHour <= offHour
|
|
256
|
+
? h >= onHour && h < offHour
|
|
257
|
+
: h >= onHour || h < offHour;
|
|
258
|
+
await this.toggleNightLight(shouldBeOn);
|
|
259
|
+
}, checkIntervalMs);
|
|
260
|
+
// @ts-ignore
|
|
261
|
+
this._nightLightScheduleId = id;
|
|
262
|
+
// @ts-ignore
|
|
263
|
+
return id;
|
|
264
|
+
}
|
|
265
|
+
// 7) Cancelar programación de Night Light (si existiera)
|
|
266
|
+
static cancelNightLightSchedule(id) {
|
|
267
|
+
// @ts-ignore
|
|
268
|
+
const actual = id ?? this._nightLightScheduleId;
|
|
269
|
+
if (actual)
|
|
270
|
+
clearInterval(actual);
|
|
271
|
+
// @ts-ignore
|
|
272
|
+
this._nightLightScheduleId = null;
|
|
273
|
+
}
|
|
274
|
+
// 8) Obtener modos disponibles que se parezcan al display indicado (heurístico)
|
|
275
|
+
static getDisplayModesForIndex(displayIndex = 0) {
|
|
276
|
+
const display = (async () => (await si.graphics()).displays[displayIndex])();
|
|
277
|
+
// fallback: devolver todos los modos y dejar que el llamador filtre si quiere
|
|
278
|
+
return this.getAllDisplayModes();
|
|
279
|
+
}
|
|
280
|
+
// 9) Pixel count por display (currentResX * currentResY)
|
|
281
|
+
static async getPixelCountPerDisplay() {
|
|
282
|
+
const g = await si.graphics();
|
|
283
|
+
return g.displays.map((d, i) => {
|
|
284
|
+
const w = d.currentResX || 0;
|
|
285
|
+
const h = d.currentResY || 0;
|
|
286
|
+
return { index: i, pixels: w * h };
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
// 10) Total de píxeles combinados de todos los displays
|
|
290
|
+
static async getTotalPixelCount() {
|
|
291
|
+
const arr = await this.getPixelCountPerDisplay();
|
|
292
|
+
return arr.reduce((s, v) => s + v.pixels, 0);
|
|
293
|
+
}
|
|
294
|
+
// 11) Comprobar si un display soporta entrada táctil (si la info está disponible)
|
|
295
|
+
static async isTouchEnabled(displayIndex = 0) {
|
|
296
|
+
const g = await si.graphics();
|
|
297
|
+
const d = g.displays[displayIndex];
|
|
298
|
+
if (d == null)
|
|
299
|
+
return null;
|
|
300
|
+
if (typeof d.touch === "boolean")
|
|
301
|
+
return d.touch;
|
|
302
|
+
return null; // desconocido si no viene en la data
|
|
303
|
+
}
|
|
304
|
+
// 12) Apagar monitor (usa nircmd si está disponible; fallback: stub)
|
|
305
|
+
static async turnOffDisplay() {
|
|
306
|
+
return new Promise((resolve) => {
|
|
307
|
+
exec("nircmd.exe monitor off", (err) => {
|
|
308
|
+
if (err) {
|
|
309
|
+
console.warn("turnOffDisplay: nircmd no disponible o falló. Requiere herramienta externa.");
|
|
310
|
+
return resolve(false);
|
|
311
|
+
}
|
|
312
|
+
resolve(true);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
// 13) "Despertar" monitor moviendo el mouse (usa nircmd si está disponible)
|
|
317
|
+
static async wakeDisplay() {
|
|
318
|
+
return new Promise((resolve) => {
|
|
319
|
+
exec("nircmd.exe sendmouse move 1 0", (err) => {
|
|
320
|
+
if (err) {
|
|
321
|
+
console.warn("wakeDisplay: nircmd no disponible o falló. Requiere herramienta externa.");
|
|
322
|
+
return resolve(false);
|
|
323
|
+
}
|
|
324
|
+
resolve(true);
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
// 14) Establecer estado de energía del display (on = true, off = false) — wrapper
|
|
329
|
+
static async setDisplayPower(on) {
|
|
330
|
+
if (on)
|
|
331
|
+
return this.wakeDisplay();
|
|
332
|
+
return this.turnOffDisplay();
|
|
333
|
+
}
|
|
334
|
+
// 15) Rango de refresh rates soportados por display (min/max)
|
|
335
|
+
static getMonitorRefreshCapability(displayIndex = 0) {
|
|
336
|
+
const rates = this.getAvailableRefreshRates(displayIndex);
|
|
337
|
+
if (!rates.length)
|
|
338
|
+
return null;
|
|
339
|
+
return { minHz: Math.min(...rates), maxHz: Math.max(...rates) };
|
|
340
|
+
}
|
|
341
|
+
// 16) Buscar mejor modo por aspect ratio (p. ej. "16:9")
|
|
342
|
+
static findBestModeForAspectRatio(aspect) {
|
|
343
|
+
const [aw, ah] = aspect.split(":").map((s) => parseFloat(s));
|
|
344
|
+
if (!aw || !ah)
|
|
345
|
+
return null;
|
|
346
|
+
const targetRatio = aw / ah;
|
|
347
|
+
const modes = this.getAllDisplayModes();
|
|
348
|
+
if (!modes.length)
|
|
349
|
+
return null;
|
|
350
|
+
let best = null;
|
|
351
|
+
let bestDiff = Infinity;
|
|
352
|
+
for (const m of modes) {
|
|
353
|
+
const r = m.width / m.height;
|
|
354
|
+
const diff = Math.abs(r - targetRatio);
|
|
355
|
+
const score = diff * 100000 - (m.width * m.height) / 1000 - m.hz; // prefer close ratio y alta resolución/Hz
|
|
356
|
+
if (score < bestDiff) {
|
|
357
|
+
bestDiff = score;
|
|
358
|
+
best = m;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return best || null;
|
|
362
|
+
}
|
|
363
|
+
// 17) Resumen human-readable (string) de displays
|
|
364
|
+
static async formatDisplayInfoHumanReadable() {
|
|
365
|
+
const info = await this.getDisplayInfo();
|
|
366
|
+
return info
|
|
367
|
+
.map((d, i) => {
|
|
368
|
+
return `Display ${i}: ${d.model || "unknown"} — ${d.resolution} @ ${d.refreshRate || "?"}Hz — main:${!!d.main} — depth:${d.pixelDepth || "?"}`;
|
|
369
|
+
})
|
|
370
|
+
.join("\n");
|
|
371
|
+
}
|
|
372
|
+
// 18) Comparar displays por PPI (lista ordenada descendente)
|
|
373
|
+
static async compareDisplaysByPPI() {
|
|
374
|
+
const g = await si.graphics();
|
|
375
|
+
const ppis = [];
|
|
376
|
+
for (let i = 0; i < g.displays.length; i++) {
|
|
377
|
+
const d = g.displays[i];
|
|
378
|
+
if (typeof d.currentResX === "number" &&
|
|
379
|
+
typeof d.currentResY === "number" &&
|
|
380
|
+
typeof d.sizeX === "number" &&
|
|
381
|
+
typeof d.sizeY === "number") {
|
|
382
|
+
const diagPx = Math.sqrt(d.currentResX * d.currentResX + d.currentResY * d.currentResY);
|
|
383
|
+
const diagIn = Math.sqrt(d.sizeX * d.sizeX + d.sizeY * d.sizeY);
|
|
384
|
+
if (diagIn > 0)
|
|
385
|
+
ppis.push({ index: i, ppi: diagPx / diagIn });
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (!ppis.length)
|
|
389
|
+
return null;
|
|
390
|
+
return ppis.sort((a, b) => b.ppi - a.ppi);
|
|
391
|
+
}
|
|
392
|
+
// 19) Mayor intervalo (segundos) entre cambios de resolución en el historial
|
|
393
|
+
static getLongestUptimeSinceResolutionChange() {
|
|
394
|
+
if (this.resolutionHistory.length < 2)
|
|
395
|
+
return 0;
|
|
396
|
+
let best = 0;
|
|
397
|
+
for (let i = 1; i < this.resolutionHistory.length; i++) {
|
|
398
|
+
const diffSec = (this.resolutionHistory[i].timestamp -
|
|
399
|
+
this.resolutionHistory[i - 1].timestamp) /
|
|
400
|
+
1000;
|
|
401
|
+
if (diffSec > best)
|
|
402
|
+
best = diffSec;
|
|
403
|
+
}
|
|
404
|
+
return best;
|
|
405
|
+
}
|
|
406
|
+
// 20) Snapshot de la configuración actual (guarda a file con timestamp) y devuelve ruta
|
|
407
|
+
static async snapshotConfigs(saveFolder = "./") {
|
|
408
|
+
const fs = require("fs");
|
|
409
|
+
try {
|
|
410
|
+
const config = {
|
|
411
|
+
timestamp: Date.now(),
|
|
412
|
+
resolution: this.getCurrentResolution(),
|
|
413
|
+
mode: this.getCurrentDisplayMode(),
|
|
414
|
+
displays: await this.getDisplayInfo(),
|
|
415
|
+
};
|
|
416
|
+
const name = `display_snapshot_${Date.now()}.json`;
|
|
417
|
+
const path = require("path").join(saveFolder, name);
|
|
418
|
+
fs.writeFileSync(path, JSON.stringify(config, null, 2));
|
|
419
|
+
return path;
|
|
420
|
+
}
|
|
421
|
+
catch (e) {
|
|
422
|
+
console.error("snapshotConfigs error:", e);
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
// 20) Listar drivers de monitor instalados (intento con pnputil; puede fallar si no existe)
|
|
427
|
+
static async listInstalledMonitorDrivers() {
|
|
428
|
+
return new Promise((resolve) => {
|
|
429
|
+
exec(`pnputil /enum-drivers`, (err, stdout) => {
|
|
430
|
+
if (err) {
|
|
431
|
+
console.warn("listInstalledMonitorDrivers: pnputil no disponible o error.");
|
|
432
|
+
return resolve([]);
|
|
433
|
+
}
|
|
434
|
+
const blocks = stdout
|
|
435
|
+
.split(/\r?\n\r?\n/)
|
|
436
|
+
.map((b) => b.trim())
|
|
437
|
+
.filter(Boolean);
|
|
438
|
+
// extraer nombres de driver (heurístico)
|
|
439
|
+
const names = blocks.map((b) => {
|
|
440
|
+
const m = b.match(/Published Name : (.+)/i);
|
|
441
|
+
return m ? m[1].trim() : b.split(/\r?\n/)[0];
|
|
442
|
+
});
|
|
443
|
+
resolve(names);
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
static watchResolutionChangeWithHistory(interval = 1000) {
|
|
448
|
+
let lastRes = this.getCurrentResolution();
|
|
449
|
+
this.resolutionHistory.push({ ...lastRes, timestamp: Date.now() });
|
|
450
|
+
setInterval(() => {
|
|
451
|
+
const currentRes = this.getCurrentResolution();
|
|
452
|
+
if (currentRes.width !== lastRes.width ||
|
|
453
|
+
currentRes.height !== lastRes.height) {
|
|
454
|
+
lastRes = currentRes;
|
|
455
|
+
this.resolutionHistory.push({ ...currentRes, timestamp: Date.now() });
|
|
456
|
+
}
|
|
457
|
+
}, interval);
|
|
458
|
+
}
|
|
459
|
+
static getResolutionHistory() {
|
|
460
|
+
return this.resolutionHistory;
|
|
461
|
+
}
|
|
462
|
+
static async isHDRSupported() {
|
|
463
|
+
return new Promise((resolve) => {
|
|
464
|
+
const psCommand = `$hdr=$false;Get-ChildItem 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers\\Configuration' | ForEach-Object { $props=Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue; if($props -ne $null){ if($props.PSObject.Properties.Name -contains 'PrimSurfSize.cx'){$hdr=$true}}}; if($hdr){Write-Host 'true'}else{Write-Host 'false'}`;
|
|
465
|
+
exec(`powershell -Command "${psCommand}"`, (error, stdout, stderr) => {
|
|
466
|
+
if (error) {
|
|
467
|
+
resolve(false);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
resolve(stdout.trim().toLowerCase() === "true");
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
static getAverageRefreshRate() {
|
|
475
|
+
const modes = this.getAllDisplayModes();
|
|
476
|
+
if (!modes.length)
|
|
477
|
+
return 0;
|
|
478
|
+
const totalHz = modes.reduce((sum, m) => sum + m.hz, 0);
|
|
479
|
+
return totalHz / modes.length;
|
|
480
|
+
}
|
|
481
|
+
static getResolutionChangeRate() {
|
|
482
|
+
if (this.resolutionHistory.length < 2)
|
|
483
|
+
return 0;
|
|
484
|
+
const totalChanges = this.resolutionHistory.length - 1;
|
|
485
|
+
const timeSpan = (this.resolutionHistory[this.resolutionHistory.length - 1].timestamp -
|
|
486
|
+
this.resolutionHistory[0].timestamp) /
|
|
487
|
+
1000;
|
|
488
|
+
return totalChanges / timeSpan;
|
|
489
|
+
}
|
|
490
|
+
static compareRefreshRates(modeA, modeB) {
|
|
491
|
+
if (modeA.hz > modeB.hz)
|
|
492
|
+
return "A";
|
|
493
|
+
if (modeB.hz > modeA.hz)
|
|
494
|
+
return "B";
|
|
495
|
+
return "Equal";
|
|
496
|
+
}
|
|
497
|
+
static async getPPI() {
|
|
498
|
+
const displays = await si.graphics();
|
|
499
|
+
const display = displays.displays[0];
|
|
500
|
+
// Verificar que existan todos los valores necesarios y sean números
|
|
501
|
+
if (!display ||
|
|
502
|
+
typeof display.sizeX !== "number" ||
|
|
503
|
+
typeof display.sizeY !== "number" ||
|
|
504
|
+
typeof display.currentResX !== "number" ||
|
|
505
|
+
typeof display.currentResY !== "number") {
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
const diagonalPixels = Math.sqrt(Math.pow(display.currentResX, 2) + Math.pow(display.currentResY, 2));
|
|
509
|
+
const diagonalInches = Math.sqrt(Math.pow(display.sizeX, 2) + Math.pow(display.sizeY, 2));
|
|
510
|
+
return diagonalPixels / diagonalInches;
|
|
511
|
+
}
|
|
512
|
+
static setResolution(width, height) {
|
|
513
|
+
exec(`powershell -Command "Get-DisplayResolution | Format-List"`, (error, stdout, stderr) => {
|
|
514
|
+
if (error) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const matchWidth = stdout.match(/dmPelsWidth\s*:\s*(\d+)/);
|
|
518
|
+
const matchHeight = stdout.match(/dmPelsHeight\s*:\s*(\d+)/);
|
|
519
|
+
if (!matchWidth || !matchHeight) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
exec(`powershell -Command "Set-DisplayResolution -Width ${width} -Height ${height} -Force"`, (error) => { });
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
static autoResolutionByTime(dayRes, nightRes) {
|
|
526
|
+
setInterval(() => {
|
|
527
|
+
const hour = new Date().getHours();
|
|
528
|
+
if (hour >= 20 || hour < 6) {
|
|
529
|
+
this.setResolutionSafe(nightRes.w, nightRes.h);
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
this.setResolutionSafe(dayRes.w, dayRes.h);
|
|
533
|
+
}
|
|
534
|
+
}, 60000);
|
|
535
|
+
}
|
|
536
|
+
static async getPrimaryDisplay() {
|
|
537
|
+
const displays = await si.graphics();
|
|
538
|
+
return displays.displays.find((d) => d.main) || null;
|
|
539
|
+
}
|
|
540
|
+
static async getMultiMonitorInfo() {
|
|
541
|
+
const displays = await si.graphics();
|
|
542
|
+
return displays.displays.map((d) => ({
|
|
543
|
+
model: d.model,
|
|
544
|
+
resolution: `${d.currentResX}x${d.currentResY}`,
|
|
545
|
+
refreshRate: d.currentRefreshRate,
|
|
546
|
+
isMain: d.main,
|
|
547
|
+
}));
|
|
548
|
+
}
|
|
549
|
+
static exportResolutionHistoryCSV(path) {
|
|
550
|
+
const fs = require("fs");
|
|
551
|
+
const csv = this.resolutionHistory
|
|
552
|
+
.map((r) => `${r.timestamp},${r.width},${r.height}`)
|
|
553
|
+
.join("\n");
|
|
554
|
+
fs.writeFileSync(path, "timestamp,width,height\n" + csv);
|
|
555
|
+
}
|
|
556
|
+
static resetDisplaySettings() {
|
|
557
|
+
exec(`powershell -Command "DisplayReset"`, (err) => {
|
|
558
|
+
if (err)
|
|
559
|
+
console.error("Error resetting display:", err);
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
static autoResolutionByBrightness(dayRes, nightRes) {
|
|
563
|
+
setInterval(async () => {
|
|
564
|
+
const brightness = await Screen.getBrightness();
|
|
565
|
+
if (brightness !== null && brightness < 30) {
|
|
566
|
+
Screen.setResolutionSafe(nightRes.w, nightRes.h);
|
|
567
|
+
}
|
|
568
|
+
else if (brightness !== null) {
|
|
569
|
+
Screen.setResolutionSafe(dayRes.w, dayRes.h);
|
|
570
|
+
}
|
|
571
|
+
}, 10000);
|
|
572
|
+
}
|
|
573
|
+
static async getEDID(displayIndex = 0) {
|
|
574
|
+
return new Promise((resolve) => {
|
|
575
|
+
exec(`powershell -Command "Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorID | Select-Object -ExpandProperty UserFriendlyName"`, (err, stdout) => {
|
|
576
|
+
if (err)
|
|
577
|
+
return resolve(null);
|
|
578
|
+
const lines = stdout
|
|
579
|
+
.trim()
|
|
580
|
+
.split(/\r?\n/)
|
|
581
|
+
.map((l) => l.trim())
|
|
582
|
+
.filter(Boolean);
|
|
583
|
+
resolve(lines[displayIndex] ?? null);
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
// 2) Tipo de conector (HDMI/DP/VGA) - fallback con si.graphics()
|
|
588
|
+
static async getConnectorType(displayIndex = 0) {
|
|
589
|
+
const g = await si.graphics();
|
|
590
|
+
const d = g.displays[displayIndex];
|
|
591
|
+
return (d && d.connection) ?? null;
|
|
592
|
+
}
|
|
593
|
+
// 3) Listar perfiles de color instalados (sRGB, AdobeRGB, etc.)
|
|
594
|
+
static async listColorProfiles() {
|
|
595
|
+
return new Promise((resolve) => {
|
|
596
|
+
exec(`powershell -Command "Get-ChildItem 'HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ICM' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty PSChildName"`, (err, stdout) => {
|
|
597
|
+
if (err)
|
|
598
|
+
return resolve([]);
|
|
599
|
+
resolve(stdout
|
|
600
|
+
.trim()
|
|
601
|
+
.split(/\r?\n/)
|
|
602
|
+
.map((l) => l.trim())
|
|
603
|
+
.filter(Boolean));
|
|
604
|
+
});
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
// 4) Aplicar perfil de color (requiere herramienta externa o API)
|
|
608
|
+
static async applyColorProfile(profileName) {
|
|
609
|
+
// Stub: cambiar perfil de color requiere utilidades (DisplayCAL, Windows API).
|
|
610
|
+
// Aquí solo guardamos la intención.
|
|
611
|
+
console.warn("applyColorProfile: requiere implementación con herramientas nativas.");
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
// 5) Iniciar calibración de color (stub que lanza external tool)
|
|
615
|
+
static async calibrateColor() {
|
|
616
|
+
console.warn("calibrateColor: implementa con DisplayCAL o API de fabricante.");
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
// 6) Programar cambio de resolución a una hora (devuelve id para cancelar)
|
|
620
|
+
static scheduleResolutionChange(width, height, runAt) {
|
|
621
|
+
const ms = runAt.getTime() - Date.now();
|
|
622
|
+
const id = setTimeout(() => this.setResolutionWithFallback(width, height), Math.max(0, ms));
|
|
623
|
+
// @ts-ignore
|
|
624
|
+
return id;
|
|
625
|
+
}
|
|
626
|
+
// 7) Cancelar programación por id
|
|
627
|
+
static cancelScheduledChange(id) {
|
|
628
|
+
clearTimeout(id);
|
|
629
|
+
}
|
|
630
|
+
// 8) Obtener factor de escala (DPI scaling) de Windows
|
|
631
|
+
static async getScaling() {
|
|
632
|
+
return new Promise((resolve) => {
|
|
633
|
+
exec(`powershell -Command "[System.Windows.SystemParameters]::PrimaryScreenWidth; [System.Windows.SystemParameters]::PrimaryScreenHeight"`, (err, stdout) => {
|
|
634
|
+
if (err)
|
|
635
|
+
return resolve(null);
|
|
636
|
+
// No es directo; devolver null como fallback
|
|
637
|
+
resolve(null);
|
|
638
|
+
});
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
// 9) Establecer factor de escala (nota: requiere reinicio / logoff)
|
|
642
|
+
static async setScaling(scalePercent) {
|
|
643
|
+
console.warn("setScaling: cambiar DPI desde código requiere edición del registro y relogin. Implementación no trivial.");
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
// 10) Hacer mirror (clonar) todos los monitores en modo espejo
|
|
647
|
+
static async cloneDisplays() {
|
|
648
|
+
// Requiere llamadas a API nativas o DisplaySwitch.exe
|
|
649
|
+
exec(`powershell -Command "DisplaySwitch.exe /clone"`, (err) => { });
|
|
650
|
+
return true;
|
|
651
|
+
}
|
|
652
|
+
// 11) Extender escritorio a monitor específico (extend)
|
|
653
|
+
static async extendToDisplay(displayIndex = 1) {
|
|
654
|
+
// Invocar DisplaySwitch no permite elegir índice; es un stub
|
|
655
|
+
exec(`powershell -Command "DisplaySwitch.exe /extend"`, (err) => { });
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
658
|
+
// 12) Mover una ventana (por handle) a otro display (stub)
|
|
659
|
+
static moveWindowToDisplay(windowHandle, displayIndex) {
|
|
660
|
+
console.warn("moveWindowToDisplay: requiere bindings a Win32 (SetWindowPos / MonitorFromWindow).");
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
// 13) Obtener lista de refresh rates disponibles para un display
|
|
664
|
+
static getAvailableRefreshRates(displayIndex = 0) {
|
|
665
|
+
const modes = this.getAllDisplayModes().filter((m, i) => true);
|
|
666
|
+
const rates = Array.from(new Set(modes.map((m) => m.hz))).sort((a, b) => a - b);
|
|
667
|
+
return rates;
|
|
668
|
+
}
|
|
669
|
+
// 14) Ajustar gamma (simple wrapper, necesita herramienta externa)
|
|
670
|
+
static setGamma(r, g, b) {
|
|
671
|
+
console.warn("setGamma: implementar con API nativa (SetDeviceGammaRamp) o tool externa.");
|
|
672
|
+
}
|
|
673
|
+
// 15) Obtener gamma actual (stub)
|
|
674
|
+
static getGamma() {
|
|
675
|
+
console.warn("getGamma: requiere API nativa.");
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
// 16) Habilitar Adaptive Sync (G-Sync/FreeSync) (stub)
|
|
679
|
+
static async enableAdaptiveSync() {
|
|
680
|
+
console.warn("enableAdaptiveSync: normalmente se controla por driver (NVIDIA/AMD).");
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
683
|
+
// 17) Deshabilitar Adaptive Sync (stub)
|
|
684
|
+
static async disableAdaptiveSync() {
|
|
685
|
+
console.warn("disableAdaptiveSync: normalmente se controla por driver (NVIDIA/AMD).");
|
|
686
|
+
return false;
|
|
687
|
+
}
|
|
688
|
+
// 18) Forzar monitor primario (setPrimaryDisplay)
|
|
689
|
+
static async setPrimaryDisplay(displayIndex = 0) {
|
|
690
|
+
// Requiere llamadas nativas (ChangeDisplaySettingsEx)
|
|
691
|
+
console.warn("setPrimaryDisplay: requiere API nativa ChangeDisplaySettingsEx.");
|
|
692
|
+
return false;
|
|
693
|
+
}
|
|
694
|
+
// 19) Ver estado del cable (si está conectado/detected) - stub con si.graphics fallback
|
|
695
|
+
static async getCableStatus(displayIndex = 0) {
|
|
696
|
+
const g = await si.graphics();
|
|
697
|
+
const d = g.displays[displayIndex];
|
|
698
|
+
if (!d)
|
|
699
|
+
return "unknown";
|
|
700
|
+
if (d.connection && d.connection !== "") {
|
|
701
|
+
return "connected";
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
return "disconnected";
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
static async rescanDisplays() {
|
|
708
|
+
console.warn("rescanDisplays: implementar con devcon o reiniciando el driver.");
|
|
709
|
+
return false;
|
|
710
|
+
}
|
|
711
|
+
static async setBrightness(value) {
|
|
712
|
+
exec(`powershell -Command "(Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightnessMethods).WmiSetBrightness(1, ${value})"`, (err) => { });
|
|
713
|
+
}
|
|
714
|
+
static rotateNext() {
|
|
715
|
+
const rotations = [0, 90, 180, 270];
|
|
716
|
+
const current = this.rotationHistory.length
|
|
717
|
+
? this.rotationHistory[this.rotationHistory.length - 1].degrees
|
|
718
|
+
: 0;
|
|
719
|
+
const nextIndex = (rotations.indexOf(current) + 1) % rotations.length;
|
|
720
|
+
this.rotateDisplay(rotations[nextIndex]);
|
|
721
|
+
}
|
|
722
|
+
static async exportDisplayInfo(path) {
|
|
723
|
+
const info = await this.getDisplayInfo();
|
|
724
|
+
const fs = require("fs");
|
|
725
|
+
fs.writeFileSync(path, JSON.stringify(info, null, 2));
|
|
726
|
+
}
|
|
727
|
+
static watchMonitorChanges(callback, interval = 2000) {
|
|
728
|
+
let lastCount = 0;
|
|
729
|
+
setInterval(async () => {
|
|
730
|
+
const count = await this.getNumberOfDisplays();
|
|
731
|
+
if (count !== lastCount) {
|
|
732
|
+
callback(count);
|
|
733
|
+
lastCount = count;
|
|
734
|
+
}
|
|
735
|
+
}, interval);
|
|
736
|
+
}
|
|
737
|
+
static async getBrightness() {
|
|
738
|
+
return new Promise((resolve) => {
|
|
739
|
+
exec(`powershell -Command "(Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightness).CurrentBrightness"`, (err, stdout) => {
|
|
740
|
+
if (err)
|
|
741
|
+
return resolve(null);
|
|
742
|
+
resolve(parseInt(stdout.trim()));
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
static async saveCurrentConfig(path) {
|
|
747
|
+
const config = {
|
|
748
|
+
resolution: this.getCurrentResolution(),
|
|
749
|
+
refreshRate: this.getCurrentDisplayMode().hz,
|
|
750
|
+
orientation: this.getCurrentOrientation(),
|
|
751
|
+
timestamp: Date.now(),
|
|
752
|
+
};
|
|
753
|
+
const fs = require("fs");
|
|
754
|
+
fs.writeFileSync(path, JSON.stringify(config, null, 2));
|
|
755
|
+
}
|
|
756
|
+
static async restoreConfig(path) {
|
|
757
|
+
const fs = require("fs");
|
|
758
|
+
if (!fs.existsSync(path))
|
|
759
|
+
return;
|
|
760
|
+
const config = JSON.parse(fs.readFileSync(path, "utf8"));
|
|
761
|
+
this.setResolutionSafe(config.resolution.width, config.resolution.height);
|
|
762
|
+
this.setRefreshRate(config.refreshRate);
|
|
763
|
+
}
|
|
764
|
+
static isCurrentResolutionOptimal() {
|
|
765
|
+
const best = this.getBestResolution();
|
|
766
|
+
const current = this.getCurrentResolution();
|
|
767
|
+
return best?.width === current.width && best?.height === current.height;
|
|
768
|
+
}
|
|
769
|
+
static watchDisplayChanges(callback, interval = 1000) {
|
|
770
|
+
let lastRes = this.getCurrentResolution();
|
|
771
|
+
let lastOrientation = this.getCurrentOrientation();
|
|
772
|
+
setInterval(() => {
|
|
773
|
+
if (this.hasResolutionChanged(lastRes) ||
|
|
774
|
+
lastOrientation !== this.getCurrentOrientation()) {
|
|
775
|
+
callback();
|
|
776
|
+
lastRes = this.getCurrentResolution();
|
|
777
|
+
lastOrientation = this.getCurrentOrientation();
|
|
778
|
+
}
|
|
779
|
+
}, interval);
|
|
780
|
+
}
|
|
781
|
+
static compareAllResolutions() {
|
|
782
|
+
const resolutions = this.getAllResolutions();
|
|
783
|
+
return resolutions.sort((a, b) => b.width * b.height - a.width * a.height);
|
|
784
|
+
}
|
|
785
|
+
static setRefreshRate(hz) {
|
|
786
|
+
exec(`powershell -Command "Set-DisplayRefreshRate -Hz ${hz}"`, (err) => { });
|
|
787
|
+
}
|
|
788
|
+
static exportResolutionHistory(path) {
|
|
789
|
+
const fs = require("fs");
|
|
790
|
+
fs.writeFileSync(path, JSON.stringify(this.resolutionHistory, null, 2));
|
|
791
|
+
}
|
|
792
|
+
static setResolutionSafe(width, height) {
|
|
793
|
+
if (!this.supportsResolution(width, height)) {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
this.setResolution(width, height);
|
|
797
|
+
}
|
|
798
|
+
static setResolutionWithFallback(width, height) {
|
|
799
|
+
if (this.supportsResolution(width, height)) {
|
|
800
|
+
this.setResolution(width, height);
|
|
801
|
+
}
|
|
802
|
+
else {
|
|
803
|
+
const best = this.getBestResolution();
|
|
804
|
+
if (best)
|
|
805
|
+
this.setResolution(best.width, best.height);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
static async getDisplaySummary() {
|
|
809
|
+
const info = await this.getDisplayInfo();
|
|
810
|
+
return info.map((d) => ({
|
|
811
|
+
model: d.model,
|
|
812
|
+
resolution: d.resolution,
|
|
813
|
+
refreshRate: d.refreshRate,
|
|
814
|
+
pixelDepth: d.pixelDepth,
|
|
815
|
+
}));
|
|
816
|
+
}
|
|
817
|
+
static watchRotationChange(degrees) {
|
|
818
|
+
this.rotationHistory.push({ degrees, timestamp: Date.now() });
|
|
819
|
+
this.rotateDisplay(degrees);
|
|
820
|
+
}
|
|
821
|
+
static getRotationHistory() {
|
|
822
|
+
return this.rotationHistory;
|
|
823
|
+
}
|
|
824
|
+
static restoreInitialResolution() {
|
|
825
|
+
if (this.resolutionHistory.length > 0) {
|
|
826
|
+
const { width, height } = this.resolutionHistory[0];
|
|
827
|
+
this.setResolutionSafe(width, height);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
static rotateDisplay(degrees) {
|
|
831
|
+
const allowed = [0, 90, 180, 270];
|
|
832
|
+
if (!allowed.includes(degrees)) {
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
exec(`powershell -Command "DisplayRotation ${degrees}"`, (err) => { });
|
|
836
|
+
}
|
|
837
|
+
static getSupportedOrientations() {
|
|
838
|
+
const resolutions = this.getAllResolutions();
|
|
839
|
+
const orientations = new Set();
|
|
840
|
+
resolutions.forEach((r) => {
|
|
841
|
+
orientations.add(r.width >= r.height ? "landscape" : "portrait");
|
|
842
|
+
});
|
|
843
|
+
return Array.from(orientations);
|
|
844
|
+
}
|
|
845
|
+
static getCurrentOrientation() {
|
|
846
|
+
const res = this.getCurrentResolution();
|
|
847
|
+
return res.width >= res.height ? "landscape" : "portrait";
|
|
848
|
+
}
|
|
849
|
+
static async getNumberOfDisplays() {
|
|
850
|
+
const displays = await si.graphics();
|
|
851
|
+
return displays.displays.length;
|
|
852
|
+
}
|
|
853
|
+
static compareResolutions(resA, resB) {
|
|
854
|
+
const pixelsA = resA.width * resA.height;
|
|
855
|
+
const pixelsB = resB.width * resB.height;
|
|
856
|
+
if (pixelsA > pixelsB)
|
|
857
|
+
return "A";
|
|
858
|
+
if (pixelsB > pixelsA)
|
|
859
|
+
return "B";
|
|
860
|
+
return "Equal";
|
|
861
|
+
}
|
|
862
|
+
static async getColorDepth() {
|
|
863
|
+
const displays = await si.graphics();
|
|
864
|
+
return displays.displays[0]?.pixelDepth || null;
|
|
865
|
+
}
|
|
866
|
+
static async captureScreenshot(path = "screenshot.jpg") {
|
|
867
|
+
await screenshot({ filename: path });
|
|
868
|
+
}
|
|
869
|
+
static watchResolutionChange(callback, interval = 1000) {
|
|
870
|
+
let lastRes = this.getCurrentResolution();
|
|
871
|
+
setInterval(() => {
|
|
872
|
+
const currentRes = this.getCurrentResolution();
|
|
873
|
+
if (currentRes.width !== lastRes.width ||
|
|
874
|
+
currentRes.height !== lastRes.height) {
|
|
875
|
+
lastRes = currentRes;
|
|
876
|
+
callback(currentRes);
|
|
877
|
+
}
|
|
878
|
+
}, interval);
|
|
879
|
+
}
|
|
880
|
+
static async getDisplayInfo() {
|
|
881
|
+
const displays = await si.graphics();
|
|
882
|
+
return displays.displays.map((d) => ({
|
|
883
|
+
model: d.model,
|
|
884
|
+
main: d.main,
|
|
885
|
+
resolution: `${d.currentResX}x${d.currentResY}`,
|
|
886
|
+
refreshRate: d.currentRefreshRate,
|
|
887
|
+
pixelDepth: d.pixelDepth,
|
|
888
|
+
}));
|
|
889
|
+
}
|
|
890
|
+
static isHighRefreshRate() {
|
|
891
|
+
const mode = this.getCurrentDisplayMode();
|
|
892
|
+
return mode.hz >= 120;
|
|
893
|
+
}
|
|
894
|
+
static getAspectRatio() {
|
|
895
|
+
const res = this.getCurrentResolution();
|
|
896
|
+
const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
|
|
897
|
+
const divisor = gcd(res.width, res.height);
|
|
898
|
+
return `${res.width / divisor}:${res.height / divisor}`;
|
|
899
|
+
}
|
|
900
|
+
static supportsResolution(width, height) {
|
|
901
|
+
return this.getAllResolutions().some((r) => r.width === width && r.height === height);
|
|
902
|
+
}
|
|
903
|
+
static getBestDisplayMode() {
|
|
904
|
+
const modes = this.getAllDisplayModes();
|
|
905
|
+
if (!modes.length)
|
|
906
|
+
return null;
|
|
907
|
+
return modes.sort((a, b) => b.width - a.width ||
|
|
908
|
+
b.height - a.height ||
|
|
909
|
+
b.hz - a.hz ||
|
|
910
|
+
b.color - a.color)[0];
|
|
911
|
+
}
|
|
912
|
+
static hasResolutionChanged(last) {
|
|
913
|
+
const current = this.getCurrentResolution();
|
|
914
|
+
return current.width !== last.width || current.height !== last.height;
|
|
915
|
+
}
|
|
916
|
+
static hasDisplayModeChanged(last) {
|
|
917
|
+
const current = this.getCurrentDisplayMode();
|
|
918
|
+
return (current.width !== last.width ||
|
|
919
|
+
current.height !== last.height ||
|
|
920
|
+
current.hz !== last.hz ||
|
|
921
|
+
current.color !== last.color);
|
|
922
|
+
}
|
|
923
|
+
static getBestResolution() {
|
|
924
|
+
const all = this.getAllResolutions();
|
|
925
|
+
if (!all.length)
|
|
926
|
+
return null;
|
|
927
|
+
return all.sort((a, b) => b.width - a.width === 0 ? b.height - a.height : b.width - a.width)[0];
|
|
928
|
+
}
|
|
929
|
+
static getCurrentResolution() {
|
|
930
|
+
return getCurrentResolution();
|
|
931
|
+
}
|
|
932
|
+
static getAllResolutions() {
|
|
933
|
+
return getAvailableResolution();
|
|
934
|
+
}
|
|
935
|
+
static getCurrentDisplayMode() {
|
|
936
|
+
return getCurrentDisplayMode();
|
|
937
|
+
}
|
|
938
|
+
static getAllDisplayModes() {
|
|
939
|
+
return getAvailableDisplayMode();
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
//# sourceMappingURL=screen.js.map
|