UNPKG

31.3 kBJavaScriptView Raw
1'use strict';
2// @ts-check
3// ==================================================================================
4// graphics.js
5// ----------------------------------------------------------------------------------
6// Description: System Information - library
7// for Node.js
8// Copyright: (c) 2014 - 2020
9// Author: Sebastian Hildebrandt
10// ----------------------------------------------------------------------------------
11// License: MIT
12// ==================================================================================
13// 7. Graphics (controller, display)
14// ----------------------------------------------------------------------------------
15
16const os = require('os');
17const exec = require('child_process').exec;
18const execSync = require('child_process').execSync;
19const util = require('./util');
20
21let _platform = process.platform;
22
23const _linux = (_platform === 'linux');
24const _darwin = (_platform === 'darwin');
25const _windows = (_platform === 'win32');
26const _freebsd = (_platform === 'freebsd');
27const _openbsd = (_platform === 'openbsd');
28const _netbsd = (_platform === 'netbsd');
29const _sunos = (_platform === 'sunos');
30
31let _resolutionx = 0;
32let _resolutiony = 0;
33let _pixeldepth = 0;
34let _refreshrate = 0;
35
36const videoTypes = {
37 '-2': 'UNINITIALIZED',
38 '-1': 'OTHER',
39 '0': 'HD15',
40 '1': 'SVIDEO',
41 '2': 'Composite video',
42 '3': 'Component video',
43 '4': 'DVI',
44 '5': 'HDMI',
45 '6': 'LVDS',
46 '8': 'D_JPN',
47 '9': 'SDI',
48 '10': 'DP',
49 '11': 'DP embedded',
50 '12': 'UDI',
51 '13': 'UDI embedded',
52 '14': 'SDTVDONGLE',
53 '15': 'MIRACAST',
54 '2147483648': 'INTERNAL'
55};
56
57function graphics(callback) {
58
59 function parseLinesDarwin(lines) {
60 let starts = [];
61 let level = -1;
62 let lastlevel = -1;
63 let controllers = [];
64 let displays = [];
65 let currentController = {
66 vendor: '',
67 model: '',
68 bus: '',
69 vram: -1,
70 vramDynamic: false
71 };
72 let currentDisplay = {
73 vendor: '',
74 model: '',
75 main: false,
76 builtin: false,
77 connection: '',
78 sizex: -1,
79 sizey: -1,
80 pixeldepth: -1,
81 resolutionx: -1,
82 resolutiony: -1,
83 currentResX: -1,
84 currentResY: -1,
85 positionX: 0,
86 positionY: 0,
87 currentRefreshRate: -1
88 };
89 for (let i = 0; i < lines.length; i++) {
90 if ('' !== lines[i].trim()) {
91 let start = lines[i].search(/\S|$/);
92 if (-1 === starts.indexOf(start)) {
93 starts.push(start);
94 }
95 level = starts.indexOf(start);
96 if (level < lastlevel) {
97 if (Object.keys(currentController).length > 0) {// just changed to Displays
98 controllers.push(currentController);
99 currentController = {
100 vendor: '',
101 model: '',
102 bus: '',
103 vram: -1,
104 vramDynamic: false
105 };
106 }
107 if (Object.keys(currentDisplay).length > 0) {// just changed to Displays
108 displays.push(currentDisplay);
109 currentDisplay = {
110 vendor: '',
111 model: '',
112 main: false,
113 builtin: false,
114 connection: '',
115 sizex: -1,
116 sizey: -1,
117 pixeldepth: -1,
118 resolutionx: -1,
119 resolutiony: -1,
120 currentResX: -1,
121 currentResY: -1,
122 positionX: 0,
123 positionY: 0,
124 currentRefreshRate: -1
125 };
126 }
127 }
128 lastlevel = level;
129 let parts = lines[i].split(':');
130 if (2 === level) { // grafics controller level
131 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('chipsetmodel') !== -1) currentController.model = parts[1].trim();
132 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('bus') !== -1) currentController.bus = parts[1].trim();
133 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('vendor') !== -1) currentController.vendor = parts[1].split('(')[0].trim();
134 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('vram(total)') !== -1) {
135 currentController.vram = parseInt(parts[1]); // in MB
136 if (parts[1].toLowerCase().indexOf('gb') !== -1) {
137 currentController.vram = currentController.vram * 1024;
138 }
139 currentController.vramDynamic = false;
140 }
141 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('vram(dynamic,max)') !== -1) {
142 currentController.vram = parseInt(parts[1]); // in MB
143 if (parts[1].toLowerCase().indexOf('gb') !== -1) {
144 currentController.vram = currentController.vram * 1024;
145 }
146 currentController.vramDynamic = true;
147 }
148 }
149 if (3 === level) { // display controller level
150 if (parts.length > 1 && '' === parts[1]) {
151 currentDisplay.vendor = '';
152 currentDisplay.model = parts[0].trim();
153 currentDisplay.main = false;
154 currentDisplay.builtin = false;
155 currentDisplay.connection = '';
156 currentDisplay.sizex = -1;
157 currentDisplay.sizey = -1;
158 currentDisplay.positionX = 0;
159 currentDisplay.positionY = 0;
160 currentDisplay.pixeldepth = -1;
161 }
162 }
163 if (4 === level) { // display controller details level
164 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('resolution') !== -1) {
165 let resolution = parts[1].split('x');
166 currentDisplay.resolutionx = (resolution.length > 1 ? parseInt(resolution[0]) : 0);
167 currentDisplay.resolutiony = (resolution.length > 1 ? parseInt(resolution[1]) : 0);
168 currentDisplay.currentResX = currentDisplay.resolutionx;
169 currentDisplay.currentResY = currentDisplay.resolutiony;
170 }
171 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('pixeldepth') !== -1) currentDisplay.pixeldepth = parseInt(parts[1]); // in BIT
172 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('framebufferdepth') !== -1) currentDisplay.pixeldepth = parseInt(parts[1]); // in BIT
173 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('maindisplay') !== -1 && parts[1].replace(/ +/g, '').toLowerCase() === 'yes') currentDisplay.main = true;
174 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('built-in') !== -1 && parts[1].replace(/ +/g, '').toLowerCase() === 'yes') {
175 currentDisplay.builtin = true;
176 currentDisplay.connection = '';
177 }
178 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('connectiontype') !== -1) {
179 currentDisplay.builtin = false;
180 currentDisplay.connection = parts[1].trim();
181 }
182 }
183 }
184 }
185 if (Object.keys(currentController).length > 0) {// just changed to Displays
186 controllers.push(currentController);
187 }
188 if (Object.keys(currentDisplay).length > 0) {// just changed to Displays
189 displays.push(currentDisplay);
190 }
191 return ({
192 controllers: controllers,
193 displays: displays
194 });
195 }
196
197 function parseLinesLinuxControllers(lines) {
198 let controllers = [];
199 let currentController = {
200 vendor: '',
201 model: '',
202 bus: '',
203 vram: -1,
204 vramDynamic: false
205 };
206 let isGraphicsController = false;
207 // PCI bus IDs
208 let pciIDs = [];
209 try {
210 pciIDs = execSync('export LC_ALL=C; dmidecode -t 9 2>/dev/null; unset LC_ALL | grep "Bus Address: "').toString().split('\n');
211 for (let i = 0; i < pciIDs.length; i++) {
212 pciIDs[i] = pciIDs[i].replace('Bus Address:', '').replace('0000:', '').trim();
213 }
214 pciIDs = pciIDs.filter(function (el) {
215 return el != null && el;
216 });
217 } catch (e) {
218 util.noop();
219 }
220 for (let i = 0; i < lines.length; i++) {
221 if ('' !== lines[i].trim()) {
222 if (' ' !== lines[i][0] && '\t' !== lines[i][0]) { // first line of new entry
223 let isExternal = (pciIDs.indexOf(lines[i].split(' ')[0]) >= 0);
224 let vgapos = lines[i].toLowerCase().indexOf(' vga ');
225 let _3dcontrollerpos = lines[i].toLowerCase().indexOf('3d controller');
226 if (vgapos !== -1 || _3dcontrollerpos !== -1) { // VGA
227 if (_3dcontrollerpos !== -1 && vgapos === -1) {
228 vgapos = _3dcontrollerpos;
229 }
230 if (currentController.vendor || currentController.model || currentController.bus || currentController.vram !== -1 || currentController.vramDynamic) { // already a controller found
231 controllers.push(currentController);
232 currentController = {
233 vendor: '',
234 model: '',
235 bus: '',
236 vram: -1,
237 vramDynamic: false
238 };
239 }
240 isGraphicsController = true;
241 let endpos = lines[i].search(/\[[0-9a-f]{4}:[0-9a-f]{4}]|$/);
242 let parts = lines[i].substr(vgapos, endpos - vgapos).split(':');
243 if (parts.length > 1) {
244 parts[1] = parts[1].trim();
245 if (parts[1].toLowerCase().indexOf('corporation') >= 0) {
246 currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf('corporation') + 11).trim();
247 currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf('corporation') + 11, 200).trim().split('(')[0];
248 currentController.bus = (pciIDs.length > 0 && isExternal) ? 'PCIe' : 'Onboard';
249 currentController.vram = -1;
250 currentController.vramDynamic = false;
251 } else if (parts[1].toLowerCase().indexOf(' inc.') >= 0) {
252 if ((parts[1].match(new RegExp(']', 'g')) || []).length > 1) {
253 currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(']') + 1).trim();
254 currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(']') + 1, 200).trim().split('(')[0].trim();
255 } else {
256 currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(' inc.') + 5).trim();
257 currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(' inc.') + 5, 200).trim().split('(')[0].trim();
258 }
259 currentController.bus = (pciIDs.length > 0 && isExternal) ? 'PCIe' : 'Onboard';
260 currentController.vram = -1;
261 currentController.vramDynamic = false;
262 } else if (parts[1].toLowerCase().indexOf(' ltd.') >= 0) {
263 if ((parts[1].match(new RegExp(']', 'g')) || []).length > 1) {
264 currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(']') + 1).trim();
265 currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(']') + 1, 200).trim().split('(')[0].trim();
266 } else {
267 currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf(' ltd.') + 5).trim();
268 currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf(' ltd.') + 5, 200).trim().split('(')[0].trim();
269 }
270 }
271 }
272
273 } else {
274 isGraphicsController = false;
275 }
276 }
277 if (isGraphicsController) { // within VGA details
278 let parts = lines[i].split(':');
279 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('devicename') !== -1 && parts[1].toLowerCase().indexOf('onboard') !== -1) currentController.bus = 'Onboard';
280 if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('region') !== -1 && parts[1].toLowerCase().indexOf('memory') !== -1) {
281 let memparts = parts[1].split('=');
282 if (memparts.length > 1) {
283 currentController.vram = parseInt(memparts[1]);
284 }
285 }
286 }
287 }
288 }
289 if (currentController.vendor || currentController.model || currentController.bus || currentController.vram !== -1 || currentController.vramDynamic) { // already a controller found
290 controllers.push(currentController);
291 }
292 return (controllers);
293 }
294
295 function parseLinesLinuxEdid(edid) {
296 // parsen EDID
297 // --> model
298 // --> resolutionx
299 // --> resolutiony
300 // --> builtin = false
301 // --> pixeldepth (?)
302 // --> sizex
303 // --> sizey
304 let result = {
305 vendor: '',
306 model: '',
307 main: false,
308 builtin: false,
309 connection: '',
310 sizex: -1,
311 sizey: -1,
312 pixeldepth: -1,
313 resolutionx: -1,
314 resolutiony: -1,
315 currentResX: -1,
316 currentResY: -1,
317 positionX: 0,
318 positionY: 0,
319 currentRefreshRate: -1
320 };
321 // find first "Detailed Timing Description"
322 let start = 108;
323 if (edid.substr(start, 6) === '000000') {
324 start += 36;
325 }
326 if (edid.substr(start, 6) === '000000') {
327 start += 36;
328 }
329 if (edid.substr(start, 6) === '000000') {
330 start += 36;
331 }
332 if (edid.substr(start, 6) === '000000') {
333 start += 36;
334 }
335 result.resolutionx = parseInt('0x0' + edid.substr(start + 8, 1) + edid.substr(start + 4, 2));
336 result.resolutiony = parseInt('0x0' + edid.substr(start + 14, 1) + edid.substr(start + 10, 2));
337 result.sizex = parseInt('0x0' + edid.substr(start + 28, 1) + edid.substr(start + 24, 2));
338 result.sizey = parseInt('0x0' + edid.substr(start + 29, 1) + edid.substr(start + 26, 2));
339 // monitor name
340 start = edid.indexOf('000000fc00'); // find first "Monitor Description Data"
341 if (start >= 0) {
342 let model_raw = edid.substr(start + 10, 26);
343 if (model_raw.indexOf('0a') !== -1) {
344 model_raw = model_raw.substr(0, model_raw.indexOf('0a'));
345 }
346 try {
347 if (model_raw.length > 2) {
348 result.model = model_raw.match(/.{1,2}/g).map(function (v) {
349 return String.fromCharCode(parseInt(v, 16));
350 }).join('');
351 }
352 } catch (e) {
353 util.noop();
354 }
355 } else {
356 result.model = '';
357 }
358 return result;
359 }
360
361 function parseLinesLinuxDisplays(lines, depth) {
362 let displays = [];
363 let currentDisplay = {
364 vendor: '',
365 model: '',
366 main: false,
367 builtin: false,
368 connection: '',
369 sizex: -1,
370 sizey: -1,
371 pixeldepth: -1,
372 resolutionx: -1,
373 resolutiony: -1,
374 currentResX: -1,
375 currentResY: -1,
376 positionX: 0,
377 positionY: 0,
378 currentRefreshRate: -1
379 };
380 let is_edid = false;
381 let is_current = false;
382 let edid_raw = '';
383 let start = 0;
384 for (let i = 1; i < lines.length; i++) { // start with second line
385 if ('' !== lines[i].trim()) {
386 if (' ' !== lines[i][0] && '\t' !== lines[i][0] && lines[i].toLowerCase().indexOf(' connected ') !== -1) { // first line of new entry
387 if (currentDisplay.model || currentDisplay.main || currentDisplay.builtin || currentDisplay.connection || currentDisplay.sizex !== -1 || currentDisplay.pixeldepth !== -1 || currentDisplay.resolutionx !== -1) { // push last display to array
388 displays.push(currentDisplay);
389 currentDisplay = {
390 vendor: '',
391 model: '',
392 main: false,
393 builtin: false,
394 connection: '',
395 sizex: -1,
396 sizey: -1,
397 pixeldepth: -1,
398 resolutionx: -1,
399 resolutiony: -1,
400 currentResX: -1,
401 currentResY: -1,
402 positionX: 0,
403 positionY: 0,
404 currentRefreshRate: -1
405 };
406 }
407 let parts = lines[i].split(' ');
408 currentDisplay.connection = parts[0];
409 currentDisplay.main = lines[i].toLowerCase().indexOf(' primary ') >= 0;
410 currentDisplay.builtin = (parts[0].toLowerCase().indexOf('edp') >= 0);
411 }
412
413 // try to read EDID information
414 if (is_edid) {
415 if (lines[i].search(/\S|$/) > start) {
416 edid_raw += lines[i].toLowerCase().trim();
417 } else {
418 // parsen EDID
419 let edid_decoded = parseLinesLinuxEdid(edid_raw);
420 currentDisplay.vendor = edid_decoded.vendor;
421 currentDisplay.model = edid_decoded.model;
422 currentDisplay.resolutionx = edid_decoded.resolutionx;
423 currentDisplay.resolutiony = edid_decoded.resolutiony;
424 currentDisplay.sizex = edid_decoded.sizex;
425 currentDisplay.sizey = edid_decoded.sizey;
426 currentDisplay.pixeldepth = depth;
427 is_edid = false;
428 }
429 }
430 if (lines[i].toLowerCase().indexOf('edid:') >= 0) {
431 is_edid = true;
432 start = lines[i].search(/\S|$/);
433 }
434 if (lines[i].toLowerCase().indexOf('*current') >= 0) {
435 const parts1 = lines[i].split('(');
436 if (parts1 && parts1.length > 1 && parts1[0].indexOf('x') >= 0) {
437 const resParts = parts1[0].trim().split('x');
438 currentDisplay.currentResX = util.toInt(resParts[0]);
439 currentDisplay.currentResY = util.toInt(resParts[1]);
440 }
441 is_current = true;
442 }
443 if (is_current && lines[i].toLowerCase().indexOf('clock') >= 0 && lines[i].toLowerCase().indexOf('hz') >= 0 && lines[i].toLowerCase().indexOf('v: height') >= 0) {
444 const parts1 = lines[i].split('clock');
445 if (parts1 && parts1.length > 1 && parts1[1].toLowerCase().indexOf('hz') >= 0) {
446 currentDisplay.currentRefreshRate = util.toInt(parts1[1]);
447 }
448 is_current = false;
449 }
450 }
451 }
452
453 // pushen displays
454 if (currentDisplay.model || currentDisplay.main || currentDisplay.builtin || currentDisplay.connection || currentDisplay.sizex !== -1 || currentDisplay.pixeldepth !== -1 || currentDisplay.resolutionx !== -1) { // still information there
455 displays.push(currentDisplay);
456 }
457 return displays;
458 }
459
460 // function starts here
461 return new Promise((resolve) => {
462 process.nextTick(() => {
463 let result = {
464 controllers: [],
465 displays: []
466 };
467 if (_darwin) {
468 let cmd = 'system_profiler SPDisplaysDataType';
469 exec(cmd, function (error, stdout) {
470 if (!error) {
471 let lines = stdout.toString().split('\n');
472 result = parseLinesDarwin(lines);
473 }
474 if (callback) {
475 callback(result);
476 }
477 resolve(result);
478 });
479 }
480 if (_linux) {
481 // Raspberry: https://elinux.org/RPI_vcgencmd_usage
482 if (util.isRaspberry() && util.isRaspbian()) {
483 let cmd = 'fbset -s | grep \'mode "\'; vcgencmd get_mem gpu; tvservice -s; tvservice -n;';
484 exec(cmd, function (error, stdout) {
485 let lines = stdout.toString().split('\n');
486 if (lines.length > 3 && lines[0].indexOf('mode "') >= -1 && lines[2].indexOf('0x12000a') > -1) {
487 const parts = lines[0].replace('mode', '').replace(/"/g, '').trim().split('x');
488 if (parts.length === 2) {
489 result.displays.push({
490 vendor: '',
491 model: util.getValue(lines, 'device_name', '='),
492 main: true,
493 builtin: false,
494 connection: 'HDMI',
495 sizex: -1,
496 sizey: -1,
497 pixeldepth: -1,
498 resolutionx: parseInt(parts[0], 10),
499 resolutiony: parseInt(parts[1], 10),
500 currentResX: -1,
501 currentResY: -1,
502 positionX: 0,
503 positionY: 0,
504 currentRefreshRate: -1
505 });
506 }
507 }
508 if (lines.length > 1 && lines[1].indexOf('gpu=') >= -1) {
509 result.controllers.push({
510 vendor: 'Broadcom',
511 model: 'VideoCore IV',
512 bus: '',
513 vram: lines[1].replace('gpu=', ''),
514 vramDynamic: true
515 });
516 }
517 if (callback) {
518 callback(result);
519 }
520 resolve(result);
521 });
522 } else {
523 let cmd = 'lspci -vvv 2>/dev/null';
524 exec(cmd, function (error, stdout) {
525 if (!error) {
526 let lines = stdout.toString().split('\n');
527 result.controllers = parseLinesLinuxControllers(lines);
528 }
529 let cmd = 'xdpyinfo 2>/dev/null | grep \'depth of root window\' | awk \'{ print $5 }\'';
530 exec(cmd, function (error, stdout) {
531 let depth = 0;
532 if (!error) {
533 let lines = stdout.toString().split('\n');
534 depth = parseInt(lines[0]) || 0;
535 }
536 let cmd = 'xrandr --verbose 2>/dev/null';
537 exec(cmd, function (error, stdout) {
538 if (!error) {
539 let lines = stdout.toString().split('\n');
540 result.displays = parseLinesLinuxDisplays(lines, depth);
541 }
542 if (callback) {
543 callback(result);
544 }
545 resolve(result);
546 });
547 });
548 });
549 }
550 }
551 if (_freebsd || _openbsd || _netbsd) {
552 if (callback) { callback(result); }
553 resolve(result);
554 }
555 if (_sunos) {
556 if (callback) { callback(result); }
557 resolve(result);
558 }
559 if (_windows) {
560
561 // https://blogs.technet.microsoft.com/heyscriptingguy/2013/10/03/use-powershell-to-discover-multi-monitor-information/
562 // https://devblogs.microsoft.com/scripting/use-powershell-to-discover-multi-monitor-information/
563 try {
564 const workload = [];
565 workload.push(util.wmic('path win32_VideoController get /value'));
566 workload.push(util.wmic('path win32_desktopmonitor get /value'));
567 workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorBasicDisplayParams | fl'));
568 workload.push(util.powerShell('Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Screen]::AllScreens'));
569 workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorConnectionParams | fl'));
570 workload.push(util.powerShell('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}'));
571
572 Promise.all(
573 workload
574 ).then(data => {
575 // controller
576 let csections = data[0].split(/\n\s*\n/);
577 result.controllers = parseLinesWindowsControllers(csections);
578
579 // displays
580 let dsections = data[1].split(/\n\s*\n/);
581 // result.displays = parseLinesWindowsDisplays(dsections);
582 dsections.shift();
583 dsections.pop();
584
585 // monitor (powershell)
586 let msections = data[2].split('Active ');
587 msections.shift();
588
589 // forms.screens (powershell)
590 let ssections = data[3].split('BitsPerPixel ');
591 ssections.shift();
592
593 // connection params (powershell) - video type
594 let tsections = data[4].split(/\n\s*\n/);
595 tsections.shift();
596
597 // monitor ID (powershell) - model / vendor
598 const res = data[5].split(/\r\n/);
599 let isections = [];
600 res.forEach(element => {
601 const parts = element.split('|');
602 if (parts.length === 5) {
603 isections.push({
604 vendor: parts[0],
605 code: parts[1],
606 model: parts[2],
607 serial: parts[3],
608 instanceId: parts[4]
609 });
610 }
611 });
612 result.displays = parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections, isections);
613
614 if (result.displays.length === 1) {
615 if (_resolutionx) {
616 result.displays[0].resolutionx = _resolutionx;
617 if (!result.displays[0].currentResX) {
618 result.displays[0].currentResX = _resolutionx;
619 }
620 }
621 if (_resolutiony) {
622 result.displays[0].resolutiony = _resolutiony;
623 if (result.displays[0].currentResY === 0) {
624 result.displays[0].currentResY = _resolutiony;
625 }
626 }
627 if (_pixeldepth) {
628 result.displays[0].pixeldepth = _pixeldepth;
629 }
630 if (_refreshrate && !result.displays[0].refreshrate) {
631 result.displays[0].currentRefreshRate = _refreshrate;
632 }
633 }
634
635 if (callback) {
636 callback(result);
637 }
638 resolve(result);
639 })
640 .catch(() => {
641 if (callback) {
642 callback(result);
643 }
644 resolve(result);
645 });
646 } catch (e) {
647 if (callback) { callback(result); }
648 resolve(result);
649 }
650 }
651 });
652 });
653
654 function parseLinesWindowsControllers(sections) {
655 let controllers = [];
656 for (let i in sections) {
657 if ({}.hasOwnProperty.call(sections, i)) {
658 if (sections[i].trim() !== '') {
659
660 let lines = sections[i].trim().split('\r\n');
661 controllers.push({
662 vendor: util.getValue(lines, 'AdapterCompatibility', '='),
663 model: util.getValue(lines, 'name', '='),
664 bus: util.getValue(lines, 'PNPDeviceID', '=').startsWith('PCI') ? 'PCI' : '',
665 vram: parseInt(util.getValue(lines, 'AdapterRAM', '='), 10) / 1024 / 1024,
666 vramDynamic: (util.getValue(lines, 'VideoMemoryType', '=') === '2')
667 });
668 _resolutionx = util.toInt(util.getValue(lines, 'CurrentHorizontalResolution', '=')) || _resolutionx;
669 _resolutiony = util.toInt(util.getValue(lines, 'CurrentVerticalResolution', '=')) || _resolutiony;
670 _refreshrate = util.toInt(util.getValue(lines, 'CurrentRefreshRate', '=')) || _refreshrate;
671 _pixeldepth = util.toInt(util.getValue(lines, 'CurrentBitsPerPixel', '=')) || _pixeldepth;
672 }
673 }
674 }
675 return controllers;
676 }
677
678 // function parseLinesWindowsDisplays(sections) {
679 // let displays = [];
680 // for (let i in sections) {
681 // if (sections.hasOwnProperty(i)) {
682 // if (sections[i].trim() !== '') {
683 // let lines = sections[i].trim().split('\r\n');
684 // displays.push({
685 // vendor: util.getValue(lines, 'MonitorManufacturer', '='),
686 // model: util.getValue(lines, 'Name', '='),
687 // main: false,
688 // builtin: false,
689 // connection: '',
690 // sizex: -1,
691 // sizey: -1,
692 // pixeldepth: -1,
693 // resolutionx: util.toInt(util.getValue(lines, 'ScreenWidth', '=')),
694 // resolutiony: util.toInt(util.getValue(lines, 'ScreenHeight', '=')),
695 // });
696 // }
697 // }
698 // }
699 // return displays;
700 // }
701
702 function parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections, isections) {
703 let displays = [];
704 let vendor = '';
705 let model = '';
706 let deviceID = '';
707 let resolutionx = 0;
708 let resolutiony = 0;
709 if (dsections && dsections.length) {
710 let linesDisplay = dsections[0].split(os.EOL);
711 vendor = util.getValue(linesDisplay, 'MonitorManufacturer', '=');
712 model = util.getValue(linesDisplay, 'Name', '=');
713 deviceID = util.getValue(linesDisplay, 'PNPDeviceID', '=').replace(/&amp;/g, '&').toLowerCase();
714 resolutionx = util.toInt(util.getValue(linesDisplay, 'ScreenWidth', '='));
715 resolutiony = util.toInt(util.getValue(linesDisplay, 'ScreenHeight', '='));
716 }
717 for (let i = 0; i < ssections.length; i++) {
718 if (ssections[i].trim() !== '') {
719 ssections[i] = 'BitsPerPixel ' + ssections[i];
720 msections[i] = 'Active ' + msections[i];
721
722 let linesScreen = ssections[i].split(os.EOL);
723 let linesMonitor = msections[i].split(os.EOL);
724 let linesConnection = tsections[i].split(os.EOL);
725 const bitsPerPixel = util.getValue(linesScreen, 'BitsPerPixel');
726 const bounds = util.getValue(linesScreen, 'Bounds').replace('{', '').replace('}', '').split(',');
727 const primary = util.getValue(linesScreen, 'Primary');
728 const sizex = util.getValue(linesMonitor, 'MaxHorizontalImageSize');
729 const sizey = util.getValue(linesMonitor, 'MaxVerticalImageSize');
730 const instanceName = util.getValue(linesMonitor, 'InstanceName').toLowerCase();
731 const videoOutputTechnology = util.getValue(linesConnection, 'VideoOutputTechnology');
732 let displayVendor = '';
733 let displayModel = '';
734 isections.forEach(element => {
735 if (element.instanceId.toLowerCase().startsWith(instanceName) && vendor.startsWith('(') && model.startsWith('PnP')) {
736 displayVendor = element.vendor;
737 displayModel = element.model;
738 }
739 });
740 displays.push({
741 vendor: instanceName.startsWith(deviceID) && displayVendor === '' ? vendor : displayVendor,
742 model: instanceName.startsWith(deviceID) && displayModel === '' ? model : displayModel,
743 main: primary.toLowerCase() === 'true',
744 builtin: videoOutputTechnology === '2147483648',
745 connection: videoOutputTechnology && videoTypes[videoOutputTechnology] ? videoTypes[videoOutputTechnology] : '',
746 resolutionx: util.toInt(util.getValue(bounds, 'Width', '=')),
747 resolutiony: util.toInt(util.getValue(bounds, 'Height', '=')),
748 sizex: sizex ? parseInt(sizex, 10) : -1,
749 sizey: sizey ? parseInt(sizey, 10) : -1,
750 pixeldepth: bitsPerPixel,
751 currentResX: util.toInt(util.getValue(bounds, 'Width', '=')),
752 currentResY: util.toInt(util.getValue(bounds, 'Height', '=')),
753 positionX: util.toInt(util.getValue(bounds, 'X', '=')),
754 positionY: util.toInt(util.getValue(bounds, 'Y', '=')),
755 });
756 }
757 }
758 if (ssections.length === 0) {
759 displays.push({
760 vendor,
761 model,
762 main: true,
763 resolutionx,
764 resolutiony,
765 sizex: -1,
766 sizey: -1,
767 pixeldepth: -1,
768 currentResX: resolutionx,
769 currentResY: resolutiony,
770 positionX: 0,
771 positionY: 0
772 });
773 }
774 return displays;
775 }
776
777}
778
779exports.graphics = graphics;