@midscene/computer 1.13.1-beta-20260921034220.0 → 1.13.1-beta-20260921075813.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.
package/dist/es/cli.mjs CHANGED
@@ -461,8 +461,12 @@ if ($midscenePreviousDpiContext -eq [System.IntPtr]::Zero) {
461
461
  throw 'Unable to enter the Per-Monitor V2 DPI awareness context.'
462
462
  }
463
463
  `.trim();
464
- function runWindowsPowershellScript(script) {
465
- const encoded = Buffer.from(script, 'utf16le').toString('base64');
464
+ function runWindowsPhysicalPixelPowershell(script) {
465
+ const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
466
+ $ErrorActionPreference = 'Stop'
467
+ ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
468
+ ${script}`;
469
+ const encoded = Buffer.from(physicalPixelScript, 'utf16le').toString('base64');
466
470
  return execFileSync('powershell.exe', [
467
471
  '-NoProfile',
468
472
  '-NonInteractive',
@@ -475,130 +479,6 @@ function runWindowsPowershellScript(script) {
475
479
  windowsHide: true
476
480
  });
477
481
  }
478
- function runWindowsPowershellCommand(script) {
479
- return execFileSync('powershell.exe', [
480
- '-NoProfile',
481
- '-Command',
482
- script
483
- ], {
484
- encoding: 'utf8',
485
- timeout: POWERSHELL_TIMEOUT_MS,
486
- maxBuffer: POWERSHELL_MAX_BUFFER,
487
- windowsHide: true
488
- });
489
- }
490
- function runWindowsPowershell(script) {
491
- return runWindowsPowershellCommand(`$ProgressPreference = 'SilentlyContinue'
492
- $ErrorActionPreference = 'Stop'
493
- ${script}`);
494
- }
495
- function runWindowsPhysicalPixelPowershell(script) {
496
- const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
497
- $ErrorActionPreference = 'Stop'
498
- ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
499
- ${script}`;
500
- return runWindowsPowershellScript(physicalPixelScript);
501
- }
502
- class WindowsDisplayEnumerationEmptyError extends Error {
503
- }
504
- function isFiniteNumber(value) {
505
- return 'number' == typeof value && Number.isFinite(value);
506
- }
507
- function isWindowsDisplayGeometry(value) {
508
- if (!value || 'object' != typeof value) return false;
509
- const candidate = value;
510
- const bounds = candidate.bounds;
511
- return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && !!bounds && isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
512
- }
513
- function readWindowsDisplayGeometriesWith(runPowershell, context) {
514
- const serializeScreens = 'legacy' === context ? 'ConvertTo-Json -InputObject $screens -Compress' : '[Console]::Out.Write((ConvertTo-Json -InputObject $screens -Compress))';
515
- const script = `
516
- Add-Type -AssemblyName System.Windows.Forms
517
- $screens = @([System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
518
- $bounds = $_.Bounds
519
- [PSCustomObject]@{
520
- id = $_.DeviceName
521
- name = $_.DeviceName
522
- primary = $_.Primary
523
- bounds = [PSCustomObject]@{
524
- x = $bounds.X
525
- y = $bounds.Y
526
- width = $bounds.Width
527
- height = $bounds.Height
528
- }
529
- }
530
- })
531
- ${serializeScreens}
532
- `.trim();
533
- const output = runPowershell(script).trim();
534
- if (!output) throw new WindowsDisplayEnumerationEmptyError(`Windows ${context} display enumeration returned no data`);
535
- const parsed = JSON.parse(output);
536
- if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
537
- const displays = parsed.filter(isWindowsDisplayGeometry);
538
- if (displays.length !== parsed.length) throw new Error('Windows display enumeration returned invalid geometry');
539
- if (0 === displays.length) throw new WindowsDisplayEnumerationEmptyError(`Windows ${context} display enumeration returned no displays`);
540
- return displays;
541
- }
542
- function readWindowsDisplayGeometries() {
543
- return readWindowsDisplayGeometriesWith(runWindowsPhysicalPixelPowershell, 'physical');
544
- }
545
- function discoverWindowsDisplays(runners = {
546
- physical: runWindowsPhysicalPixelPowershell,
547
- legacy: runWindowsPowershell
548
- }) {
549
- try {
550
- return {
551
- geometries: readWindowsDisplayGeometriesWith(runners.physical, 'physical'),
552
- coordinateMode: 'physical'
553
- };
554
- } catch (error) {
555
- if (!(error instanceof WindowsDisplayEnumerationEmptyError)) throw error;
556
- const geometries = readWindowsDisplayGeometriesWith(runners.legacy, 'legacy');
557
- return {
558
- geometries,
559
- coordinateMode: 'legacy'
560
- };
561
- }
562
- }
563
- function readPngDimensions(dataUri) {
564
- const prefix = 'data:image/png;base64,';
565
- if (!dataUri.startsWith(prefix)) throw new Error('Screenshot is not a PNG data URI');
566
- const buffer = Buffer.from(dataUri.slice(prefix.length), 'base64');
567
- const pngSignature = Buffer.from([
568
- 137,
569
- 80,
570
- 78,
571
- 71,
572
- 13,
573
- 10,
574
- 26,
575
- 10
576
- ]);
577
- if (buffer.length < 24 || !buffer.subarray(0, pngSignature.length).equals(pngSignature)) throw new Error('Screenshot returned invalid PNG data');
578
- const width = buffer.readUInt32BE(16);
579
- const height = buffer.readUInt32BE(20);
580
- if (width <= 0 || height <= 0) throw new Error('Screenshot returned invalid PNG dimensions');
581
- return {
582
- width,
583
- height
584
- };
585
- }
586
- function assertLegacyWindowsCoordinateCompatibility({ geometry, screenshotBase64, inputSize }) {
587
- if (!geometry?.primary) throw new Error('Windows legacy coordinate compatibility mode only supports the primary display');
588
- if (0 !== geometry.bounds.x || 0 !== geometry.bounds.y) throw new Error(`Windows legacy coordinate compatibility mode requires a primary display origin of (0, 0), got (${geometry.bounds.x}, ${geometry.bounds.y})`);
589
- const screenshotSize = readPngDimensions(screenshotBase64);
590
- const displaySize = {
591
- width: Math.round(geometry.bounds.width),
592
- height: Math.round(geometry.bounds.height)
593
- };
594
- const sizesMatch = screenshotSize.width === displaySize.width && screenshotSize.height === displaySize.height && inputSize.width === displaySize.width && inputSize.height === displaySize.height;
595
- if (!sizesMatch) throw new Error(`Windows legacy coordinate compatibility check failed: display=${displaySize.width}x${displaySize.height}, screenshot=${screenshotSize.width}x${screenshotSize.height}, input=${inputSize.width}x${inputSize.height}. Refusing to continue because clicks may use incorrect coordinates.`);
596
- }
597
- function resolveWindowsDisplayGeometryFromList(displayId, displays) {
598
- if (!displays.length) return;
599
- if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
600
- return displays.find((display)=>display.id === displayId);
601
- }
602
482
  function windows_pointer_define_property(obj, key, value) {
603
483
  if (key in obj) Object.defineProperty(obj, key, {
604
484
  value: value,
@@ -916,6 +796,28 @@ const EDGE_SCROLL_SPEC = {
916
796
  function escapePowershellSingleQuoted(value) {
917
797
  return value.replace(/'/g, "''");
918
798
  }
799
+ function readWindowsDisplayGeometries() {
800
+ const script = `
801
+ Add-Type -AssemblyName System.Windows.Forms
802
+ $s = [System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
803
+ $b = $_.Bounds
804
+ [PSCustomObject]@{
805
+ id = $_.DeviceName
806
+ name = $_.DeviceName
807
+ primary = $_.Primary
808
+ bounds = [PSCustomObject]@{ x = $b.X; y = $b.Y; width = $b.Width; height = $b.Height }
809
+ }
810
+ }
811
+ ConvertTo-Json @($s) -Compress
812
+ `.trim();
813
+ const output = runWindowsPhysicalPixelPowershell(script).trim();
814
+ if (!output) throw new Error('Windows display enumeration returned no data');
815
+ const parsed = JSON.parse(output);
816
+ if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
817
+ const displays = parsed.filter(isWindowsDisplayGeometry);
818
+ if (displays.length !== parsed.length || 0 === displays.length) throw new Error('Windows display enumeration returned invalid geometry');
819
+ return displays;
820
+ }
919
821
  function listWindowsDisplays(geometries = readWindowsDisplayGeometries()) {
920
822
  return geometries.map((display)=>({
921
823
  id: display.id,
@@ -1019,13 +921,23 @@ function getDisplayInfoBinary() {
1019
921
  displayInfoBinaryPath = binPath;
1020
922
  return binPath;
1021
923
  }
1022
- function device_isFiniteNumber(value) {
924
+ function isFiniteNumber(value) {
1023
925
  return 'number' == typeof value && Number.isFinite(value);
1024
926
  }
927
+ function isDisplayBounds(value) {
928
+ if (!value || 'object' != typeof value) return false;
929
+ const bounds = value;
930
+ return isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
931
+ }
932
+ function isWindowsDisplayGeometry(value) {
933
+ if (!value || 'object' != typeof value) return false;
934
+ const candidate = value;
935
+ return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && isDisplayBounds(candidate.bounds);
936
+ }
1025
937
  function isDarwinDisplayGeometry(value) {
1026
938
  if (!value || 'object' != typeof value) return false;
1027
939
  const candidate = value;
1028
- return Number.isInteger(candidate.screenIndex) && Number.isInteger(candidate.cgDisplayId) && 'boolean' == typeof candidate.primary && !!candidate.bounds && device_isFiniteNumber(candidate.bounds.x) && device_isFiniteNumber(candidate.bounds.y) && device_isFiniteNumber(candidate.bounds.width) && device_isFiniteNumber(candidate.bounds.height);
940
+ return Number.isInteger(candidate.screenIndex) && Number.isInteger(candidate.cgDisplayId) && 'boolean' == typeof candidate.primary && !!candidate.bounds && isFiniteNumber(candidate.bounds.x) && isFiniteNumber(candidate.bounds.y) && isFiniteNumber(candidate.bounds.width) && isFiniteNumber(candidate.bounds.height);
1029
941
  }
1030
942
  function readDarwinDisplayGeometries() {
1031
943
  const bin = getDisplayInfoBinary();
@@ -1095,6 +1007,11 @@ function resolveDarwinDisplayGeometryFromList(displayId, displays) {
1095
1007
  if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays.find((display)=>0 === display.screenIndex) || displays[0];
1096
1008
  return displays.find((display)=>display.screenIndex === screenIndex) || displays.find((display)=>display.cgDisplayId === screenIndex);
1097
1009
  }
1010
+ function resolveWindowsDisplayGeometryFromList(displayId, displays) {
1011
+ if (!displays.length) return;
1012
+ if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
1013
+ return displays.find((display)=>display.id === displayId);
1014
+ }
1098
1015
  function resolveDisplayGeometry(displayId, windowsDisplays) {
1099
1016
  if ('darwin' === process.platform) return resolveDarwinDisplayGeometryFromList(displayId, readDarwinDisplayGeometries());
1100
1017
  if ('win32' === process.platform) {
@@ -1187,24 +1104,13 @@ function normalizePrimaryKey(key) {
1187
1104
  return KEY_NAME_MAP[lowerKey] || lowerKey;
1188
1105
  }
1189
1106
  class ComputerDevice {
1190
- usesPhysicalWindowsCoordinates() {
1191
- return 'win32' === process.platform && 'physical' === this.windowsCoordinateContext.mode;
1192
- }
1193
- assertLegacyWindowsCoordinateCompatibility(screenshotBase64) {
1194
- if ('win32' !== process.platform || 'legacy' !== this.windowsCoordinateContext.mode) return;
1195
- assertLegacyWindowsCoordinateCompatibility({
1196
- geometry: this.displayGeometry,
1197
- screenshotBase64,
1198
- inputSize: this.inputDriver.getScreenSize()
1199
- });
1200
- }
1201
1107
  async moveGlobalPointer(point, context, smooth) {
1202
1108
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
1203
1109
  const target = {
1204
1110
  x: Math.round(point.x),
1205
1111
  y: Math.round(point.y)
1206
1112
  };
1207
- if (this.usesPhysicalWindowsCoordinates()) {
1113
+ if ('win32' === process.platform) {
1208
1114
  const actual = this.windowsPointerDriver.moveTo(target, {
1209
1115
  smoothSteps: smooth?.smoothSteps,
1210
1116
  smoothDelayMs: smooth?.smoothDelay
@@ -1256,7 +1162,7 @@ class ComputerDevice {
1256
1162
  }
1257
1163
  static async listDisplays() {
1258
1164
  try {
1259
- if ('win32' === process.platform) return listWindowsDisplays(discoverWindowsDisplays().geometries);
1165
+ if ('win32' === process.platform) return listWindowsDisplays();
1260
1166
  const displays = await screenshot_desktop.listDisplays();
1261
1167
  return displays.map((d)=>({
1262
1168
  id: String(d.id),
@@ -1294,14 +1200,7 @@ class ComputerDevice {
1294
1200
  }
1295
1201
  }
1296
1202
  device_libnut = await getLibnut();
1297
- const windowsDisplayDiscovery = 'win32' === process.platform ? discoverWindowsDisplays() : void 0;
1298
- const windowsDisplayGeometries = windowsDisplayDiscovery?.geometries;
1299
- if (windowsDisplayDiscovery?.coordinateMode === 'legacy') warnDevice('Windows display enumeration returned no data in the Per-Monitor V2 DPI context; using the legacy Windows coordinate path for this device connection.');
1300
- this.windowsCoordinateContext = windowsDisplayDiscovery?.coordinateMode === 'legacy' ? {
1301
- mode: 'legacy'
1302
- } : {
1303
- mode: 'physical'
1304
- };
1203
+ const windowsDisplayGeometries = 'win32' === process.platform ? readWindowsDisplayGeometries() : void 0;
1305
1204
  this.displayGeometry = resolveDisplayGeometry(this.displayId, windowsDisplayGeometries);
1306
1205
  const size = await this.size();
1307
1206
  const displays = windowsDisplayGeometries ? listWindowsDisplays(windowsDisplayGeometries) : await ComputerDevice.listDisplays();
@@ -1312,7 +1211,6 @@ Platform: ${process.platform}
1312
1211
  Display: ${this.displayId || 'Primary'}
1313
1212
  Screen Size: ${size.width}x${size.height}
1314
1213
  Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ') : 'Unknown'}${headlessInfo}
1315
- ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordinateContext.mode}` : ''}
1316
1214
  `;
1317
1215
  debugDevice('Computer device connected', this.description);
1318
1216
  await this.healthCheck(displays);
@@ -1336,7 +1234,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1336
1234
  }
1337
1235
  async healthCheck(displays) {
1338
1236
  console.log('[HealthCheck] Starting health check...');
1339
- console.log("[HealthCheck] @midscene/computer v1.13.1-beta-20260921034220.0");
1237
+ console.log("[HealthCheck] @midscene/computer v1.13.1-beta-20260921075813.0");
1340
1238
  console.log('[HealthCheck] Taking screenshot...');
1341
1239
  const screenshotTimeout = 15000;
1342
1240
  let timeoutId;
@@ -1348,12 +1246,10 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1348
1246
  timeoutPromise
1349
1247
  ]);
1350
1248
  console.log(`[HealthCheck] Screenshot succeeded (length=${base64.length})`);
1351
- this.assertLegacyWindowsCoordinateCompatibility(base64);
1352
1249
  console.log('[HealthCheck] Verifying mouse control...');
1353
- const usePhysicalWindowsCoordinates = this.usesPhysicalWindowsCoordinates();
1354
- const startPos = usePhysicalWindowsCoordinates ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1250
+ const startPos = 'win32' === process.platform ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1355
1251
  console.log(`[HealthCheck] Current mouse position: (${startPos.x}, ${startPos.y})`);
1356
- if (usePhysicalWindowsCoordinates) {
1252
+ if ('win32' === process.platform) {
1357
1253
  if (!this.displayGeometry) throw new Error('Windows display geometry is unavailable');
1358
1254
  const bounds = this.displayGeometry.bounds;
1359
1255
  const target = {
@@ -1419,7 +1315,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1419
1315
  debugDevice('Taking screenshot', {
1420
1316
  displayId: this.displayId
1421
1317
  });
1422
- if (this.usesPhysicalWindowsCoordinates()) return this.screenshotViaPowershell();
1318
+ if ('win32' === process.platform) return this.screenshotViaPowershell();
1423
1319
  const options = {
1424
1320
  format: 'png'
1425
1321
  };
@@ -1582,7 +1478,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1582
1478
  this.inputDriver.sendKey(key, modifiers);
1583
1479
  }
1584
1480
  resolveUntargetedScrollPoint(screenSize) {
1585
- if (this.usesPhysicalWindowsCoordinates()) {
1481
+ if ('win32' === process.platform) {
1586
1482
  const activeWindowRect = this.windowsPointerDriver.getActiveWindowRect();
1587
1483
  if (activeWindowRect) {
1588
1484
  const activeWindowCenter = {
@@ -1726,9 +1622,6 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1726
1622
  device_define_property(this, "options", void 0);
1727
1623
  device_define_property(this, "displayId", void 0);
1728
1624
  device_define_property(this, "displayGeometry", void 0);
1729
- device_define_property(this, "windowsCoordinateContext", {
1730
- mode: 'physical'
1731
- });
1732
1625
  device_define_property(this, "description", void 0);
1733
1626
  device_define_property(this, "destroyed", false);
1734
1627
  device_define_property(this, "xvfbInstance", void 0);
@@ -2830,7 +2723,7 @@ const tools = new ComputerMidsceneTools({
2830
2723
  });
2831
2724
  runToolsCLI(tools, 'midscene-computer', {
2832
2725
  stripPrefix: 'computer_',
2833
- version: "1.13.1-beta-20260921034220.0",
2726
+ version: "1.13.1-beta-20260921075813.0",
2834
2727
  extraCommands: createReportCliCommands()
2835
2728
  }).catch((e)=>{
2836
2729
  process.exit(reportCLIError(e));
package/dist/es/index.mjs CHANGED
@@ -461,8 +461,12 @@ if ($midscenePreviousDpiContext -eq [System.IntPtr]::Zero) {
461
461
  throw 'Unable to enter the Per-Monitor V2 DPI awareness context.'
462
462
  }
463
463
  `.trim();
