@depup/systeminformation 5.31.4-depup.0

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.
@@ -0,0 +1,1235 @@
1
+ 'use strict';
2
+ // @ts-check
3
+ // ==================================================================================
4
+ // graphics.js
5
+ // ----------------------------------------------------------------------------------
6
+ // Description: System Information - library
7
+ // for Node.js
8
+ // Copyright: (c) 2014 - 2026
9
+ // Author: Sebastian Hildebrandt
10
+ // ----------------------------------------------------------------------------------
11
+ // License: MIT
12
+ // ==================================================================================
13
+ // 7. Graphics (controller, display)
14
+ // ----------------------------------------------------------------------------------
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const exec = require('child_process').exec;
19
+ const execSync = require('child_process').execSync;
20
+ const util = require('./util');
21
+
22
+ const _platform = process.platform;
23
+ let _nvidiaSmiPath = '';
24
+
25
+ const _linux = _platform === 'linux' || _platform === 'android';
26
+ const _darwin = _platform === 'darwin';
27
+ const _windows = _platform === 'win32';
28
+ const _freebsd = _platform === 'freebsd';
29
+ const _openbsd = _platform === 'openbsd';
30
+ const _netbsd = _platform === 'netbsd';
31
+ const _sunos = _platform === 'sunos';
32
+
33
+ let _resolutionX = 0;
34
+ let _resolutionY = 0;
35
+ let _pixelDepth = 0;
36
+ let _refreshRate = 0;
37
+
38
+ const videoTypes = {
39
+ '-2': 'UNINITIALIZED',
40
+ '-1': 'OTHER',
41
+ 0: 'HD15',
42
+ 1: 'SVIDEO',
43
+ 2: 'Composite video',
44
+ 3: 'Component video',
45
+ 4: 'DVI',
46
+ 5: 'HDMI',
47
+ 6: 'LVDS',
48
+ 8: 'D_JPN',
49
+ 9: 'SDI',
50
+ 10: 'DP',
51
+ 11: 'DP embedded',
52
+ 12: 'UDI',
53
+ 13: 'UDI embedded',
54
+ 14: 'SDTVDONGLE',
55
+ 15: 'MIRACAST',
56
+ 2147483648: 'INTERNAL'
57
+ };
58
+
59
+ function getVendorFromModel(model) {
60
+ const manufacturers = [
61
+ { pattern: '^LG.+', manufacturer: 'LG' },
62
+ { pattern: '^BENQ.+', manufacturer: 'BenQ' },
63
+ { pattern: '^ASUS.+', manufacturer: 'Asus' },
64
+ { pattern: '^DELL.+', manufacturer: 'Dell' },
65
+ { pattern: '^SAMSUNG.+', manufacturer: 'Samsung' },
66
+ { pattern: '^VIEWSON.+', manufacturer: 'ViewSonic' },
67
+ { pattern: '^SONY.+', manufacturer: 'Sony' },
68
+ { pattern: '^ACER.+', manufacturer: 'Acer' },
69
+ { pattern: '^AOC.+', manufacturer: 'AOC Monitors' },
70
+ { pattern: '^HP.+', manufacturer: 'HP' },
71
+ { pattern: '^EIZO.?', manufacturer: 'Eizo' },
72
+ { pattern: '^PHILIPS.?', manufacturer: 'Philips' },
73
+ { pattern: '^IIYAMA.?', manufacturer: 'Iiyama' },
74
+ { pattern: '^SHARP.?', manufacturer: 'Sharp' },
75
+ { pattern: '^NEC.?', manufacturer: 'NEC' },
76
+ { pattern: '^LENOVO.?', manufacturer: 'Lenovo' },
77
+ { pattern: 'COMPAQ.?', manufacturer: 'Compaq' },
78
+ { pattern: 'APPLE.?', manufacturer: 'Apple' },
79
+ { pattern: 'INTEL.?', manufacturer: 'Intel' },
80
+ { pattern: 'AMD.?', manufacturer: 'AMD' },
81
+ { pattern: 'NVIDIA.?', manufacturer: 'NVDIA' }
82
+ ];
83
+
84
+ let result = '';
85
+ if (model) {
86
+ model = model.toUpperCase();
87
+ manufacturers.forEach((manufacturer) => {
88
+ const re = RegExp(manufacturer.pattern);
89
+ if (re.test(model)) {
90
+ result = manufacturer.manufacturer;
91
+ }
92
+ });
93
+ }
94
+ return result;
95
+ }
96
+
97
+ function getVendorFromId(id) {
98
+ const vendors = {
99
+ 610: 'Apple',
100
+ '1e6d': 'LG',
101
+ '10ac': 'DELL',
102
+ '4dd9': 'Sony',
103
+ '38a3': 'NEC'
104
+ };
105
+ return vendors[id] || '';
106
+ }
107
+
108
+ function vendorToId(str) {
109
+ let result = '';
110
+ str = (str || '').toLowerCase();
111
+ if (str.indexOf('apple') >= 0) {
112
+ result = '0x05ac';
113
+ } else if (str.indexOf('nvidia') >= 0) {
114
+ result = '0x10de';
115
+ } else if (str.indexOf('intel') >= 0) {
116
+ result = '0x8086';
117
+ } else if (str.indexOf('ati') >= 0 || str.indexOf('amd') >= 0) {
118
+ result = '0x1002';
119
+ }
120
+
121
+ return result;
122
+ }
123
+
124
+ function getMetalVersion(id) {
125
+ const families = {
126
+ spdisplays_mtlgpufamilymac1: 'mac1',
127
+ spdisplays_mtlgpufamilymac2: 'mac2',
128
+ spdisplays_mtlgpufamilyapple1: 'apple1',
129
+ spdisplays_mtlgpufamilyapple2: 'apple2',
130
+ spdisplays_mtlgpufamilyapple3: 'apple3',
131
+ spdisplays_mtlgpufamilyapple4: 'apple4',
132
+ spdisplays_mtlgpufamilyapple5: 'apple5',
133
+ spdisplays_mtlgpufamilyapple6: 'apple6',
134
+ spdisplays_mtlgpufamilyapple7: 'apple7',
135
+ spdisplays_metalfeaturesetfamily11: 'family1_v1',
136
+ spdisplays_metalfeaturesetfamily12: 'family1_v2',
137
+ spdisplays_metalfeaturesetfamily13: 'family1_v3',
138
+ spdisplays_metalfeaturesetfamily14: 'family1_v4',
139
+ spdisplays_metalfeaturesetfamily21: 'family2_v1'
140
+ };
141
+ return families[id] || '';
142
+ }
143
+
144
+ function graphics(callback) {
145
+ function parseLinesDarwin(graphicsArr) {
146
+ const res = {
147
+ controllers: [],
148
+ displays: []
149
+ };
150
+ try {
151
+ graphicsArr.forEach((item) => {
152
+ // controllers
153
+ const bus = (item.sppci_bus || '').indexOf('builtin') > -1 ? 'Built-In' : (item.sppci_bus || '').indexOf('pcie') > -1 ? 'PCIe' : '';
154
+ const vram = (parseInt(item.spdisplays_vram || '', 10) || 0) * ((item.spdisplays_vram || '').indexOf('GB') > -1 ? 1024 : 1);
155
+ const vramDyn = (parseInt(item.spdisplays_vram_shared || '', 10) || 0) * ((item.spdisplays_vram_shared || '').indexOf('GB') > -1 ? 1024 : 1);
156
+ let metalVersion = getMetalVersion(item.spdisplays_metal || item.spdisplays_metalfamily || '');
157
+ res.controllers.push({
158
+ vendor: getVendorFromModel(item.spdisplays_vendor || '') || item.spdisplays_vendor || '',
159
+ model: item.sppci_model || '',
160
+ bus,
161
+ vramDynamic: bus === 'Built-In',
162
+ vram: vram || vramDyn || null,
163
+ deviceId: item['spdisplays_device-id'] || '',
164
+ vendorId: item['spdisplays_vendor-id'] || vendorToId((item['spdisplays_vendor'] || '') + (item.sppci_model || '')),
165
+ external: item.sppci_device_type === 'spdisplays_egpu',
166
+ cores: item['sppci_cores'] || null,
167
+ metalVersion
168
+ });
169
+
170
+ // displays
171
+ if (item.spdisplays_ndrvs && item.spdisplays_ndrvs.length) {
172
+ item.spdisplays_ndrvs.forEach((displayItem) => {
173
+ const connectionType = displayItem['spdisplays_connection_type'] || '';
174
+ const currentResolutionParts = (displayItem['_spdisplays_resolution'] || '').split('@');
175
+ const currentResolution = currentResolutionParts[0].split('x');
176
+ const pixelParts = (displayItem['_spdisplays_pixels'] || '').split('x');
177
+ const pixelDepthString = displayItem['spdisplays_depth'] || '';
178
+ const serial = displayItem['_spdisplays_display-serial-number'] || displayItem['_spdisplays_display-serial-number2'] || null;
179
+ res.displays.push({
180
+ vendor: getVendorFromId(displayItem['_spdisplays_display-vendor-id'] || '') || getVendorFromModel(displayItem['_name'] || ''),
181
+ vendorId: displayItem['_spdisplays_display-vendor-id'] || '',
182
+ model: displayItem['_name'] || '',
183
+ productionYear: displayItem['_spdisplays_display-year'] || null,
184
+ serial: serial !== '0' ? serial : null,
185
+ displayId: displayItem['_spdisplays_displayID'] || null,
186
+ main: displayItem['spdisplays_main'] ? displayItem['spdisplays_main'] === 'spdisplays_yes' : false,
187
+ builtin: (displayItem['spdisplays_display_type'] || '').indexOf('built-in') > -1,
188
+ connection: connectionType.indexOf('_internal') > -1 ? 'Internal' : connectionType.indexOf('_displayport') > -1 ? 'Display Port' : connectionType.indexOf('_hdmi') > -1 ? 'HDMI' : null,
189
+ sizeX: null,
190
+ sizeY: null,
191
+ pixelDepth: pixelDepthString === 'CGSThirtyBitColor' ? 30 : pixelDepthString === 'CGSThirtytwoBitColor' ? 32 : pixelDepthString === 'CGSTwentyfourBitColor' ? 24 : null,
192
+ resolutionX: pixelParts.length > 1 ? parseInt(pixelParts[0], 10) : null,
193
+ resolutionY: pixelParts.length > 1 ? parseInt(pixelParts[1], 10) : null,
194
+ currentResX: currentResolution.length > 1 ? parseInt(currentResolution[0], 10) : null,
195
+ currentResY: currentResolution.length > 1 ? parseInt(currentResolution[1], 10) : null,
196
+ positionX: 0,
197
+ positionY: 0,
198
+ currentRefreshRate: currentResolutionParts.length > 1 ? parseInt(currentResolutionParts[1], 10) : null
199
+ });
200
+ });
201
+ }
202
+ });
203
+ return res;
204
+ } catch (e) {
205
+ return res;
206
+ }
207
+ }
208
+
209
+ function parseLinesLinuxControllers(lines) {
210
+ let controllers = [];
211
+ let currentController = {
212
+ vendor: '',
213
+ subVendor: '',
214
+ model: '',
215
+ bus: '',
216
+ busAddress: '',
217
+ vram: null,
218
+ vramDynamic: false,
219
+ pciID: ''
220
+ };
221
+ let isGraphicsController = false;
222
+ // PCI bus IDs
223
+ let pciIDs = [];
224
+ try {
225
+ pciIDs = execSync('export LC_ALL=C; dmidecode -t 9 2>/dev/null; unset LC_ALL | grep "Bus Address: "', util.execOptsLinux).toString().split('\n');
226
+ for (let i = 0; i < pciIDs.length; i++) {
227
+ pciIDs[i] = pciIDs[i].replace('Bus Address:', '').replace('0000:', '').trim();
228
+ }
229
+ pciIDs = pciIDs.filter((el) => el != null && el);
230
+ } catch {
231
+ util.noop();
232
+ }
233
+ let i = 1;
234
+ lines.forEach((line) => {
235
+ let subsystem = '';
236
+ if (i < lines.length && lines[i]) {
237
+ // get next line;
238
+ subsystem = lines[i];
239
+ if (subsystem.indexOf(':') > 0) {
240
+ subsystem = subsystem.split(':')[1];
241
+ }
242
+ }
243
+ if ('' !== line.trim()) {
244
+ if (' ' !== line[0] && '\t' !== line[0]) {
245
+ // first line of new entry
246
+ let isExternal = pciIDs.indexOf(line.split(' ')[0]) >= 0;
247
+ let vgapos = line.toLowerCase().indexOf(' vga ');
248
+ let _3dcontrollerpos = line.toLowerCase().indexOf('3d controller');
249
+ if (vgapos !== -1 || _3dcontrollerpos !== -1) {
250
+ // VGA
251
+ if (_3dcontrollerpos !== -1 && vgapos === -1) {
252
+ vgapos = _3dcontrollerpos;
253
+ }
254
+ if (currentController.vendor || currentController.model || currentController.bus || currentController.vram !== null || currentController.vramDynamic) {
255
+ // already a controller found
256
+ controllers.push(currentController);
257
+ currentController = {
258
+ vendor: '',
259
+ model: '',
260
+ bus: '',
261
+ busAddress: '',
262
+ vram: null,
263
+ vramDynamic: false
264
+ };
265
+ }
266
+
267
+ const pciIDCandidate = line.split(' ')[0];
268
+ if (/[\da-fA-F]{2}:[\da-fA-F]{2}\.[\da-fA-F]/.test(pciIDCandidate)) {
269
+ currentController.busAddress = pciIDCandidate;
270
+ }
271
+ isGraphicsController = true;
272
+ let endpos = line.search(/\[[0-9a-f]{4}:[0-9a-f]{4}]|$/);
273
+ let parts = line.substr(vgapos, endpos - vgapos).split(':');
274
+ currentController.busAddress = line.substr(0, vgapos).trim();
275
+ if (parts.length > 1) {
276
+ parts[1] = parts[1].trim();
277
+ if (parts[1].toLowerCase().indexOf('corporation') >= 0) {
278
+ currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf('corporation') + 11).trim();
279
+ currentController.model = parts[1]
280
+ .substr(parts[1].toLowerCase().indexOf('corporation') + 11, 200)
281
+ .split('(')[0]
282
+ .trim();
283
+ currentController.bus = pciIDs.length > 0 && isExternal ? 'PCIe' : 'Onboard';
284
+ currentController.vram = null;
285
+ currentController.vramDynamic = false;
286
+ } else if (parts[1].toLowerCase().indexOf(' inc.') >= 0) {
287
+ if ((parts[1].match(/]/g) || []).length > 1) {
288
+ currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(']') + 1).trim();
289
+ currentController.model = parts[1]
290
+ .substr(parts[1].toLowerCase().indexOf(']') + 1, 200)
291
+ .trim()
292
+ .split('(')[0]
293
+ .trim();
294
+ } else {
295
+ currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(' inc.') + 5).trim();
296
+ currentController.model = parts[1]
297
+ .substr(parts[1].toLowerCase().indexOf(' inc.') + 5, 200)
298
+ .trim()
299
+ .split('(')[0]
300
+ .trim();
301
+ }
302
+ currentController.bus = pciIDs.length > 0 && isExternal ? 'PCIe' : 'Onboard';
303
+ currentController.vram = null;
304
+ currentController.vramDynamic = false;
305
+ } else if (parts[1].toLowerCase().indexOf(' ltd.') >= 0) {
306
+ if ((parts[1].match(/]/g) || []).length > 1) {
307
+ currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(']') + 1).trim();
308
+ currentController.model = parts[1]
309
+ .substr(parts[1].toLowerCase().indexOf(']') + 1, 200)
310
+ .trim()
311
+ .split('(')[0]
312
+ .trim();
313
+ } else {
314
+ currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(' ltd.') + 5).trim();
315
+ currentController.model = parts[1]
316
+ .substr(parts[1].toLowerCase().indexOf(' ltd.') + 5, 200)
317
+ .trim()
318
+ .split('(')[0]
319
+ .trim();
320
+ }
321
+ }
322
+ if (currentController.model && subsystem.indexOf(currentController.model) !== -1) {
323
+ const subVendor = subsystem.split(currentController.model)[0].trim();
324
+ if (subVendor) {
325
+ currentController.subVendor = subVendor;
326
+ }
327
+ }
328
+ }
329
+ } else {
330
+ isGraphicsController = false;
331
+ }
332
+ }
333
+ if (isGraphicsController) {
334
+ // within VGA details
335
+ let parts = line.split(':');
336
+ if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('devicename') !== -1 && parts[1].toLowerCase().indexOf('onboard') !== -1) {
337
+ currentController.bus = 'Onboard';
338
+ }
339
+ if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('region') !== -1 && parts[1].toLowerCase().indexOf('memory') !== -1) {
340
+ let memparts = parts[1].split('=');
341
+ if (memparts.length > 1) {
342
+ currentController.vram = parseInt(memparts[1]);
343
+ }
344
+ }
345
+ }
346
+ }
347
+ i++;
348
+ });
349
+
350
+ if (currentController.vendor || currentController.model || currentController.bus || currentController.busAddress || currentController.vram !== null || currentController.vramDynamic) {
351
+ // already a controller found
352
+ controllers.push(currentController);
353
+ }
354
+ return controllers;
355
+ }
356
+
357
+ function parseLinesLinuxClinfo(controllers, lines) {
358
+ const fieldPattern = /\[([^\]]+)\]\s+(\w+)\s+(.*)/;
359
+ const devices = lines.reduce((devices, line) => {
360
+ const field = fieldPattern.exec(line.trim());
361
+ if (field) {
362
+ if (!devices[field[1]]) {
363
+ devices[field[1]] = {};
364
+ }
365
+ devices[field[1]][field[2]] = field[3];
366
+ }
367
+ return devices;
368
+ }, {});
369
+ for (let deviceId in devices) {
370
+ const device = devices[deviceId];
371
+ if (device['CL_DEVICE_TYPE'] === 'CL_DEVICE_TYPE_GPU') {
372
+ let busAddress;
373
+ if (device['CL_DEVICE_TOPOLOGY_AMD']) {
374
+ const bdf = device['CL_DEVICE_TOPOLOGY_AMD'].match(/[a-zA-Z0-9]+:\d+\.\d+/);
375
+ if (bdf) {
376
+ busAddress = bdf[0];
377
+ }
378
+ } else if (device['CL_DEVICE_PCI_BUS_ID_NV'] && device['CL_DEVICE_PCI_SLOT_ID_NV']) {
379
+ const bus = parseInt(device['CL_DEVICE_PCI_BUS_ID_NV']);
380
+ const slot = parseInt(device['CL_DEVICE_PCI_SLOT_ID_NV']);
381
+ if (!isNaN(bus) && !isNaN(slot)) {
382
+ const b = bus & 0xff;
383
+ const d = (slot >> 3) & 0xff;
384
+ const f = slot & 0x07;
385
+ busAddress = `${b.toString().padStart(2, '0')}:${d.toString().padStart(2, '0')}.${f}`;
386
+ }
387
+ }
388
+ if (busAddress) {
389
+ let controller = controllers.find((controller) => controller.busAddress === busAddress);
390
+ if (!controller) {
391
+ controller = {
392
+ vendor: '',
393
+ model: '',
394
+ bus: '',
395
+ busAddress,
396
+ vram: null,
397
+ vramDynamic: false
398
+ };
399
+ controllers.push(controller);
400
+ }
401
+ controller.vendor = device['CL_DEVICE_VENDOR'];
402
+ if (device['CL_DEVICE_BOARD_NAME_AMD']) {
403
+ controller.model = device['CL_DEVICE_BOARD_NAME_AMD'];
404
+ } else {
405
+ controller.model = device['CL_DEVICE_NAME'];
406
+ }
407
+ const memory = parseInt(device['CL_DEVICE_GLOBAL_MEM_SIZE']);
408
+ if (!isNaN(memory)) {
409
+ controller.vram = Math.round(memory / 1024 / 1024);
410
+ }
411
+ }
412
+ }
413
+ }
414
+ return controllers;
415
+ }
416
+
417
+ function getNvidiaSmi() {
418
+ if (_nvidiaSmiPath) {
419
+ return _nvidiaSmiPath;
420
+ }
421
+
422
+ if (_windows) {
423
+ try {
424
+ const basePath = path.join(util.WINDIR, 'System32', 'DriverStore', 'FileRepository');
425
+ // find all directories that have an nvidia-smi.exe file with date
426
+ const candidates = fs
427
+ .readdirSync(basePath, { withFileTypes: true })
428
+ .filter((dir) => dir.isDirectory())
429
+ .map((dir) => {
430
+ const nvidiaSmiPath = path.join(basePath, dir.name, 'nvidia-smi.exe');
431
+ try {
432
+ const stats = fs.statSync(nvidiaSmiPath);
433
+ return { path: nvidiaSmiPath, ctime: stats.ctimeMs };
434
+ } catch {
435
+ return null;
436
+ }
437
+ })
438
+ .filter(Boolean);
439
+ if (candidates.length > 0) {
440
+ // take the most recent
441
+ _nvidiaSmiPath = candidates.reduce((prev, curr) => (curr.ctime > prev.ctime ? curr : prev)).path;
442
+ }
443
+ } catch {
444
+ util.noop();
445
+ }
446
+ } else if (_linux) {
447
+ _nvidiaSmiPath = 'nvidia-smi';
448
+ }
449
+ return _nvidiaSmiPath;
450
+ }
451
+
452
+ function nvidiaSmi(options) {
453
+ const nvidiaSmiExe = getNvidiaSmi();
454
+ options = options || util.execOptsWin;
455
+ if (nvidiaSmiExe) {
456
+ const nvidiaSmiOpts =
457
+ '--query-gpu=driver_version,pci.sub_device_id,name,pci.bus_id,fan.speed,memory.total,memory.used,memory.free,utilization.gpu,utilization.memory,temperature.gpu,temperature.memory,power.draw,power.limit,clocks.gr,clocks.mem --format=csv,noheader,nounits';
458
+ const cmd = `"${nvidiaSmiExe}" ${nvidiaSmiOpts}`;
459
+ if (_linux) {
460
+ options.stdio = ['pipe', 'pipe', 'ignore'];
461
+ }
462
+ try {
463
+ const sanitized = cmd + (_linux ? ' 2>/dev/null' : '') + (_windows ? ' 2> nul' : '');
464
+ const res = execSync(sanitized, options).toString();
465
+ return res;
466
+ } catch {
467
+ util.noop();
468
+ }
469
+ }
470
+ return '';
471
+ }
472
+
473
+ function nvidiaDevices() {
474
+ function safeParseNumber(value) {
475
+ if ([null, undefined].includes(value)) {
476
+ return value;
477
+ }
478
+ return parseFloat(value);
479
+ }
480
+
481
+ const stdout = nvidiaSmi();
482
+ if (!stdout) {
483
+ return [];
484
+ }
485
+
486
+ const gpus = stdout.split('\n').filter(Boolean);
487
+ let results = gpus.map((gpu) => {
488
+ const splittedData = gpu.split(', ').map((value) => (value.includes('N/A') ? undefined : value));
489
+ if (splittedData.length === 16) {
490
+ return {
491
+ driverVersion: splittedData[0],
492
+ subDeviceId: splittedData[1],
493
+ name: splittedData[2],
494
+ pciBus: splittedData[3],
495
+ fanSpeed: safeParseNumber(splittedData[4]),
496
+ memoryTotal: safeParseNumber(splittedData[5]),
497
+ memoryUsed: safeParseNumber(splittedData[6]),
498
+ memoryFree: safeParseNumber(splittedData[7]),
499
+ utilizationGpu: safeParseNumber(splittedData[8]),
500
+ utilizationMemory: safeParseNumber(splittedData[9]),
501
+ temperatureGpu: safeParseNumber(splittedData[10]),
502
+ temperatureMemory: safeParseNumber(splittedData[11]),
503
+ powerDraw: safeParseNumber(splittedData[12]),
504
+ powerLimit: safeParseNumber(splittedData[13]),
505
+ clockCore: safeParseNumber(splittedData[14]),
506
+ clockMemory: safeParseNumber(splittedData[15])
507
+ };
508
+ } else {
509
+ return {};
510
+ }
511
+ });
512
+ results = results.filter((item) => {
513
+ return 'pciBus' in item;
514
+ });
515
+ return results;
516
+ }
517
+
518
+ function mergeControllerNvidia(controller, nvidia) {
519
+ if (nvidia.driverVersion) {
520
+ controller.driverVersion = nvidia.driverVersion;
521
+ }
522
+ if (nvidia.subDeviceId) {
523
+ controller.subDeviceId = nvidia.subDeviceId;
524
+ }
525
+ if (nvidia.name) {
526
+ controller.name = nvidia.name;
527
+ }
528
+ if (nvidia.pciBus) {
529
+ controller.pciBus = nvidia.pciBus;
530
+ }
531
+ if (nvidia.fanSpeed) {
532
+ controller.fanSpeed = nvidia.fanSpeed;
533
+ }
534
+ if (nvidia.memoryTotal) {
535
+ controller.memoryTotal = nvidia.memoryTotal;
536
+ controller.vram = nvidia.memoryTotal;
537
+ controller.vramDynamic = false;
538
+ }
539
+ if (nvidia.memoryUsed) {
540
+ controller.memoryUsed = nvidia.memoryUsed;
541
+ }
542
+ if (nvidia.memoryFree) {
543
+ controller.memoryFree = nvidia.memoryFree;
544
+ }
545
+ if (nvidia.utilizationGpu) {
546
+ controller.utilizationGpu = nvidia.utilizationGpu;
547
+ }
548
+ if (nvidia.utilizationMemory) {
549
+ controller.utilizationMemory = nvidia.utilizationMemory;
550
+ }
551
+ if (nvidia.temperatureGpu) {
552
+ controller.temperatureGpu = nvidia.temperatureGpu;
553
+ }
554
+ if (nvidia.temperatureMemory) {
555
+ controller.temperatureMemory = nvidia.temperatureMemory;
556
+ }
557
+ if (nvidia.powerDraw) {
558
+ controller.powerDraw = nvidia.powerDraw;
559
+ }
560
+ if (nvidia.powerLimit) {
561
+ controller.powerLimit = nvidia.powerLimit;
562
+ }
563
+ if (nvidia.clockCore) {
564
+ controller.clockCore = nvidia.clockCore;
565
+ }
566
+ if (nvidia.clockMemory) {
567
+ controller.clockMemory = nvidia.clockMemory;
568
+ }
569
+ return controller;
570
+ }
571
+
572
+ function parseLinesLinuxEdid(edid) {
573
+ // parsen EDID
574
+ // --> model
575
+ // --> resolutionx
576
+ // --> resolutiony
577
+ // --> builtin = false
578
+ // --> pixeldepth (?)
579
+ // --> sizex
580
+ // --> sizey
581
+ const result = {
582
+ vendor: '',
583
+ model: '',
584
+ deviceName: '',
585
+ main: false,
586
+ builtin: false,
587
+ connection: '',
588
+ sizeX: null,
589
+ sizeY: null,
590
+ pixelDepth: null,
591
+ resolutionX: null,
592
+ resolutionY: null,
593
+ currentResX: null,
594
+ currentResY: null,
595
+ positionX: 0,
596
+ positionY: 0,
597
+ currentRefreshRate: null
598
+ };
599
+ // find first "Detailed Timing Description"
600
+ let start = 108;
601
+ if (edid.substr(start, 6) === '000000') {
602
+ start += 36;
603
+ }
604
+ if (edid.substr(start, 6) === '000000') {
605
+ start += 36;
606
+ }
607
+ if (edid.substr(start, 6) === '000000') {
608
+ start += 36;
609
+ }
610
+ if (edid.substr(start, 6) === '000000') {
611
+ start += 36;
612
+ }
613
+ result.resolutionX = parseInt('0x0' + edid.substr(start + 8, 1) + edid.substr(start + 4, 2));
614
+ result.resolutionY = parseInt('0x0' + edid.substr(start + 14, 1) + edid.substr(start + 10, 2));
615
+ result.sizeX = parseInt('0x0' + edid.substr(start + 28, 1) + edid.substr(start + 24, 2));
616
+ result.sizeY = parseInt('0x0' + edid.substr(start + 29, 1) + edid.substr(start + 26, 2));
617
+ // monitor name
618
+ start = edid.indexOf('000000fc00'); // find first "Monitor Description Data"
619
+ if (start >= 0) {
620
+ let model_raw = edid.substr(start + 10, 26);
621
+ if (model_raw.indexOf('0a') !== -1) {
622
+ model_raw = model_raw.substr(0, model_raw.indexOf('0a'));
623
+ }
624
+ try {
625
+ if (model_raw.length > 2) {
626
+ result.model = model_raw
627
+ .match(/.{1,2}/g)
628
+ .map((v) => String.fromCharCode(parseInt(v, 16)))
629
+ .join('');
630
+ }
631
+ } catch {
632
+ util.noop();
633
+ }
634
+ } else {
635
+ result.model = '';
636
+ }
637
+ return result;
638
+ }
639
+
640
+ function parseLinesLinuxDisplays(lines, depth) {
641
+ const displays = [];
642
+ let currentDisplay = {
643
+ vendor: '',
644
+ model: '',
645
+ deviceName: '',
646
+ main: false,
647
+ builtin: false,
648
+ connection: '',
649
+ sizeX: null,
650
+ sizeY: null,
651
+ pixelDepth: null,
652
+ resolutionX: null,
653
+ resolutionY: null,
654
+ currentResX: null,
655
+ currentResY: null,
656
+ positionX: 0,
657
+ positionY: 0,
658
+ currentRefreshRate: null
659
+ };
660
+ let is_edid = false;
661
+ let is_current = false;
662
+ let edid_raw = '';
663
+ let start = 0;
664
+ for (let i = 1; i < lines.length; i++) {
665
+ // start with second line
666
+ if ('' !== lines[i].trim()) {
667
+ if (' ' !== lines[i][0] && '\t' !== lines[i][0] && lines[i].toLowerCase().indexOf(' connected ') !== -1) {
668
+ // first line of new entry
669
+ if (
670
+ currentDisplay.model ||
671
+ currentDisplay.main ||
672
+ currentDisplay.builtin ||
673
+ currentDisplay.connection ||
674
+ currentDisplay.sizeX !== null ||
675
+ currentDisplay.pixelDepth !== null ||
676
+ currentDisplay.resolutionX !== null
677
+ ) {
678
+ // push last display to array
679
+ displays.push(currentDisplay);
680
+ currentDisplay = {
681
+ vendor: '',
682
+ model: '',
683
+ main: false,
684
+ builtin: false,
685
+ connection: '',
686
+ sizeX: null,
687
+ sizeY: null,
688
+ pixelDepth: null,
689
+ resolutionX: null,
690
+ resolutionY: null,
691
+ currentResX: null,
692
+ currentResY: null,
693
+ positionX: 0,
694
+ positionY: 0,
695
+ currentRefreshRate: null
696
+ };
697
+ }
698
+ let parts = lines[i].split(' ');
699
+ currentDisplay.connection = parts[0];
700
+ currentDisplay.main = lines[i].toLowerCase().indexOf(' primary ') >= 0;
701
+ currentDisplay.builtin = parts[0].toLowerCase().indexOf('edp') >= 0;
702
+ }
703
+
704
+ // try to read EDID information
705
+ if (is_edid) {
706
+ if (lines[i].search(/\S|$/) > start) {
707
+ edid_raw += lines[i].toLowerCase().trim();
708
+ } else {
709
+ // parsen EDID
710
+ let edid_decoded = parseLinesLinuxEdid(edid_raw);
711
+ currentDisplay.vendor = edid_decoded.vendor;
712
+ currentDisplay.model = edid_decoded.model;
713
+ currentDisplay.resolutionX = edid_decoded.resolutionX;
714
+ currentDisplay.resolutionY = edid_decoded.resolutionY;
715
+ currentDisplay.sizeX = edid_decoded.sizeX;
716
+ currentDisplay.sizeY = edid_decoded.sizeY;
717
+ currentDisplay.pixelDepth = depth;
718
+ is_edid = false;
719
+ }
720
+ }
721
+ if (lines[i].toLowerCase().indexOf('edid:') >= 0) {
722
+ is_edid = true;
723
+ start = lines[i].search(/\S|$/);
724
+ }
725
+ if (lines[i].toLowerCase().indexOf('*current') >= 0) {
726
+ const parts1 = lines[i].split('(');
727
+ if (parts1 && parts1.length > 1 && parts1[0].indexOf('x') >= 0) {
728
+ const resParts = parts1[0].trim().split('x');
729
+ currentDisplay.currentResX = util.toInt(resParts[0]);
730
+ currentDisplay.currentResY = util.toInt(resParts[1]);
731
+ }
732
+ is_current = true;
733
+ }
734
+ if (is_current && lines[i].toLowerCase().indexOf('clock') >= 0 && lines[i].toLowerCase().indexOf('hz') >= 0 && lines[i].toLowerCase().indexOf('v: height') >= 0) {
735
+ const parts1 = lines[i].split('clock');
736
+ if (parts1 && parts1.length > 1 && parts1[1].toLowerCase().indexOf('hz') >= 0) {
737
+ currentDisplay.currentRefreshRate = util.toInt(parts1[1]);
738
+ }
739
+ is_current = false;
740
+ }
741
+ }
742
+ }
743
+
744
+ // pushen displays
745
+ if (
746
+ currentDisplay.model ||
747
+ currentDisplay.main ||
748
+ currentDisplay.builtin ||
749
+ currentDisplay.connection ||
750
+ currentDisplay.sizeX !== null ||
751
+ currentDisplay.pixelDepth !== null ||
752
+ currentDisplay.resolutionX !== null
753
+ ) {
754
+ // still information there
755
+ displays.push(currentDisplay);
756
+ }
757
+ return displays;
758
+ }
759
+
760
+ // function starts here
761
+ return new Promise((resolve) => {
762
+ process.nextTick(() => {
763
+ let result = {
764
+ controllers: [],
765
+ displays: []
766
+ };
767
+ if (_darwin) {
768
+ const cmd = 'system_profiler -xml -detailLevel full SPDisplaysDataType';
769
+ exec(cmd, (error, stdout) => {
770
+ if (!error) {
771
+ try {
772
+ const output = stdout.toString();
773
+ result = parseLinesDarwin(util.plistParser(output)[0]._items);
774
+ } catch (e) {
775
+ util.noop();
776
+ }
777
+ try {
778
+ stdout = execSync(
779
+ 'defaults read /Library/Preferences/com.apple.windowserver.plist 2>/dev/null;defaults read /Library/Preferences/com.apple.windowserver.displays.plist 2>/dev/null; echo ""',
780
+ { maxBuffer: 1024 * 102400 }
781
+ );
782
+ const output = (stdout || '').toString();
783
+ const obj = util.plistReader(output);
784
+ if (obj['DisplayAnyUserSets'] && obj['DisplayAnyUserSets']['Configs'] && obj['DisplayAnyUserSets']['Configs'][0] && obj['DisplayAnyUserSets']['Configs'][0]['DisplayConfig']) {
785
+ const current = obj['DisplayAnyUserSets']['Configs'][0]['DisplayConfig'];
786
+ let i = 0;
787
+ current.forEach((o) => {
788
+ if (o['CurrentInfo'] && o['CurrentInfo']['OriginX'] !== undefined && result.displays && result.displays[i]) {
789
+ result.displays[i].positionX = o['CurrentInfo']['OriginX'];
790
+ }
791
+ if (o['CurrentInfo'] && o['CurrentInfo']['OriginY'] !== undefined && result.displays && result.displays[i]) {
792
+ result.displays[i].positionY = o['CurrentInfo']['OriginY'];
793
+ }
794
+ i++;
795
+ });
796
+ }
797
+ if (obj['DisplayAnyUserSets'] && obj['DisplayAnyUserSets'].length > 0 && obj['DisplayAnyUserSets'][0].length > 0 && obj['DisplayAnyUserSets'][0][0]['DisplayID']) {
798
+ const current = obj['DisplayAnyUserSets'][0];
799
+ let i = 0;
800
+ current.forEach((o) => {
801
+ if ('OriginX' in o && result.displays && result.displays[i]) {
802
+ result.displays[i].positionX = o['OriginX'];
803
+ }
804
+ if ('OriginY' in o && result.displays && result.displays[i]) {
805
+ result.displays[i].positionY = o['OriginY'];
806
+ }
807
+ if (o['Mode'] && o['Mode']['BitsPerPixel'] !== undefined && result.displays && result.displays[i]) {
808
+ result.displays[i].pixelDepth = o['Mode']['BitsPerPixel'];
809
+ }
810
+ i++;
811
+ });
812
+ }
813
+ } catch {
814
+ util.noop();
815
+ }
816
+ }
817
+ if (callback) {
818
+ callback(result);
819
+ }
820
+ resolve(result);
821
+ });
822
+ }
823
+ if (_linux) {
824
+ // Raspberry: https://elinux.org/RPI_vcgencmd_usage
825
+ if (util.isRaspberry()) {
826
+ const cmd = "fbset -s 2> /dev/null | grep 'mode \"' ; vcgencmd get_mem gpu 2> /dev/null; tvservice -s 2> /dev/null; tvservice -n 2> /dev/null;";
827
+ exec(cmd, (error, stdout) => {
828
+ const lines = stdout.toString().split('\n');
829
+ if (lines.length > 3 && lines[0].indexOf('mode "') >= -1 && lines[2].indexOf('0x12000a') > -1) {
830
+ const parts = lines[0].replace('mode', '').replace(/"/g, '').trim().split('x');
831
+ if (parts.length === 2) {
832
+ result.displays.push({
833
+ vendor: '',
834
+ model: util.getValue(lines, 'device_name', '='),
835
+ main: true,
836
+ builtin: false,
837
+ connection: 'HDMI',
838
+ sizeX: null,
839
+ sizeY: null,
840
+ pixelDepth: null,
841
+ resolutionX: parseInt(parts[0], 10),
842
+ resolutionY: parseInt(parts[1], 10),
843
+ currentResX: null,
844
+ currentResY: null,
845
+ positionX: 0,
846
+ positionY: 0,
847
+ currentRefreshRate: null
848
+ });
849
+ }
850
+ }
851
+ if (lines.length >= 1 && stdout.toString().indexOf('gpu=') >= -1) {
852
+ result.controllers.push({
853
+ vendor: 'Broadcom',
854
+ model: util.getRpiGpu(),
855
+ bus: '',
856
+ vram: util.getValue(lines, 'gpu', '=').replace('M', ''),
857
+ vramDynamic: true
858
+ });
859
+ }
860
+ });
861
+ }
862
+ // } else {
863
+ const cmd = 'lspci -vvv 2>/dev/null';
864
+ exec(cmd, (error, stdout) => {
865
+ if (!error) {
866
+ const lines = stdout.toString().split('\n');
867
+ if (result.controllers.length === 0) {
868
+ result.controllers = parseLinesLinuxControllers(lines);
869
+
870
+ const nvidiaData = nvidiaDevices();
871
+ // needs to be rewritten ... using no spread operators
872
+ result.controllers = result.controllers.map((controller) => {
873
+ // match by busAddress
874
+ return mergeControllerNvidia(controller, nvidiaData.find((contr) => contr.pciBus.toLowerCase().endsWith(controller.busAddress.toLowerCase())) || {});
875
+ });
876
+ }
877
+ }
878
+ const cmd = 'clinfo --raw';
879
+ exec(cmd, (error, stdout) => {
880
+ if (!error) {
881
+ const lines = stdout.toString().split('\n');
882
+ result.controllers = parseLinesLinuxClinfo(result.controllers, lines);
883
+ }
884
+ const cmd = "xdpyinfo 2>/dev/null | grep 'depth of root window' | awk '{ print $5 }'";
885
+ exec(cmd, (error, stdout) => {
886
+ let depth = 0;
887
+ if (!error) {
888
+ const lines = stdout.toString().split('\n');
889
+ depth = parseInt(lines[0]) || 0;
890
+ }
891
+ const cmd = 'xrandr --verbose 2>/dev/null';
892
+ exec(cmd, (error, stdout) => {
893
+ if (!error) {
894
+ const lines = stdout.toString().split('\n');
895
+ result.displays = parseLinesLinuxDisplays(lines, depth);
896
+ }
897
+ if (callback) {
898
+ callback(result);
899
+ }
900
+ resolve(result);
901
+ });
902
+ });
903
+ });
904
+ });
905
+ // }
906
+ }
907
+ if (_freebsd || _openbsd || _netbsd) {
908
+ if (callback) {
909
+ callback(null);
910
+ }
911
+ resolve(null);
912
+ }
913
+ if (_sunos) {
914
+ if (callback) {
915
+ callback(null);
916
+ }
917
+ resolve(null);
918
+ }
919
+ if (_windows) {
920
+ // https://blogs.technet.microsoft.com/heyscriptingguy/2013/10/03/use-powershell-to-discover-multi-monitor-information/
921
+ // https://devblogs.microsoft.com/scripting/use-powershell-to-discover-multi-monitor-information/
922
+ try {
923
+ const workload = [];
924
+ workload.push(util.powerShell('Get-CimInstance win32_VideoController | fl *'));
925
+ workload.push(
926
+ util.powerShell(
927
+ 'gp "HKLM:\\SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\*" -ErrorAction SilentlyContinue | where MatchingDeviceId $null -NE | select MatchingDeviceId,HardwareInformation.qwMemorySize | fl'
928
+ )
929
+ );
930
+ workload.push(util.powerShell('Get-CimInstance win32_desktopmonitor | fl *'));
931
+ workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorBasicDisplayParams | fl'));
932
+ workload.push(util.powerShell('Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Screen]::AllScreens'));
933
+ workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorConnectionParams | fl'));
934
+ workload.push(
935
+ util.powerShell(
936
+ 'gwmi WmiMonitorID -Namespace root\\wmi | ForEach-Object {(($_.ManufacturerName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.ProductCodeID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.UserFriendlyName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.SerialNumberID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + $_.InstanceName}'
937
+ )
938
+ );
939
+
940
+ const nvidiaData = nvidiaDevices();
941
+
942
+ Promise.all(workload)
943
+ .then((data) => {
944
+ // controller + vram
945
+ const csections = data[0].replace(/\r/g, '').split(/\n\s*\n/);
946
+ const vsections = data[1].replace(/\r/g, '').split(/\n\s*\n/);
947
+ result.controllers = parseLinesWindowsControllers(csections, vsections);
948
+ result.controllers = result.controllers.map((controller) => {
949
+ // match by subDeviceId
950
+ if (controller.vendor.toLowerCase() === 'nvidia') {
951
+ return mergeControllerNvidia(
952
+ controller,
953
+ nvidiaData.find((device) => {
954
+ let windowsSubDeviceId = (controller.subDeviceId || '').toLowerCase();
955
+ const nvidiaSubDeviceIdParts = device.subDeviceId.split('x');
956
+ let nvidiaSubDeviceId = nvidiaSubDeviceIdParts.length > 1 ? nvidiaSubDeviceIdParts[1].toLowerCase() : nvidiaSubDeviceIdParts[0].toLowerCase();
957
+ const lengthDifference = Math.abs(windowsSubDeviceId.length - nvidiaSubDeviceId.length);
958
+ if (windowsSubDeviceId.length > nvidiaSubDeviceId.length) {
959
+ for (let i = 0; i < lengthDifference; i++) {
960
+ nvidiaSubDeviceId = '0' + nvidiaSubDeviceId;
961
+ }
962
+ } else if (windowsSubDeviceId.length < nvidiaSubDeviceId.length) {
963
+ for (let i = 0; i < lengthDifference; i++) {
964
+ windowsSubDeviceId = '0' + windowsSubDeviceId;
965
+ }
966
+ }
967
+ return windowsSubDeviceId === nvidiaSubDeviceId;
968
+ }) || {}
969
+ );
970
+ } else {
971
+ return controller;
972
+ }
973
+ });
974
+
975
+ // displays
976
+ const dsections = data[2].replace(/\r/g, '').split(/\n\s*\n/);
977
+ // result.displays = parseLinesWindowsDisplays(dsections);
978
+ if (dsections[0].trim() === '') {
979
+ dsections.shift();
980
+ }
981
+ if (dsections.length && dsections[dsections.length - 1].trim() === '') {
982
+ dsections.pop();
983
+ }
984
+
985
+ // monitor (powershell)
986
+ const msections = data[3].replace(/\r/g, '').split('Active ');
987
+ msections.shift();
988
+
989
+ // forms.screens (powershell)
990
+ const ssections = data[4].replace(/\r/g, '').split('BitsPerPixel ');
991
+ ssections.shift();
992
+
993
+ // connection params (powershell) - video type
994
+ const tsections = data[5].replace(/\r/g, '').split(/\n\s*\n/);
995
+ tsections.shift();
996
+
997
+ // monitor ID (powershell) - model / vendor
998
+ const res = data[6].replace(/\r/g, '').split(/\n/);
999
+ const isections = [];
1000
+ res.forEach((element) => {
1001
+ const parts = element.split('|');
1002
+ if (parts.length === 5) {
1003
+ isections.push({
1004
+ vendor: parts[0],
1005
+ code: parts[1],
1006
+ model: parts[2],
1007
+ serial: parts[3],
1008
+ instanceId: parts[4]
1009
+ });
1010
+ }
1011
+ });
1012
+
1013
+ result.displays = parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections, isections);
1014
+
1015
+ if (result.displays.length === 1) {
1016
+ if (_resolutionX) {
1017
+ result.displays[0].resolutionX = _resolutionX;
1018
+ if (!result.displays[0].currentResX) {
1019
+ result.displays[0].currentResX = _resolutionX;
1020
+ }
1021
+ }
1022
+ if (_resolutionY) {
1023
+ result.displays[0].resolutionY = _resolutionY;
1024
+ if (result.displays[0].currentResY === 0) {
1025
+ result.displays[0].currentResY = _resolutionY;
1026
+ }
1027
+ }
1028
+ if (_pixelDepth) {
1029
+ result.displays[0].pixelDepth = _pixelDepth;
1030
+ }
1031
+ }
1032
+ result.displays = result.displays.map((element) => {
1033
+ if (_refreshRate && !element.currentRefreshRate) {
1034
+ element.currentRefreshRate = _refreshRate;
1035
+ }
1036
+ return element;
1037
+ });
1038
+
1039
+ if (callback) {
1040
+ callback(result);
1041
+ }
1042
+ resolve(result);
1043
+ })
1044
+ .catch(() => {
1045
+ if (callback) {
1046
+ callback(result);
1047
+ }
1048
+ resolve(result);
1049
+ });
1050
+ } catch (e) {
1051
+ if (callback) {
1052
+ callback(result);
1053
+ }
1054
+ resolve(result);
1055
+ }
1056
+ }
1057
+ });
1058
+ });
1059
+
1060
+ function parseLinesWindowsControllers(sections, vections) {
1061
+ const memorySizes = {};
1062
+ for (const i in vections) {
1063
+ if ({}.hasOwnProperty.call(vections, i)) {
1064
+ if (vections[i].trim() !== '') {
1065
+ const lines = vections[i].trim().split('\n');
1066
+ const matchingDeviceId = util.getValue(lines, 'MatchingDeviceId').match(/PCI\\(VEN_[0-9A-F]{4})&(DEV_[0-9A-F]{4})(?:&(SUBSYS_[0-9A-F]{8}))?(?:&(REV_[0-9A-F]{2}))?/i);
1067
+ if (matchingDeviceId) {
1068
+ const quadWordmemorySize = parseInt(util.getValue(lines, 'HardwareInformation.qwMemorySize'));
1069
+ if (!isNaN(quadWordmemorySize)) {
1070
+ let deviceId = matchingDeviceId[1].toUpperCase() + '&' + matchingDeviceId[2].toUpperCase();
1071
+ if (matchingDeviceId[3]) {
1072
+ deviceId += '&' + matchingDeviceId[3].toUpperCase();
1073
+ }
1074
+ if (matchingDeviceId[4]) {
1075
+ deviceId += '&' + matchingDeviceId[4].toUpperCase();
1076
+ }
1077
+ memorySizes[deviceId] = quadWordmemorySize;
1078
+ }
1079
+ }
1080
+ }
1081
+ }
1082
+ }
1083
+
1084
+ const controllers = [];
1085
+ for (const i in sections) {
1086
+ if ({}.hasOwnProperty.call(sections, i)) {
1087
+ if (sections[i].trim() !== '') {
1088
+ const lines = sections[i].trim().split('\n');
1089
+ const pnpDeviceId = util.getValue(lines, 'PNPDeviceID', ':').match(/PCI\\(VEN_[0-9A-F]{4})&(DEV_[0-9A-F]{4})(?:&(SUBSYS_[0-9A-F]{8}))?(?:&(REV_[0-9A-F]{2}))?/i);
1090
+ let subDeviceId = null;
1091
+ let memorySize = null;
1092
+ if (pnpDeviceId) {
1093
+ subDeviceId = pnpDeviceId[3] || '';
1094
+ if (subDeviceId) {
1095
+ subDeviceId = subDeviceId.split('_')[1];
1096
+ }
1097
+
1098
+ // Match PCI device identifier (there's an order of increasing generality):
1099
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-pci-devices
1100
+
1101
+ // PCI\VEN_v(4)&DEV_d(4)&SUBSYS_s(4)n(4)&REV_r(2)
1102
+ if (memorySize == null && pnpDeviceId[3] && pnpDeviceId[4]) {
1103
+ const deviceId = pnpDeviceId[1].toUpperCase() + '&' + pnpDeviceId[2].toUpperCase() + '&' + pnpDeviceId[3].toUpperCase() + '&' + pnpDeviceId[4].toUpperCase();
1104
+ if ({}.hasOwnProperty.call(memorySizes, deviceId)) {
1105
+ memorySize = memorySizes[deviceId];
1106
+ }
1107
+ }
1108
+
1109
+ // PCI\VEN_v(4)&DEV_d(4)&SUBSYS_s(4)n(4)
1110
+ if (memorySize == null && pnpDeviceId[3]) {
1111
+ const deviceId = pnpDeviceId[1].toUpperCase() + '&' + pnpDeviceId[2].toUpperCase() + '&' + pnpDeviceId[3].toUpperCase();
1112
+ if ({}.hasOwnProperty.call(memorySizes, deviceId)) {
1113
+ memorySize = memorySizes[deviceId];
1114
+ }
1115
+ }
1116
+
1117
+ // PCI\VEN_v(4)&DEV_d(4)&REV_r(2)
1118
+ if (memorySize == null && pnpDeviceId[4]) {
1119
+ const deviceId = pnpDeviceId[1].toUpperCase() + '&' + pnpDeviceId[2].toUpperCase() + '&' + pnpDeviceId[4].toUpperCase();
1120
+ if ({}.hasOwnProperty.call(memorySizes, deviceId)) {
1121
+ memorySize = memorySizes[deviceId];
1122
+ }
1123
+ }
1124
+
1125
+ // PCI\VEN_v(4)&DEV_d(4)
1126
+ if (memorySize == null) {
1127
+ const deviceId = pnpDeviceId[1].toUpperCase() + '&' + pnpDeviceId[2].toUpperCase();
1128
+ if ({}.hasOwnProperty.call(memorySizes, deviceId)) {
1129
+ memorySize = memorySizes[deviceId];
1130
+ }
1131
+ }
1132
+ }
1133
+
1134
+ controllers.push({
1135
+ vendor: util.getValue(lines, 'AdapterCompatibility', ':'),
1136
+ model: util.getValue(lines, 'name', ':'),
1137
+ bus: util.getValue(lines, 'PNPDeviceID', ':').startsWith('PCI') ? 'PCI' : '',
1138
+ vram: (memorySize == null ? util.toInt(util.getValue(lines, 'AdapterRAM', ':')) : memorySize) / 1024 / 1024,
1139
+ vramDynamic: util.getValue(lines, 'VideoMemoryType', ':') === '2',
1140
+ subDeviceId
1141
+ });
1142
+ _resolutionX = util.toInt(util.getValue(lines, 'CurrentHorizontalResolution', ':')) || _resolutionX;
1143
+ _resolutionY = util.toInt(util.getValue(lines, 'CurrentVerticalResolution', ':')) || _resolutionY;
1144
+ _refreshRate = util.toInt(util.getValue(lines, 'CurrentRefreshRate', ':')) || _refreshRate;
1145
+ _pixelDepth = util.toInt(util.getValue(lines, 'CurrentBitsPerPixel', ':')) || _pixelDepth;
1146
+ }
1147
+ }
1148
+ }
1149
+ return controllers;
1150
+ }
1151
+
1152
+ function parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections, isections) {
1153
+ const displays = [];
1154
+ let vendor = '';
1155
+ let model = '';
1156
+ let deviceID = '';
1157
+ let resolutionX = 0;
1158
+ let resolutionY = 0;
1159
+ if (dsections && dsections.length) {
1160
+ const linesDisplay = dsections[0].split('\n');
1161
+ vendor = util.getValue(linesDisplay, 'MonitorManufacturer', ':');
1162
+ model = util.getValue(linesDisplay, 'Name', ':');
1163
+ deviceID = util.getValue(linesDisplay, 'PNPDeviceID', ':').replace(/&amp;/g, '&').toLowerCase();
1164
+ resolutionX = util.toInt(util.getValue(linesDisplay, 'ScreenWidth', ':'));
1165
+ resolutionY = util.toInt(util.getValue(linesDisplay, 'ScreenHeight', ':'));
1166
+ }
1167
+ for (let i = 0; i < ssections.length; i++) {
1168
+ if (ssections[i].trim() !== '') {
1169
+ ssections[i] = 'BitsPerPixel ' + ssections[i];
1170
+ msections[i] = 'Active ' + msections[i];
1171
+ // tsections can be empty OR undefined on earlier versions of powershell (<=2.0)
1172
+ // Tag connection type as UNKNOWN by default if this information is missing
1173
+ if (tsections.length === 0 || tsections[i] === undefined) {
1174
+ tsections[i] = 'Unknown';
1175
+ }
1176
+ const linesScreen = ssections[i].split('\n');
1177
+ const linesMonitor = msections[i].split('\n');
1178
+
1179
+ const linesConnection = tsections[i].split('\n');
1180
+ const bitsPerPixel = util.getValue(linesScreen, 'BitsPerPixel');
1181
+ const bounds = util.getValue(linesScreen, 'Bounds').replace('{', '').replace('}', '').replace(/=/g, ':').split(',');
1182
+ const primary = util.getValue(linesScreen, 'Primary');
1183
+ const sizeX = util.getValue(linesMonitor, 'MaxHorizontalImageSize');
1184
+ const sizeY = util.getValue(linesMonitor, 'MaxVerticalImageSize');
1185
+ const instanceName = util.getValue(linesMonitor, 'InstanceName').toLowerCase();
1186
+ const videoOutputTechnology = util.getValue(linesConnection, 'VideoOutputTechnology');
1187
+ const deviceName = util.getValue(linesScreen, 'DeviceName');
1188
+ let displayVendor = '';
1189
+ let displayModel = '';
1190
+ isections.forEach((element) => {
1191
+ if (element.instanceId.toLowerCase().startsWith(instanceName) && vendor.startsWith('(') && model.startsWith('PnP')) {
1192
+ displayVendor = element.vendor;
1193
+ displayModel = element.model;
1194
+ }
1195
+ });
1196
+ displays.push({
1197
+ vendor: instanceName.startsWith(deviceID) && displayVendor === '' ? vendor : displayVendor,
1198
+ model: instanceName.startsWith(deviceID) && displayModel === '' ? model : displayModel,
1199
+ deviceName,
1200
+ main: primary.toLowerCase() === 'true',
1201
+ builtin: videoOutputTechnology === '2147483648',
1202
+ connection: videoOutputTechnology && videoTypes[videoOutputTechnology] ? videoTypes[videoOutputTechnology] : '',
1203
+ resolutionX: util.toInt(util.getValue(bounds, 'Width', ':')),
1204
+ resolutionY: util.toInt(util.getValue(bounds, 'Height', ':')),
1205
+ sizeX: sizeX ? parseInt(sizeX, 10) : null,
1206
+ sizeY: sizeY ? parseInt(sizeY, 10) : null,
1207
+ pixelDepth: bitsPerPixel,
1208
+ currentResX: util.toInt(util.getValue(bounds, 'Width', ':')),
1209
+ currentResY: util.toInt(util.getValue(bounds, 'Height', ':')),
1210
+ positionX: util.toInt(util.getValue(bounds, 'X', ':')),
1211
+ positionY: util.toInt(util.getValue(bounds, 'Y', ':'))
1212
+ });
1213
+ }
1214
+ }
1215
+ if (ssections.length === 0) {
1216
+ displays.push({
1217
+ vendor,
1218
+ model,
1219
+ main: true,
1220
+ sizeX: null,
1221
+ sizeY: null,
1222
+ resolutionX,
1223
+ resolutionY,
1224
+ pixelDepth: null,
1225
+ currentResX: resolutionX,
1226
+ currentResY: resolutionY,
1227
+ positionX: 0,
1228
+ positionY: 0
1229
+ });
1230
+ }
1231
+ return displays;
1232
+ }
1233
+ }
1234
+
1235
+ exports.graphics = graphics;