@midscene/computer 1.12.10-beta-20260920031616.0 → 1.13.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/lib/cli.js CHANGED
@@ -450,20 +450,6 @@ $midsceneSetDpiMethod.SetImplementationFlags(
450
450
  $midsceneSetDpiMethod.GetMethodImplementationFlags() -bor
451
451
  [System.Reflection.MethodImplAttributes]::PreserveSig
452
452
  )
453
- $midsceneGetDpiForSystemMethod = $midsceneType.DefinePInvokeMethod(
454
- 'GetDpiForSystem',
455
- 'user32.dll',
456
- $midsceneMethodAttributes,
457
- [System.Reflection.CallingConventions]::Standard,
458
- [uint32],
459
- [System.Type[]]@(),
460
- [System.Runtime.InteropServices.CallingConvention]::Winapi,
461
- [System.Runtime.InteropServices.CharSet]::None
462
- )
463
- $midsceneGetDpiForSystemMethod.SetImplementationFlags(
464
- $midsceneGetDpiForSystemMethod.GetMethodImplementationFlags() -bor
465
- [System.Reflection.MethodImplAttributes]::PreserveSig
466
- )
467
453
  $midsceneGetForegroundWindowMethod = $midsceneType.DefinePInvokeMethod(
468
454
  'GetForegroundWindow',
469
455
  'user32.dll',
@@ -500,8 +486,12 @@ if ($midscenePreviousDpiContext -eq [System.IntPtr]::Zero) {
500
486
  throw 'Unable to enter the Per-Monitor V2 DPI awareness context.'
501
487
  }
502
488
  `.trim();
503
- function runWindowsPowershellScript(script) {
504
- const encoded = Buffer.from(script, 'utf16le').toString('base64');
489
+ function runWindowsPhysicalPixelPowershell(script) {
490
+ const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
491
+ $ErrorActionPreference = 'Stop'
492
+ ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
493
+ ${script}`;
494
+ const encoded = Buffer.from(physicalPixelScript, 'utf16le').toString('base64');
505
495
  return (0, external_node_child_process_namespaceObject.execFileSync)('powershell.exe', [
506
496
  '-NoProfile',
507
497
  '-NonInteractive',
@@ -514,121 +504,6 @@ function runWindowsPowershellScript(script) {
514
504
  windowsHide: true
515
505
  });
516
506
  }
517
- function runWindowsPowershell(script) {
518
- return runWindowsPowershellScript(`$ProgressPreference = 'SilentlyContinue'
519
- $ErrorActionPreference = 'Stop'
520
- ${script}`);
521
- }
522
- function runWindowsPhysicalPixelPowershell(script) {
523
- const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
524
- $ErrorActionPreference = 'Stop'
525
- ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
526
- ${script}`;
527
- return runWindowsPowershellScript(physicalPixelScript);
528
- }
529
- class WindowsDisplayEnumerationEmptyError extends Error {
530
- }
531
- function isFiniteNumber(value) {
532
- return 'number' == typeof value && Number.isFinite(value);
533
- }
534
- function isWindowsDisplayGeometry(value) {
535
- if (!value || 'object' != typeof value) return false;
536
- const candidate = value;
537
- const bounds = candidate.bounds;
538
- 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;
539
- }
540
- function readWindowsDisplayGeometriesWith(runPowershell) {
541
- const script = `
542
- Add-Type -AssemblyName System.Windows.Forms
543
- $screens = @([System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
544
- $bounds = $_.Bounds
545
- [PSCustomObject]@{
546
- id = $_.DeviceName
547
- name = $_.DeviceName
548
- primary = $_.Primary
549
- bounds = [PSCustomObject]@{
550
- x = $bounds.X
551
- y = $bounds.Y
552
- width = $bounds.Width
553
- height = $bounds.Height
554
- }
555
- }
556
- })
557
- [Console]::Out.Write((ConvertTo-Json -InputObject $screens -Compress))
558
- `.trim();
559
- const output = runPowershell(script).trim();
560
- if (!output) throw new WindowsDisplayEnumerationEmptyError('Windows display enumeration returned no data');
561
- const parsed = JSON.parse(output);
562
- if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
563
- const displays = parsed.filter(isWindowsDisplayGeometry);
564
- if (displays.length !== parsed.length) throw new Error('Windows display enumeration returned invalid geometry');
565
- if (0 === displays.length) throw new WindowsDisplayEnumerationEmptyError('Windows display enumeration returned no displays');
566
- return displays;
567
- }
568
- function readWindowsDisplayGeometries() {
569
- return readWindowsDisplayGeometriesWith(runWindowsPhysicalPixelPowershell);
570
- }
571
- function discoverWindowsDisplays() {
572
- try {
573
- return {
574
- geometries: readWindowsDisplayGeometries(),
575
- coordinateMode: 'physical'
576
- };
577
- } catch (error) {
578
- if (!(error instanceof WindowsDisplayEnumerationEmptyError)) throw error;
579
- const geometries = readWindowsDisplayGeometriesWith(runWindowsPowershell);
580
- return {
581
- geometries,
582
- coordinateMode: 'legacy'
583
- };
584
- }
585
- }
586
- function readPhysicalWindowsSystemDpi() {
587
- const output = runWindowsPhysicalPixelPowershell('[Console]::Out.Write($midsceneNativeMethods::GetDpiForSystem())').trim();
588
- const dpi = Number(output);
589
- if (!Number.isFinite(dpi) || dpi <= 0) throw new Error(`Windows returned an invalid system DPI value: ${output}`);
590
- return dpi;
591
- }
592
- function readPngDimensions(dataUri) {
593
- const prefix = 'data:image/png;base64,';
594
- if (!dataUri.startsWith(prefix)) throw new Error('Screenshot is not a PNG data URI');
595
- const buffer = Buffer.from(dataUri.slice(prefix.length), 'base64');
596
- const pngSignature = Buffer.from([
597
- 137,
598
- 80,
599
- 78,
600
- 71,
601
- 13,
602
- 10,
603
- 26,
604
- 10
605
- ]);
606
- if (buffer.length < 24 || !buffer.subarray(0, pngSignature.length).equals(pngSignature)) throw new Error('Screenshot returned invalid PNG data');
607
- const width = buffer.readUInt32BE(16);
608
- const height = buffer.readUInt32BE(20);
609
- if (width <= 0 || height <= 0) throw new Error('Screenshot returned invalid PNG dimensions');
610
- return {
611
- width,
612
- height
613
- };
614
- }
615
- function assertLegacyWindowsCoordinateCompatibility({ geometry, systemDpi, screenshotBase64, inputSize }) {
616
- if (!geometry?.primary) throw new Error('Windows legacy coordinate compatibility mode only supports the primary display');
617
- 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})`);
618
- if (96 !== systemDpi) throw new Error(`Windows legacy coordinate compatibility mode requires 100% display scaling (96 DPI), got ${systemDpi} DPI`);
619
- const screenshotSize = readPngDimensions(screenshotBase64);
620
- const displaySize = {
621
- width: Math.round(geometry.bounds.width),
622
- height: Math.round(geometry.bounds.height)
623
- };
624
- const sizesMatch = screenshotSize.width === displaySize.width && screenshotSize.height === displaySize.height && inputSize.width === displaySize.width && inputSize.height === displaySize.height;
625
- 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.`);
626
- }
627
- function resolveWindowsDisplayGeometryFromList(displayId, displays) {
628
- if (!displays.length) return;
629
- if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
630
- return displays.find((display)=>display.id === displayId);
631
- }
632
507
  function windows_pointer_define_property(obj, key, value) {
633
508
  if (key in obj) Object.defineProperty(obj, key, {
634
509
  value: value,
@@ -947,6 +822,28 @@ const EDGE_SCROLL_SPEC = {
947
822
  function escapePowershellSingleQuoted(value) {
948
823
  return value.replace(/'/g, "''");
949
824
  }
825
+ function readWindowsDisplayGeometries() {
826
+ const script = `
827
+ Add-Type -AssemblyName System.Windows.Forms
828
+ $s = [System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
829
+ $b = $_.Bounds
830
+ [PSCustomObject]@{
831
+ id = $_.DeviceName
832
+ name = $_.DeviceName
833
+ primary = $_.Primary
834
+ bounds = [PSCustomObject]@{ x = $b.X; y = $b.Y; width = $b.Width; height = $b.Height }
835
+ }
836
+ }
837
+ ConvertTo-Json @($s) -Compress
838
+ `.trim();
839
+ const output = runWindowsPhysicalPixelPowershell(script).trim();
840
+ if (!output) throw new Error('Windows display enumeration returned no data');
841
+ const parsed = JSON.parse(output);
842
+ if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
843
+ const displays = parsed.filter(isWindowsDisplayGeometry);
844
+ if (displays.length !== parsed.length || 0 === displays.length) throw new Error('Windows display enumeration returned invalid geometry');
845
+ return displays;
846
+ }
950
847
  function listWindowsDisplays(geometries = readWindowsDisplayGeometries()) {
951
848
  return geometries.map((display)=>({
952
849
  id: display.id,
@@ -1050,13 +947,23 @@ function getDisplayInfoBinary() {
1050
947
  displayInfoBinaryPath = binPath;
1051
948
  return binPath;
1052
949
  }
1053
- function device_isFiniteNumber(value) {
950
+ function isFiniteNumber(value) {
1054
951
  return 'number' == typeof value && Number.isFinite(value);
1055
952
  }
953
+ function isDisplayBounds(value) {
954
+ if (!value || 'object' != typeof value) return false;
955
+ const bounds = value;
956
+ return isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
957
+ }
958
+ function isWindowsDisplayGeometry(value) {
959
+ if (!value || 'object' != typeof value) return false;
960
+ const candidate = value;
961
+ return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && isDisplayBounds(candidate.bounds);
962
+ }
1056
963
  function isDarwinDisplayGeometry(value) {
1057
964
  if (!value || 'object' != typeof value) return false;
1058
965
  const candidate = value;
1059
- 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);
966
+ 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);
1060
967
  }
1061
968
  function readDarwinDisplayGeometries() {
1062
969
  const bin = getDisplayInfoBinary();
@@ -1126,6 +1033,11 @@ function resolveDarwinDisplayGeometryFromList(displayId, displays) {
1126
1033
  if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays.find((display)=>0 === display.screenIndex) || displays[0];
1127
1034
  return displays.find((display)=>display.screenIndex === screenIndex) || displays.find((display)=>display.cgDisplayId === screenIndex);
1128
1035
  }
1036
+ function resolveWindowsDisplayGeometryFromList(displayId, displays) {
1037
+ if (!displays.length) return;
1038
+ if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
1039
+ return displays.find((display)=>display.id === displayId);
1040
+ }
1129
1041
  function resolveDisplayGeometry(displayId, windowsDisplays) {
1130
1042
  if ('darwin' === process.platform) return resolveDarwinDisplayGeometryFromList(displayId, readDarwinDisplayGeometries());
1131
1043
  if ('win32' === process.platform) {
@@ -1218,25 +1130,13 @@ function normalizePrimaryKey(key) {
1218
1130
  return KEY_NAME_MAP[lowerKey] || lowerKey;
1219
1131
  }
1220
1132
  class ComputerDevice {
1221
- usesPhysicalWindowsCoordinates() {
1222
- return 'win32' === process.platform && 'physical' === this.windowsCoordinateContext.mode;
1223
- }
1224
- assertLegacyWindowsCoordinateCompatibility(screenshotBase64) {
1225
- if ('win32' !== process.platform || 'legacy' !== this.windowsCoordinateContext.mode) return;
1226
- assertLegacyWindowsCoordinateCompatibility({
1227
- geometry: this.displayGeometry,
1228
- systemDpi: this.windowsCoordinateContext.systemDpi,
1229
- screenshotBase64,
1230
- inputSize: this.inputDriver.getScreenSize()
1231
- });
1232
- }
1233
1133
  async moveGlobalPointer(point, context, smooth) {
1234
1134
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
1235
1135
  const target = {
1236
1136
  x: Math.round(point.x),
1237
1137
  y: Math.round(point.y)
1238
1138
  };
1239
- if (this.usesPhysicalWindowsCoordinates()) {
1139
+ if ('win32' === process.platform) {
1240
1140
  const actual = this.windowsPointerDriver.moveTo(target, {
1241
1141
  smoothSteps: smooth?.smoothSteps,
1242
1142
  smoothDelayMs: smooth?.smoothDelay
@@ -1288,7 +1188,7 @@ class ComputerDevice {
1288
1188
  }
1289
1189
  static async listDisplays() {
1290
1190
  try {
1291
- if ('win32' === process.platform) return listWindowsDisplays(discoverWindowsDisplays().geometries);
1191
+ if ('win32' === process.platform) return listWindowsDisplays();
1292
1192
  const displays = await external_screenshot_desktop_default().listDisplays();
1293
1193
  return displays.map((d)=>({
1294
1194
  id: String(d.id),
@@ -1326,15 +1226,7 @@ class ComputerDevice {
1326
1226
  }
1327
1227
  }
1328
1228
  device_libnut = await getLibnut();
1329
- const windowsDisplayDiscovery = 'win32' === process.platform ? discoverWindowsDisplays() : void 0;
1330
- const windowsDisplayGeometries = windowsDisplayDiscovery?.geometries;
1331
- 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.');
1332
- this.windowsCoordinateContext = windowsDisplayDiscovery?.coordinateMode === 'legacy' ? {
1333
- mode: 'legacy',
1334
- systemDpi: readPhysicalWindowsSystemDpi()
1335
- } : {
1336
- mode: 'physical'
1337
- };
1229
+ const windowsDisplayGeometries = 'win32' === process.platform ? readWindowsDisplayGeometries() : void 0;
1338
1230
  this.displayGeometry = resolveDisplayGeometry(this.displayId, windowsDisplayGeometries);
1339
1231
  const size = await this.size();
1340
1232
  const displays = windowsDisplayGeometries ? listWindowsDisplays(windowsDisplayGeometries) : await ComputerDevice.listDisplays();
@@ -1345,7 +1237,6 @@ Platform: ${process.platform}
1345
1237
  Display: ${this.displayId || 'Primary'}
1346
1238
  Screen Size: ${size.width}x${size.height}
1347
1239
  Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ') : 'Unknown'}${headlessInfo}
1348
- ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordinateContext.mode}` : ''}
1349
1240
  `;
1350
1241
  debugDevice('Computer device connected', this.description);
1351
1242
  await this.healthCheck(displays);
@@ -1369,7 +1260,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1369
1260
  }
1370
1261
  async healthCheck(displays) {
1371
1262
  console.log('[HealthCheck] Starting health check...');
1372
- console.log("[HealthCheck] @midscene/computer v1.12.10-beta-20260920031616.0");
1263
+ console.log("[HealthCheck] @midscene/computer v1.13.0");
1373
1264
  console.log('[HealthCheck] Taking screenshot...');
1374
1265
  const screenshotTimeout = 15000;
1375
1266
  let timeoutId;
@@ -1381,12 +1272,10 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1381
1272
  timeoutPromise
1382
1273
  ]);
1383
1274
  console.log(`[HealthCheck] Screenshot succeeded (length=${base64.length})`);
1384
- this.assertLegacyWindowsCoordinateCompatibility(base64);
1385
1275
  console.log('[HealthCheck] Verifying mouse control...');
1386
- const usePhysicalWindowsCoordinates = this.usesPhysicalWindowsCoordinates();
1387
- const startPos = usePhysicalWindowsCoordinates ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1276
+ const startPos = 'win32' === process.platform ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1388
1277
  console.log(`[HealthCheck] Current mouse position: (${startPos.x}, ${startPos.y})`);
1389
- if (usePhysicalWindowsCoordinates) {
1278
+ if ('win32' === process.platform) {
1390
1279
  if (!this.displayGeometry) throw new Error('Windows display geometry is unavailable');
1391
1280
  const bounds = this.displayGeometry.bounds;
1392
1281
  const target = {
@@ -1452,7 +1341,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1452
1341
  debugDevice('Taking screenshot', {
1453
1342
  displayId: this.displayId
1454
1343
  });
1455
- if (this.usesPhysicalWindowsCoordinates()) return this.screenshotViaPowershell();
1344
+ if ('win32' === process.platform) return this.screenshotViaPowershell();
1456
1345
  const options = {
1457
1346
  format: 'png'
1458
1347
  };
@@ -1615,7 +1504,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1615
1504
  this.inputDriver.sendKey(key, modifiers);
1616
1505
  }
1617
1506
  resolveUntargetedScrollPoint(screenSize) {
1618
- if (this.usesPhysicalWindowsCoordinates()) {
1507
+ if ('win32' === process.platform) {
1619
1508
  const activeWindowRect = this.windowsPointerDriver.getActiveWindowRect();
1620
1509
  if (activeWindowRect) {
1621
1510
  const activeWindowCenter = {
@@ -1759,9 +1648,6 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1759
1648
  device_define_property(this, "options", void 0);
1760
1649
  device_define_property(this, "displayId", void 0);
1761
1650
  device_define_property(this, "displayGeometry", void 0);
1762
- device_define_property(this, "windowsCoordinateContext", {
1763
- mode: 'physical'
1764
- });
1765
1651
  device_define_property(this, "description", void 0);
1766
1652
  device_define_property(this, "destroyed", false);
1767
1653
  device_define_property(this, "xvfbInstance", void 0);
@@ -2864,7 +2750,7 @@ const tools = new ComputerMidsceneTools({
2864
2750
  });
2865
2751
  (0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-computer', {
2866
2752
  stripPrefix: 'computer_',
2867
- version: "1.12.10-beta-20260920031616.0",
2753
+ version: "1.13.0",
2868
2754
  extraCommands: (0, core_namespaceObject.createReportCliCommands)()
2869
2755
  }).catch((e)=>{
2870
2756
  process.exit((0, cli_namespaceObject.reportCLIError)(e));