464
- function runWindowsPowershellScript(script) {
465
- const encoded = Buffer.from(script, 'utf16le').toString('base64');
464
+ function runWindowsPhysicalPixelPowershell(script) {
465
+ const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
466
+ $ErrorActionPreference = 'Stop'
467
+ ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
468
+ ${script}`;
469
+ const encoded = Buffer.from(physicalPixelScript, 'utf16le').toString('base64');
466
470
  return execFileSync('powershell.exe', [
467
471
  '-NoProfile',
468
472
  '-NonInteractive',
@@ -475,130 +479,6 @@ function runWindowsPowershellScript(script) {
475
479
  windowsHide: true
476
480
  });
477
481
  }
478
- function runWindowsPowershellCommand(script) {
479
- return execFileSync('powershell.exe', [
480
- '-NoProfile',
481
- '-Command',
482
- script
483
- ], {
484
- encoding: 'utf8',
485
- timeout: POWERSHELL_TIMEOUT_MS,
486
- maxBuffer: POWERSHELL_MAX_BUFFER,
487
- windowsHide: true
488
- });
489
- }
490
- function runWindowsPowershell(script) {
491
- return runWindowsPowershellCommand(`$ProgressPreference = 'SilentlyContinue'
492
- $ErrorActionPreference = 'Stop'
493
- ${script}`);
494
- }
495
- function runWindowsPhysicalPixelPowershell(script) {
496
- const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
497
- $ErrorActionPreference = 'Stop'
498
- ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
499
- ${script}`;
500
- return runWindowsPowershellScript(physicalPixelScript);
501
- }
502
- class WindowsDisplayEnumerationEmptyError extends Error {
503
- }
504
- function isFiniteNumber(value) {
505
- return 'number' == typeof value && Number.isFinite(value);
506
- }
507
- function isWindowsDisplayGeometry(value) {
508
- if (!value || 'object' != typeof value) return false;
509
- const candidate = value;
510
- const bounds = candidate.bounds;
511
- return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && !!bounds && isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
512
- }
513
- function readWindowsDisplayGeometriesWith(runPowershell, context) {
514
- const serializeScreens = 'legacy' === context ? 'ConvertTo-Json -InputObject $screens -Compress' : '[Console]::Out.Write((ConvertTo-Json -InputObject $screens -Compress))';
515
- const script = `
516
- Add-Type -AssemblyName System.Windows.Forms
517
- $screens = @([System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
518
- $bounds = $_.Bounds
519
- [PSCustomObject]@{
520
- id = $_.DeviceName
521
- name = $_.DeviceName
522
- primary = $_.Primary
523
- bounds = [PSCustomObject]@{
524
- x = $bounds.X
525
- y = $bounds.Y
526
- width = $bounds.Width
527
- height = $bounds.Height
528
- }
529
- }
530
- })
531
- ${serializeScreens}
532
- `.trim();
533
- const output = runPowershell(script).trim();
534
- if (!output) throw new WindowsDisplayEnumerationEmptyError(`Windows ${context} display enumeration returned no data`);
535
- const parsed = JSON.parse(output);
536
- if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
537
- const displays = parsed.filter(isWindowsDisplayGeometry);
538
- if (displays.length !== parsed.length) throw new Error('Windows display enumeration returned invalid geometry');
539
- if (0 === displays.length) throw new WindowsDisplayEnumerationEmptyError(`Windows ${context} display enumeration returned no displays`);
540
- return displays;
541
- }
542
- function readWindowsDisplayGeometries() {
543
- return readWindowsDisplayGeometriesWith(runWindowsPhysicalPixelPowershell, 'physical');
544
- }
545
- function discoverWindowsDisplays(runners = {
546
- physical: runWindowsPhysicalPixelPowershell,
547
- legacy: runWindowsPowershell
548
- }) {
549
- try {
550
- return {
551
- geometries: readWindowsDisplayGeometriesWith(runners.physical, 'physical'),
552
- coordinateMode: 'physical'
553
- };
554
- } catch (error) {
555
- if (!(error instanceof WindowsDisplayEnumerationEmptyError)) throw error;
556
- const geometries = readWindowsDisplayGeometriesWith(runners.legacy, 'legacy');
557
- return {
558
- geometries,
559
- coordinateMode: 'legacy'
560
- };
561
- }
562
- }
563
- function readPngDimensions(dataUri) {
564
- const prefix = 'data:image/png;base64,';
565
- if (!dataUri.startsWith(prefix)) throw new Error('Screenshot is not a PNG data URI');
566
- const buffer = Buffer.from(dataUri.slice(prefix.length), 'base64');
567
- const pngSignature = Buffer.from([
568
- 137,
569
- 80,
570
- 78,
571
- 71,
572
- 13,
573
- 10,
574
- 26,
575
- 10
576
- ]);
577
- if (buffer.length < 24 || !buffer.subarray(0, pngSignature.length).equals(pngSignature)) throw new Error('Screenshot returned invalid PNG data');
578
- const width = buffer.readUInt32BE(16);
579
- const height = buffer.readUInt32BE(20);
580
- if (width <= 0 || height <= 0) throw new Error('Screenshot returned invalid PNG dimensions');
581
- return {
582
- width,
583
- height
584
- };
585
- }
586
- function assertLegacyWindowsCoordinateCompatibility({ geometry, screenshotBase64, inputSize }) {
587
- if (!geometry?.primary) throw new Error('Windows legacy coordinate compatibility mode only supports the primary display');
588
- if (0 !== geometry.bounds.x || 0 !== geometry.bounds.y) throw new Error(`Windows legacy coordinate compatibility mode requires a primary display origin of (0, 0), got (${geometry.bounds.x}, ${geometry.bounds.y})`);
589
- const screenshotSize = readPngDimensions(screenshotBase64);
590
- const displaySize = {
591
- width: Math.round(geometry.bounds.width),
592
- height: Math.round(geometry.bounds.height)
593
- };
594
- const sizesMatch = screenshotSize.width === displaySize.width && screenshotSize.height === displaySize.height && inputSize.width === displaySize.width && inputSize.height === displaySize.height;
595
- if (!sizesMatch) throw new Error(`Windows legacy coordinate compatibility check failed: display=${displaySize.width}x${displaySize.height}, screenshot=${screenshotSize.width}x${screenshotSize.height}, input=${inputSize.width}x${inputSize.height}. Refusing to continue because clicks may use incorrect coordinates.`);
596
- }
597
- function resolveWindowsDisplayGeometryFromList(displayId, displays) {
598
- if (!displays.length) return;
599
- if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
600
- return displays.find((display)=>display.id === displayId);
601
- }
602
482
  function windows_pointer_define_property(obj, key, value) {
603
483
  if (key in obj) Object.defineProperty(obj, key, {
604
484
  value: value,
@@ -916,6 +796,28 @@ const EDGE_SCROLL_SPEC = {
916
796
  function escapePowershellSingleQuoted(value) {
917
797
  return value.replace(/'/g, "''");
918
798
  }
799
+ function readWindowsDisplayGeometries() {
800
+ const script = `
801
+ Add-Type -AssemblyName System.Windows.Forms
802
+ $s = [System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
803
+ $b = $_.Bounds
804
+ [PSCustomObject]@{
805
+ id = $_.DeviceName
806
+ name = $_.DeviceName
807
+ primary = $_.Primary
808
+ bounds = [PSCustomObject]@{ x = $b.X; y = $b.Y; width = $b.Width; height = $b.Height }
809
+ }
810
+ }
811
+ ConvertTo-Json @($s) -Compress
812
+ `.trim();
813
+ const output = runWindowsPhysicalPixelPowershell(script).trim();
814
+ if (!output) throw new Error('Windows display enumeration returned no data');
815
+ const parsed = JSON.parse(output);
816
+ if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
817
+ const displays = parsed.filter(isWindowsDisplayGeometry);
818
+ if (displays.length !== parsed.length || 0 === displays.length) throw new Error('Windows display enumeration returned invalid geometry');
819
+ return displays;
820
+ }
919
821
  function listWindowsDisplays(geometries = readWindowsDisplayGeometries()) {
920
822
  return geometries.map((display)=>({
921
823
  id: display.id,
@@ -1019,13 +921,23 @@ function getDisplayInfoBinary() {
1019
921
  displayInfoBinaryPath = binPath;
1020
922
  return binPath;
1021
923
  }
1022
- function device_isFiniteNumber(value) {
924
+ function isFiniteNumber(value) {
1023
925
  return 'number' == typeof value && Number.isFinite(value);
1024
926
  }
927
+ function isDisplayBounds(value) {
928
+ if (!value || 'object' != typeof value) return false;
929
+ const bounds = value;
930
+ return isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
931
+ }
932
+ function isWindowsDisplayGeometry(value) {
933
+ if (!value || 'object' != typeof value) return false;
934
+ const candidate = value;
935
+ return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && isDisplayBounds(candidate.bounds);
936
+ }
1025
937
  function isDarwinDisplayGeometry(value) {
1026
938
  if (!value || 'object' != typeof value) return false;
1027
939
  const candidate = value;
1028
- return Number.isInteger(candidate.screenIndex) && Number.isInteger(candidate.cgDisplayId) && 'boolean' == typeof candidate.primary && !!candidate.bounds && device_isFiniteNumber(candidate.bounds.x) && device_isFiniteNumber(candidate.bounds.y) && device_isFiniteNumber(candidate.bounds.width) && device_isFiniteNumber(candidate.bounds.height);
940
+ return Number.isInteger(candidate.screenIndex) && Number.isInteger(candidate.cgDisplayId) && 'boolean' == typeof candidate.primary && !!candidate.bounds && isFiniteNumber(candidate.bounds.x) && isFiniteNumber(candidate.bounds.y) && isFiniteNumber(candidate.bounds.width) && isFiniteNumber(candidate.bounds.height);
1029
941
  }
1030
942
  function readDarwinDisplayGeometries() {
1031
943
  const bin = getDisplayInfoBinary();
@@ -1095,6 +1007,11 @@ function resolveDarwinDisplayGeometryFromList(displayId, displays) {
1095
1007
  if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays.find((display)=>0 === display.screenIndex) || displays[0];
1096
1008
  return displays.find((display)=>display.screenIndex === screenIndex) || displays.find((display)=>display.cgDisplayId === screenIndex);
1097
1009
  }
1010
+ function resolveWindowsDisplayGeometryFromList(displayId, displays) {
1011
+ if (!displays.length) return;
1012
+ if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
1013
+ return displays.find((display)=>display.id === displayId);
1014
+ }
1098
1015
  function resolveDisplayGeometry(displayId, windowsDisplays) {
1099
1016
  if ('darwin' === process.platform) return resolveDarwinDisplayGeometryFromList(displayId, readDarwinDisplayGeometries());
1100
1017
  if ('win32' === process.platform) {
@@ -1187,24 +1104,13 @@ function normalizePrimaryKey(key) {
1187
1104
  return KEY_NAME_MAP[lowerKey] || lowerKey;
1188
1105
  }
1189
1106
  class ComputerDevice {
1190
- usesPhysicalWindowsCoordinates() {
1191
- return 'win32' === process.platform && 'physical' === this.windowsCoordinateContext.mode;
1192
- }
1193
- assertLegacyWindowsCoordinateCompatibility(screenshotBase64) {
1194
- if ('win32' !== process.platform || 'legacy' !== this.windowsCoordinateContext.mode) return;
1195
- assertLegacyWindowsCoordinateCompatibility({
1196
- geometry: this.displayGeometry,
1197
- screenshotBase64,
1198
- inputSize: this.inputDriver.getScreenSize()
1199
- });
1200
- }
1201
1107
  async moveGlobalPointer(point, context, smooth) {
1202
1108
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
1203
1109
  const target = {
1204
1110
  x: Math.round(point.x),
1205
1111
  y: Math.round(point.y)
1206
1112
  };
1207
- if (this.usesPhysicalWindowsCoordinates()) {
1113
+ if ('win32' === process.platform) {
1208
1114
  const actual = this.windowsPointerDriver.moveTo(target, {
1209
1115
  smoothSteps: smooth?.smoothSteps,
1210
1116
  smoothDelayMs: smooth?.smoothDelay
@@ -1256,7 +1162,7 @@ class ComputerDevice {
1256
1162
  }
1257
1163
  static async listDisplays() {
1258
1164
  try {
1259
- if ('win32' === process.platform) return listWindowsDisplays(discoverWindowsDisplays().geometries);
1165
+ if ('win32' === process.platform) return listWindowsDisplays();
1260
1166
  const displays = await screenshot_desktop.listDisplays();
1261
1167
  return displays.map((d)=>({
1262
1168
  id: String(d.id),
@@ -1294,14 +1200,7 @@ class ComputerDevice {
1294
1200
  }
1295
1201
  }
1296
1202
  device_libnut = await getLibnut();
1297
- const windowsDisplayDiscovery = 'win32' === process.platform ? discoverWindowsDisplays() : void 0;
1298
- const windowsDisplayGeometries = windowsDisplayDiscovery?.geometries;
1299
- if (windowsDisplayDiscovery?.coordinateMode === 'legacy') warnDevice('Windows display enumeration returned no data in the Per-Monitor V2 DPI context; using the legacy Windows coordinate path for this device connection.');
1300
- this.windowsCoordinateContext = windowsDisplayDiscovery?.coordinateMode === 'legacy' ? {
1301
- mode: 'legacy'
1302
- } : {
1303
- mode: 'physical'
1304
- };
1203
+ const windowsDisplayGeometries = 'win32' === process.platform ? readWindowsDisplayGeometries() : void 0;
1305
1204
  this.displayGeometry = resolveDisplayGeometry(this.displayId, windowsDisplayGeometries);
1306
1205
  const size = await this.size();
1307
1206
  const displays = windowsDisplayGeometries ? listWindowsDisplays(windowsDisplayGeometries) : await ComputerDevice.listDisplays();
@@ -1312,7 +1211,6 @@ Platform: ${process.platform}
1312
1211
  Display: ${this.displayId || 'Primary'}
1313
1212
  Screen Size: ${size.width}x${size.height}
1314
1213
  Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ') : 'Unknown'}${headlessInfo}
1315
- ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordinateContext.mode}` : ''}
1316
1214
  `;
1317
1215
  debugDevice('Computer device connected', this.description);
1318
1216
  await this.healthCheck(displays);
@@ -1336,7 +1234,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1336
1234
  }
1337
1235
  async healthCheck(displays) {
1338
1236
  console.log('[HealthCheck] Starting health check...');
1339
- console.log("[HealthCheck] @midscene/computer v1.13.1-beta-20260921034220.0");
1237
+ console.log("[HealthCheck] @midscene/computer v1.13.1-beta-20260921075813.0");
1340
1238
  console.log('[HealthCheck] Taking screenshot...');
1341
1239
  const screenshotTimeout = 15000;
1342
1240
  let timeoutId;
@@ -1348,12 +1246,10 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1348
1246
  timeoutPromise
1349
1247
  ]);
1350
1248
  console.log(`[HealthCheck] Screenshot succeeded (length=${base64.length})`);
1351
- this.assertLegacyWindowsCoordinateCompatibility(base64);
1352
1249
  console.log('[HealthCheck] Verifying mouse control...');
1353
- const usePhysicalWindowsCoordinates = this.usesPhysicalWindowsCoordinates();
1354
- const startPos = usePhysicalWindowsCoordinates ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1250
+ const startPos = 'win32' === process.platform ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1355
1251
  console.log(`[HealthCheck] Current mouse position: (${startPos.x}, ${startPos.y})`);
1356
- if (usePhysicalWindowsCoordinates) {
1252
+ if ('win32' === process.platform) {
1357
1253
  if (!this.displayGeometry) throw new Error('Windows display geometry is unavailable');
1358
1254
  const bounds = this.displayGeometry.bounds;
1359
1255
  const target = {
@@ -1419,7 +1315,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1419
1315
  debugDevice('Taking screenshot', {
1420
1316
  displayId: this.displayId
1421
1317
  });
1422
- if (this.usesPhysicalWindowsCoordinates()) return this.screenshotViaPowershell();
1318
+ if ('win32' === process.platform) return this.screenshotViaPowershell();
1423
1319
  const options = {
1424
1320
  format: 'png'
1425
1321
  };
@@ -1582,7 +1478,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1582
1478
  this.inputDriver.sendKey(key, modifiers);
1583
1479
  }
1584
1480
  resolveUntargetedScrollPoint(screenSize) {
1585
- if (this.usesPhysicalWindowsCoordinates()) {
1481
+ if ('win32' === process.platform) {
1586
1482
  const activeWindowRect = this.windowsPointerDriver.getActiveWindowRect();
1587
1483
  if (activeWindowRect) {
1588
1484
  const activeWindowCenter = {
@@ -1726,9 +1622,6 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1726
1622
  device_define_property(this, "options", void 0);
1727
1623
  device_define_property(this, "displayId", void 0);
1728
1624
  device_define_property(this, "displayGeometry", void 0);
1729
- device_define_property(this, "windowsCoordinateContext", {
1730
- mode: 'physical'
1731
- });
1732
1625
  device_define_property(this, "description", void 0);
1733
1626
  device_define_property(this, "destroyed", false);
1734
1627
  device_define_property(this, "xvfbInstance", void 0);
@@ -2869,7 +2762,7 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
2869
2762
  }
2870
2763
  }
2871
2764
  function version() {
2872
- const currentVersion = "1.13.1-beta-20260921034220.0";
2765
+ const currentVersion = "1.13.1-beta-20260921075813.0";
2873
2766
  console.log(`@midscene/computer v${currentVersion}`);
2874
2767
  return currentVersion;
2875
2768
  }