@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/es/index.mjs CHANGED
@@ -425,20 +425,6 @@ $midsceneSetDpiMethod.SetImplementationFlags(
425
425
  $midsceneSetDpiMethod.GetMethodImplementationFlags() -bor
426
426
  [System.Reflection.MethodImplAttributes]::PreserveSig
427
427
  )
428
- $midsceneGetDpiForSystemMethod = $midsceneType.DefinePInvokeMethod(
429
- 'GetDpiForSystem',
430
- 'user32.dll',
431
- $midsceneMethodAttributes,
432
- [System.Reflection.CallingConventions]::Standard,
433
- [uint32],
434
- [System.Type[]]@(),
435
- [System.Runtime.InteropServices.CallingConvention]::Winapi,
436
- [System.Runtime.InteropServices.CharSet]::None
437
- )
438
- $midsceneGetDpiForSystemMethod.SetImplementationFlags(
439
- $midsceneGetDpiForSystemMethod.GetMethodImplementationFlags() -bor
440
- [System.Reflection.MethodImplAttributes]::PreserveSig
441
- )
442
428
  $midsceneGetForegroundWindowMethod = $midsceneType.DefinePInvokeMethod(
443
429
  'GetForegroundWindow',
444
430
  'user32.dll',
@@ -475,8 +461,12 @@ if ($midscenePreviousDpiContext -eq [System.IntPtr]::Zero) {
475
461
  throw 'Unable to enter the Per-Monitor V2 DPI awareness context.'
476
462
  }
477
463
  `.trim();
478
- function runWindowsPowershellScript(script) {
479
- 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');
480
470
  return execFileSync('powershell.exe', [
481
471
  '-NoProfile',
482
472
  '-NonInteractive',
@@ -489,121 +479,6 @@ function runWindowsPowershellScript(script) {
489
479
  windowsHide: true
490
480
  });
491
481
  }
492
- function runWindowsPowershell(script) {
493
- return runWindowsPowershellScript(`$ProgressPreference = 'SilentlyContinue'
494
- $ErrorActionPreference = 'Stop'
495
- ${script}`);
496
- }
497
- function runWindowsPhysicalPixelPowershell(script) {
498
- const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
499
- $ErrorActionPreference = 'Stop'
500
- ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
501
- ${script}`;
502
- return runWindowsPowershellScript(physicalPixelScript);
503
- }
504
- class WindowsDisplayEnumerationEmptyError extends Error {
505
- }
506
- function isFiniteNumber(value) {
507
- return 'number' == typeof value && Number.isFinite(value);
508
- }
509
- function isWindowsDisplayGeometry(value) {
510
- if (!value || 'object' != typeof value) return false;
511
- const candidate = value;
512
- const bounds = candidate.bounds;
513
- 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;
514
- }
515
- function readWindowsDisplayGeometriesWith(runPowershell) {
516
- const script = `
517
- Add-Type -AssemblyName System.Windows.Forms
518
- $screens = @([System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
519
- $bounds = $_.Bounds
520
- [PSCustomObject]@{
521
- id = $_.DeviceName
522
- name = $_.DeviceName
523
- primary = $_.Primary
524
- bounds = [PSCustomObject]@{
525
- x = $bounds.X
526
- y = $bounds.Y
527
- width = $bounds.Width
528
- height = $bounds.Height
529
- }
530
- }
531
- })
532
- [Console]::Out.Write((ConvertTo-Json -InputObject $screens -Compress))
533
- `.trim();
534
- const output = runPowershell(script).trim();
535
- if (!output) throw new WindowsDisplayEnumerationEmptyError('Windows display enumeration returned no data');
536
- const parsed = JSON.parse(output);
537
- if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
538
- const displays = parsed.filter(isWindowsDisplayGeometry);
539
- if (displays.length !== parsed.length) throw new Error('Windows display enumeration returned invalid geometry');
540
- if (0 === displays.length) throw new WindowsDisplayEnumerationEmptyError('Windows display enumeration returned no displays');
541
- return displays;
542
- }
543
- function readWindowsDisplayGeometries() {
544
- return readWindowsDisplayGeometriesWith(runWindowsPhysicalPixelPowershell);
545
- }
546
- function discoverWindowsDisplays() {
547
- try {
548
- return {
549
- geometries: readWindowsDisplayGeometries(),
550
- coordinateMode: 'physical'
551
- };
552
- } catch (error) {
553
- if (!(error instanceof WindowsDisplayEnumerationEmptyError)) throw error;
554
- const geometries = readWindowsDisplayGeometriesWith(runWindowsPowershell);
555
- return {
556
- geometries,
557
- coordinateMode: 'legacy'
558
- };
559
- }
560
- }
561
- function readPhysicalWindowsSystemDpi() {
562
- const output = runWindowsPhysicalPixelPowershell('[Console]::Out.Write($midsceneNativeMethods::GetDpiForSystem())').trim();
563
- const dpi = Number(output);
564
- if (!Number.isFinite(dpi) || dpi <= 0) throw new Error(`Windows returned an invalid system DPI value: ${output}`);
565
- return dpi;
566
- }
567
- function readPngDimensions(dataUri) {
568
- const prefix = 'data:image/png;base64,';
569
- if (!dataUri.startsWith(prefix)) throw new Error('Screenshot is not a PNG data URI');
570
- const buffer = Buffer.from(dataUri.slice(prefix.length), 'base64');
571
- const pngSignature = Buffer.from([
572
- 137,
573
- 80,
574
- 78,
575
- 71,
576
- 13,
577
- 10,
578
- 26,
579
- 10
580
- ]);
581
- if (buffer.length < 24 || !buffer.subarray(0, pngSignature.length).equals(pngSignature)) throw new Error('Screenshot returned invalid PNG data');
582
- const width = buffer.readUInt32BE(16);
583
- const height = buffer.readUInt32BE(20);
584
- if (width <= 0 || height <= 0) throw new Error('Screenshot returned invalid PNG dimensions');
585
- return {
586
- width,
587
- height
588
- };
589
- }
590
- function assertLegacyWindowsCoordinateCompatibility({ geometry, systemDpi, screenshotBase64, inputSize }) {
591
- if (!geometry?.primary) throw new Error('Windows legacy coordinate compatibility mode only supports the primary display');
592
- 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})`);
593
- if (96 !== systemDpi) throw new Error(`Windows legacy coordinate compatibility mode requires 100% display scaling (96 DPI), got ${systemDpi} DPI`);
594
- const screenshotSize = readPngDimensions(screenshotBase64);
595
- const displaySize = {
596
- width: Math.round(geometry.bounds.width),
597
- height: Math.round(geometry.bounds.height)
598
- };
599
- const sizesMatch = screenshotSize.width === displaySize.width && screenshotSize.height === displaySize.height && inputSize.width === displaySize.width && inputSize.height === displaySize.height;
600
- 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.`);
601
- }
602
- function resolveWindowsDisplayGeometryFromList(displayId, displays) {
603
- if (!displays.length) return;
604
- if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
605
- return displays.find((display)=>display.id === displayId);
606
- }
607
482
  function windows_pointer_define_property(obj, key, value) {
608
483
  if (key in obj) Object.defineProperty(obj, key, {
609
484
  value: value,
@@ -921,6 +796,28 @@ const EDGE_SCROLL_SPEC = {
921
796
  function escapePowershellSingleQuoted(value) {
922
797
  return value.replace(/'/g, "''");
923
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
+ }
924
821
  function listWindowsDisplays(geometries = readWindowsDisplayGeometries()) {
925
822
  return geometries.map((display)=>({
926
823
  id: display.id,
@@ -1024,13 +921,23 @@ function getDisplayInfoBinary() {
1024
921
  displayInfoBinaryPath = binPath;
1025
922
  return binPath;
1026
923
  }
1027
- function device_isFiniteNumber(value) {
924
+ function isFiniteNumber(value) {
1028
925
  return 'number' == typeof value && Number.isFinite(value);
1029
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
+ }
1030
937
  function isDarwinDisplayGeometry(value) {
1031
938
  if (!value || 'object' != typeof value) return false;
1032
939
  const candidate = value;
1033
- 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);
1034
941
  }
1035
942
  function readDarwinDisplayGeometries() {
1036
943
  const bin = getDisplayInfoBinary();
@@ -1100,6 +1007,11 @@ function resolveDarwinDisplayGeometryFromList(displayId, displays) {
1100
1007
  if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays.find((display)=>0 === display.screenIndex) || displays[0];
1101
1008
  return displays.find((display)=>display.screenIndex === screenIndex) || displays.find((display)=>display.cgDisplayId === screenIndex);
1102
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
+ }
1103
1015
  function resolveDisplayGeometry(displayId, windowsDisplays) {
1104
1016
  if ('darwin' === process.platform) return resolveDarwinDisplayGeometryFromList(displayId, readDarwinDisplayGeometries());
1105
1017
  if ('win32' === process.platform) {
@@ -1192,25 +1104,13 @@ function normalizePrimaryKey(key) {
1192
1104
  return KEY_NAME_MAP[lowerKey] || lowerKey;
1193
1105
  }
1194
1106
  class ComputerDevice {
1195
- usesPhysicalWindowsCoordinates() {
1196
- return 'win32' === process.platform && 'physical' === this.windowsCoordinateContext.mode;
1197
- }
1198
- assertLegacyWindowsCoordinateCompatibility(screenshotBase64) {
1199
- if ('win32' !== process.platform || 'legacy' !== this.windowsCoordinateContext.mode) return;
1200
- assertLegacyWindowsCoordinateCompatibility({
1201
- geometry: this.displayGeometry,
1202
- systemDpi: this.windowsCoordinateContext.systemDpi,
1203
- screenshotBase64,
1204
- inputSize: this.inputDriver.getScreenSize()
1205
- });
1206
- }
1207
1107
  async moveGlobalPointer(point, context, smooth) {
1208
1108
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
1209
1109
  const target = {
1210
1110
  x: Math.round(point.x),
1211
1111
  y: Math.round(point.y)
1212
1112
  };
1213
- if (this.usesPhysicalWindowsCoordinates()) {
1113
+ if ('win32' === process.platform) {
1214
1114
  const actual = this.windowsPointerDriver.moveTo(target, {
1215
1115
  smoothSteps: smooth?.smoothSteps,
1216
1116
  smoothDelayMs: smooth?.smoothDelay
@@ -1262,7 +1162,7 @@ class ComputerDevice {
1262
1162
  }
1263
1163
  static async listDisplays() {
1264
1164
  try {
1265
- if ('win32' === process.platform) return listWindowsDisplays(discoverWindowsDisplays().geometries);
1165
+ if ('win32' === process.platform) return listWindowsDisplays();
1266
1166
  const displays = await screenshot_desktop.listDisplays();
1267
1167
  return displays.map((d)=>({
1268
1168
  id: String(d.id),
@@ -1300,15 +1200,7 @@ class ComputerDevice {
1300
1200
  }
1301
1201
  }
1302
1202
  device_libnut = await getLibnut();
1303
- const windowsDisplayDiscovery = 'win32' === process.platform ? discoverWindowsDisplays() : void 0;
1304
- const windowsDisplayGeometries = windowsDisplayDiscovery?.geometries;
1305
- 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.');
1306
- this.windowsCoordinateContext = windowsDisplayDiscovery?.coordinateMode === 'legacy' ? {
1307
- mode: 'legacy',
1308
- systemDpi: readPhysicalWindowsSystemDpi()
1309
- } : {
1310
- mode: 'physical'
1311
- };
1203
+ const windowsDisplayGeometries = 'win32' === process.platform ? readWindowsDisplayGeometries() : void 0;
1312
1204
  this.displayGeometry = resolveDisplayGeometry(this.displayId, windowsDisplayGeometries);
1313
1205
  const size = await this.size();
1314
1206
  const displays = windowsDisplayGeometries ? listWindowsDisplays(windowsDisplayGeometries) : await ComputerDevice.listDisplays();
@@ -1319,7 +1211,6 @@ Platform: ${process.platform}
1319
1211
  Display: ${this.displayId || 'Primary'}
1320
1212
  Screen Size: ${size.width}x${size.height}
1321
1213
  Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ') : 'Unknown'}${headlessInfo}
1322
- ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordinateContext.mode}` : ''}
1323
1214
  `;
1324
1215
  debugDevice('Computer device connected', this.description);
1325
1216
  await this.healthCheck(displays);
@@ -1343,7 +1234,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1343
1234
  }
1344
1235
  async healthCheck(displays) {
1345
1236
  console.log('[HealthCheck] Starting health check...');
1346
- console.log("[HealthCheck] @midscene/computer v1.12.10-beta-20260920031616.0");
1237
+ console.log("[HealthCheck] @midscene/computer v1.13.0");
1347
1238
  console.log('[HealthCheck] Taking screenshot...');
1348
1239
  const screenshotTimeout = 15000;
1349
1240
  let timeoutId;
@@ -1355,12 +1246,10 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1355
1246
  timeoutPromise
1356
1247
  ]);
1357
1248
  console.log(`[HealthCheck] Screenshot succeeded (length=${base64.length})`);
1358
- this.assertLegacyWindowsCoordinateCompatibility(base64);
1359
1249
  console.log('[HealthCheck] Verifying mouse control...');
1360
- const usePhysicalWindowsCoordinates = this.usesPhysicalWindowsCoordinates();
1361
- const startPos = usePhysicalWindowsCoordinates ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1250
+ const startPos = 'win32' === process.platform ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1362
1251
  console.log(`[HealthCheck] Current mouse position: (${startPos.x}, ${startPos.y})`);
1363
- if (usePhysicalWindowsCoordinates) {
1252
+ if ('win32' === process.platform) {
1364
1253
  if (!this.displayGeometry) throw new Error('Windows display geometry is unavailable');
1365
1254
  const bounds = this.displayGeometry.bounds;
1366
1255
  const target = {
@@ -1426,7 +1315,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1426
1315
  debugDevice('Taking screenshot', {
1427
1316
  displayId: this.displayId
1428
1317
  });
1429
- if (this.usesPhysicalWindowsCoordinates()) return this.screenshotViaPowershell();
1318
+ if ('win32' === process.platform) return this.screenshotViaPowershell();
1430
1319
  const options = {
1431
1320
  format: 'png'
1432
1321
  };
@@ -1589,7 +1478,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1589
1478
  this.inputDriver.sendKey(key, modifiers);
1590
1479
  }
1591
1480
  resolveUntargetedScrollPoint(screenSize) {
1592
- if (this.usesPhysicalWindowsCoordinates()) {
1481
+ if ('win32' === process.platform) {
1593
1482
  const activeWindowRect = this.windowsPointerDriver.getActiveWindowRect();
1594
1483
  if (activeWindowRect) {
1595
1484
  const activeWindowCenter = {
@@ -1733,9 +1622,6 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1733
1622
  device_define_property(this, "options", void 0);
1734
1623
  device_define_property(this, "displayId", void 0);
1735
1624
  device_define_property(this, "displayGeometry", void 0);
1736
- device_define_property(this, "windowsCoordinateContext", {
1737
- mode: 'physical'
1738
- });
1739
1625
  device_define_property(this, "description", void 0);
1740
1626
  device_define_property(this, "destroyed", false);
1741
1627
  device_define_property(this, "xvfbInstance", void 0);
@@ -2876,7 +2762,7 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
2876
2762
  }
2877
2763
  }
2878
2764
  function version() {
2879
- const currentVersion = "1.12.10-beta-20260920031616.0";
2765
+ const currentVersion = "1.13.0";
2880
2766
  console.log(`@midscene/computer v${currentVersion}`);
2881
2767
  return currentVersion;
2882
2768
  }