1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | const os = require('os');
|
17 | const exec = require('child_process').exec;
|
18 | const execSync = require('child_process').execSync;
|
19 | const util = require('./util');
|
20 |
|
21 | let _platform = process.platform;
|
22 |
|
23 | const _linux = (_platform === 'linux');
|
24 | const _darwin = (_platform === 'darwin');
|
25 | const _windows = (_platform === 'win32');
|
26 | const _freebsd = (_platform === 'freebsd');
|
27 | const _openbsd = (_platform === 'openbsd');
|
28 | const _netbsd = (_platform === 'netbsd');
|
29 | const _sunos = (_platform === 'sunos');
|
30 |
|
31 | let _resolutionx = 0;
|
32 | let _resolutiony = 0;
|
33 | let _pixeldepth = 0;
|
34 | let _refreshrate = 0;
|
35 |
|
36 | const 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 |
|
57 | function 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) {
|
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) {
|
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) {
|
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]);
|
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]);
|
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) {
|
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) {
|
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]);
|
172 | if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('framebufferdepth') !== -1) currentDisplay.pixeldepth = parseInt(parts[1]);
|
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) {
|
186 | controllers.push(currentController);
|
187 | }
|
188 | if (Object.keys(currentDisplay).length > 0) {
|
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 |
|
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]) {
|
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) {
|
227 | if (_3dcontrollerpos !== -1 && vgapos === -1) {
|
228 | vgapos = _3dcontrollerpos;
|
229 | }
|
230 | if (currentController.vendor || currentController.model || currentController.bus || currentController.vram !== -1 || currentController.vramDynamic) {
|
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) {
|
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) {
|
290 | controllers.push(currentController);
|
291 | }
|
292 | return (controllers);
|
293 | }
|
294 |
|
295 | function parseLinesLinuxEdid(edid) {
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 |
|
303 |
|
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 |
|
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 |
|
340 | start = edid.indexOf('000000fc00');
|
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++) {
|
385 | if ('' !== lines[i].trim()) {
|
386 | if (' ' !== lines[i][0] && '\t' !== lines[i][0] && lines[i].toLowerCase().indexOf(' connected ') !== -1) {
|
387 | if (currentDisplay.model || currentDisplay.main || currentDisplay.builtin || currentDisplay.connection || currentDisplay.sizex !== -1 || currentDisplay.pixeldepth !== -1 || currentDisplay.resolutionx !== -1) {
|
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 |
|
414 | if (is_edid) {
|
415 | if (lines[i].search(/\S|$/) > start) {
|
416 | edid_raw += lines[i].toLowerCase().trim();
|
417 | } else {
|
418 |
|
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 |
|
454 | if (currentDisplay.model || currentDisplay.main || currentDisplay.builtin || currentDisplay.connection || currentDisplay.sizex !== -1 || currentDisplay.pixeldepth !== -1 || currentDisplay.resolutionx !== -1) {
|
455 | displays.push(currentDisplay);
|
456 | }
|
457 | return displays;
|
458 | }
|
459 |
|
460 |
|
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 |
|
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 |
|
562 |
|
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 |
|
576 | let csections = data[0].split(/\n\s*\n/);
|
577 | result.controllers = parseLinesWindowsControllers(csections);
|
578 |
|
579 |
|
580 | let dsections = data[1].split(/\n\s*\n/);
|
581 |
|
582 | dsections.shift();
|
583 | dsections.pop();
|
584 |
|
585 |
|
586 | let msections = data[2].split('Active ');
|
587 | msections.shift();
|
588 |
|
589 |
|
590 | let ssections = data[3].split('BitsPerPixel ');
|
591 | ssections.shift();
|
592 |
|
593 |
|
594 | let tsections = data[4].split(/\n\s*\n/);
|
595 | tsections.shift();
|
596 |
|
597 |
|
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 |
|
679 |
|
680 |
|
681 |
|
682 |
|
683 |
|
684 |
|
685 |
|
686 |
|
687 |
|
688 |
|
689 |
|
690 |
|
691 |
|
692 |
|
693 |
|
694 |
|
695 |
|
696 |
|
697 |
|
698 |
|
699 |
|
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(/&/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 |
|
779 | exports.graphics = graphics;
|