@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/index.js CHANGED
@@ -476,20 +476,6 @@ $midsceneSetDpiMethod.SetImplementationFlags(
476
476
  $midsceneSetDpiMethod.GetMethodImplementationFlags() -bor
477
477
  [System.Reflection.MethodImplAttributes]::PreserveSig
478
478
  )
479
- $midsceneGetDpiForSystemMethod = $midsceneType.DefinePInvokeMethod(
480
- 'GetDpiForSystem',
481
- 'user32.dll',
482
- $midsceneMethodAttributes,
483
- [System.Reflection.CallingConventions]::Standard,
484
- [uint32],
485
- [System.Type[]]@(),
486
- [System.Runtime.InteropServices.CallingConvention]::Winapi,
487
- [System.Runtime.InteropServices.CharSet]::None
488
- )
489
- $midsceneGetDpiForSystemMethod.SetImplementationFlags(
490
- $midsceneGetDpiForSystemMethod.GetMethodImplementationFlags() -bor
491
- [System.Reflection.MethodImplAttributes]::PreserveSig
492
- )
493
479
  $midsceneGetForegroundWindowMethod = $midsceneType.DefinePInvokeMethod(
494
480
  'GetForegroundWindow',
495
481
  'user32.dll',
@@ -526,8 +512,12 @@ if ($midscenePreviousDpiContext -eq [System.IntPtr]::Zero) {
526
512
  throw 'Unable to enter the Per-Monitor V2 DPI awareness context.'
527
513
  }
528
514
  `.trim();
529
- function runWindowsPowershellScript(script) {
530
- const encoded = Buffer.from(script, 'utf16le').toString('base64');
515
+ function runWindowsPhysicalPixelPowershell(script) {
516
+ const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
517
+ $ErrorActionPreference = 'Stop'
518
+ ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
519
+ ${script}`;
520
+ const encoded = Buffer.from(physicalPixelScript, 'utf16le').toString('base64');
531
521
  return (0, external_node_child_process_namespaceObject.execFileSync)('powershell.exe', [
532
522
  '-NoProfile',
533
523
  '-NonInteractive',
@@ -540,121 +530,6 @@ function runWindowsPowershellScript(script) {
540
530
  windowsHide: true
541
531
  });
542
532
  }
543
- function runWindowsPowershell(script) {
544
- return runWindowsPowershellScript(`$ProgressPreference = 'SilentlyContinue'
545
- $ErrorActionPreference = 'Stop'
546
- ${script}`);
547
- }
548
- function runWindowsPhysicalPixelPowershell(script) {
549
- const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
550
- $ErrorActionPreference = 'Stop'
551
- ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
552
- ${script}`;
553
- return runWindowsPowershellScript(physicalPixelScript);
554
- }
555
- class WindowsDisplayEnumerationEmptyError extends Error {
556
- }
557
- function isFiniteNumber(value) {
558
- return 'number' == typeof value && Number.isFinite(value);
559
- }
560
- function isWindowsDisplayGeometry(value) {
561
- if (!value || 'object' != typeof value) return false;
562
- const candidate = value;
563
- const bounds = candidate.bounds;
564
- 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;
565
- }
566
- function readWindowsDisplayGeometriesWith(runPowershell) {
567
- const script = `
568
- Add-Type -AssemblyName System.Windows.Forms
569
- $screens = @([System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
570
- $bounds = $_.Bounds
571
- [PSCustomObject]@{
572
- id = $_.DeviceName
573
- name = $_.DeviceName
574
- primary = $_.Primary
575
- bounds = [PSCustomObject]@{
576
- x = $bounds.X
577
- y = $bounds.Y
578
- width = $bounds.Width
579
- height = $bounds.Height
580
- }
581
- }
582
- })
583
- [Console]::Out.Write((ConvertTo-Json -InputObject $screens -Compress))
584
- `.trim();
585
- const output = runPowershell(script).trim();
586
- if (!output) throw new WindowsDisplayEnumerationEmptyError('Windows display enumeration returned no data');
587
- const parsed = JSON.parse(output);
588
- if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
589
- const displays = parsed.filter(isWindowsDisplayGeometry);
590
- if (displays.length !== parsed.length) throw new Error('Windows display enumeration returned invalid geometry');
591
- if (0 === displays.length) throw new WindowsDisplayEnumerationEmptyError('Windows display enumeration returned no displays');
592
- return displays;
593
- }
594
- function readWindowsDisplayGeometries() {
595
- return readWindowsDisplayGeometriesWith(runWindowsPhysicalPixelPowershell);
596
- }
597
- function discoverWindowsDisplays() {
598
- try {
599
- return {
600
- geometries: readWindowsDisplayGeometries(),
601
- coordinateMode: 'physical'
602
- };
603
- } catch (error) {
604
- if (!(error instanceof WindowsDisplayEnumerationEmptyError)) throw error;
605
- const geometries = readWindowsDisplayGeometriesWith(runWindowsPowershell);
606
- return {
607
- geometries,
608
- coordinateMode: 'legacy'
609
- };
610
- }
611
- }
612
- function readPhysicalWindowsSystemDpi() {
613
- const output = runWindowsPhysicalPixelPowershell('[Console]::Out.Write($midsceneNativeMethods::GetDpiForSystem())').trim();
614
- const dpi = Number(output);
615
- if (!Number.isFinite(dpi) || dpi <= 0) throw new Error(`Windows returned an invalid system DPI value: ${output}`);
616
- return dpi;
617
- }
618
- function readPngDimensions(dataUri) {
619
- const prefix = 'data:image/png;base64,';
620
- if (!dataUri.startsWith(prefix)) throw new Error('Screenshot is not a PNG data URI');
621
- const buffer = Buffer.from(dataUri.slice(prefix.length), 'base64');
622
- const pngSignature = Buffer.from([
623
- 137,
624
- 80,
625
- 78,
626
- 71,
627
- 13,
628
- 10,
629
- 26,
630
- 10
631
- ]);
632
- if (buffer.length < 24 || !buffer.subarray(0, pngSignature.length).equals(pngSignature)) throw new Error('Screenshot returned invalid PNG data');
633
- const width = buffer.readUInt32BE(16);
634
- const height = buffer.readUInt32BE(20);
635
- if (width <= 0 || height <= 0) throw new Error('Screenshot returned invalid PNG dimensions');
636
- return {
637
- width,
638
- height
639
- };
640
- }
641
- function assertLegacyWindowsCoordinateCompatibility({ geometry, systemDpi, screenshotBase64, inputSize }) {
642
- if (!geometry?.primary) throw new Error('Windows legacy coordinate compatibility mode only supports the primary display');
643
- 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})`);
644
- if (96 !== systemDpi) throw new Error(`Windows legacy coordinate compatibility mode requires 100% display scaling (96 DPI), got ${systemDpi} DPI`);
645
- const screenshotSize = readPngDimensions(screenshotBase64);
646
- const displaySize = {
647
- width: Math.round(geometry.bounds.width),
648
- height: Math.round(geometry.bounds.height)
649
- };
650
- const sizesMatch = screenshotSize.width === displaySize.width && screenshotSize.height === displaySize.height && inputSize.width === displaySize.width && inputSize.height === displaySize.height;
651
- 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.`);
652
- }
653
- function resolveWindowsDisplayGeometryFromList(displayId, displays) {
654
- if (!displays.length) return;
655
- if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
656
- return displays.find((display)=>display.id === displayId);
657
- }
658
533
  function windows_pointer_define_property(obj, key, value) {
659
534
  if (key in obj) Object.defineProperty(obj, key, {
660
535
  value: value,
@@ -973,6 +848,28 @@ const EDGE_SCROLL_SPEC = {
973
848
  function escapePowershellSingleQuoted(value) {
974
849
  return value.replace(/'/g, "''");
975
850
  }
851
+ function readWindowsDisplayGeometries() {
852
+ const script = `
853
+ Add-Type -AssemblyName System.Windows.Forms
854
+ $s = [System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
855
+ $b = $_.Bounds
856
+ [PSCustomObject]@{
857
+ id = $_.DeviceName
858
+ name = $_.DeviceName
859
+ primary = $_.Primary
860
+ bounds = [PSCustomObject]@{ x = $b.X; y = $b.Y; width = $b.Width; height = $b.Height }
861
+ }
862
+ }
863
+ ConvertTo-Json @($s) -Compress
864
+ `.trim();
865
+ const output = runWindowsPhysicalPixelPowershell(script).trim();
866
+ if (!output) throw new Error('Windows display enumeration returned no data');
867
+ const parsed = JSON.parse(output);
868
+ if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
869
+ const displays = parsed.filter(isWindowsDisplayGeometry);
870
+ if (displays.length !== parsed.length || 0 === displays.length) throw new Error('Windows display enumeration returned invalid geometry');
871
+ return displays;
872
+ }
976
873
  function listWindowsDisplays(geometries = readWindowsDisplayGeometries()) {
977
874
  return geometries.map((display)=>({
978
875
  id: display.id,
@@ -1076,13 +973,23 @@ function getDisplayInfoBinary() {
1076
973
  displayInfoBinaryPath = binPath;
1077
974
  return binPath;
1078
975
  }
1079
- function device_isFiniteNumber(value) {
976
+ function isFiniteNumber(value) {
1080
977
  return 'number' == typeof value && Number.isFinite(value);
1081
978
  }
979
+ function isDisplayBounds(value) {
980
+ if (!value || 'object' != typeof value) return false;
981
+ const bounds = value;
982
+ return isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
983
+ }
984
+ function isWindowsDisplayGeometry(value) {
985
+ if (!value || 'object' != typeof value) return false;
986
+ const candidate = value;
987
+ return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && isDisplayBounds(candidate.bounds);
988
+ }
1082
989
  function isDarwinDisplayGeometry(value) {
1083
990
  if (!value || 'object' != typeof value) return false;
1084
991
  const candidate = value;
1085
- 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);
992
+ 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);
1086
993
  }
1087
994
  function readDarwinDisplayGeometries() {
1088
995
  const bin = getDisplayInfoBinary();
@@ -1152,6 +1059,11 @@ function resolveDarwinDisplayGeometryFromList(displayId, displays) {
1152
1059
  if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays.find((display)=>0 === display.screenIndex) || displays[0];
1153
1060
  return displays.find((display)=>display.screenIndex === screenIndex) || displays.find((display)=>display.cgDisplayId === screenIndex);
1154
1061
  }
1062
+ function resolveWindowsDisplayGeometryFromList(displayId, displays) {
1063
+ if (!displays.length) return;
1064
+ if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
1065
+ return displays.find((display)=>display.id === displayId);
1066
+ }
1155
1067
  function resolveDisplayGeometry(displayId, windowsDisplays) {
1156
1068
  if ('darwin' === process.platform) return resolveDarwinDisplayGeometryFromList(displayId, readDarwinDisplayGeometries());
1157
1069
  if ('win32' === process.platform) {
@@ -1244,25 +1156,13 @@ function normalizePrimaryKey(key) {
1244
1156
  return KEY_NAME_MAP[lowerKey] || lowerKey;
1245
1157
  }
1246
1158
  class ComputerDevice {
1247
- usesPhysicalWindowsCoordinates() {
1248
- return 'win32' === process.platform && 'physical' === this.windowsCoordinateContext.mode;
1249
- }
1250
- assertLegacyWindowsCoordinateCompatibility(screenshotBase64) {
1251
- if ('win32' !== process.platform || 'legacy' !== this.windowsCoordinateContext.mode) return;
1252
- assertLegacyWindowsCoordinateCompatibility({
1253
- geometry: this.displayGeometry,
1254
- systemDpi: this.windowsCoordinateContext.systemDpi,
1255
- screenshotBase64,
1256
- inputSize: this.inputDriver.getScreenSize()
1257
- });
1258
- }
1259
1159
  async moveGlobalPointer(point, context, smooth) {
1260
1160
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
1261
1161
  const target = {
1262
1162
  x: Math.round(point.x),
1263
1163
  y: Math.round(point.y)
1264
1164
  };
1265
- if (this.usesPhysicalWindowsCoordinates()) {
1165
+ if ('win32' === process.platform) {
1266
1166
  const actual = this.windowsPointerDriver.moveTo(target, {
1267
1167
  smoothSteps: smooth?.smoothSteps,
1268
1168
  smoothDelayMs: smooth?.smoothDelay
@@ -1314,7 +1214,7 @@ class ComputerDevice {
1314
1214
  }
1315
1215
  static async listDisplays() {
1316
1216
  try {
1317
- if ('win32' === process.platform) return listWindowsDisplays(discoverWindowsDisplays().geometries);
1217
+ if ('win32' === process.platform) return listWindowsDisplays();
1318
1218
  const displays = await external_screenshot_desktop_default().listDisplays();
1319
1219
  return displays.map((d)=>({
1320
1220
  id: String(d.id),
@@ -1352,15 +1252,7 @@ class ComputerDevice {
1352
1252
  }
1353
1253
  }
1354
1254
  device_libnut = await getLibnut();
1355
- const windowsDisplayDiscovery = 'win32' === process.platform ? discoverWindowsDisplays() : void 0;
1356
- const windowsDisplayGeometries = windowsDisplayDiscovery?.geometries;
1357
- 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.');
1358
- this.windowsCoordinateContext = windowsDisplayDiscovery?.coordinateMode === 'legacy' ? {
1359
- mode: 'legacy',
1360
- systemDpi: readPhysicalWindowsSystemDpi()
1361
- } : {
1362
- mode: 'physical'
1363
- };
1255
+ const windowsDisplayGeometries = 'win32' === process.platform ? readWindowsDisplayGeometries() : void 0;
1364
1256
  this.displayGeometry = resolveDisplayGeometry(this.displayId, windowsDisplayGeometries);
1365
1257
  const size = await this.size();
1366
1258
  const displays = windowsDisplayGeometries ? listWindowsDisplays(windowsDisplayGeometries) : await ComputerDevice.listDisplays();
@@ -1371,7 +1263,6 @@ Platform: ${process.platform}
1371
1263
  Display: ${this.displayId || 'Primary'}
1372
1264
  Screen Size: ${size.width}x${size.height}
1373
1265
  Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ') : 'Unknown'}${headlessInfo}
1374
- ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordinateContext.mode}` : ''}
1375
1266
  `;
1376
1267
  debugDevice('Computer device connected', this.description);
1377
1268
  await this.healthCheck(displays);
@@ -1395,7 +1286,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1395
1286
  }
1396
1287
  async healthCheck(displays) {
1397
1288
  console.log('[HealthCheck] Starting health check...');
1398
- console.log("[HealthCheck] @midscene/computer v1.12.10-beta-20260920031616.0");
1289
+ console.log("[HealthCheck] @midscene/computer v1.13.0");
1399
1290
  console.log('[HealthCheck] Taking screenshot...');
1400
1291
  const screenshotTimeout = 15000;
1401
1292
  let timeoutId;
@@ -1407,12 +1298,10 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1407
1298
  timeoutPromise
1408
1299
  ]);
1409
1300
  console.log(`[HealthCheck] Screenshot succeeded (length=${base64.length})`);
1410
- this.assertLegacyWindowsCoordinateCompatibility(base64);
1411
1301
  console.log('[HealthCheck] Verifying mouse control...');
1412
- const usePhysicalWindowsCoordinates = this.usesPhysicalWindowsCoordinates();
1413
- const startPos = usePhysicalWindowsCoordinates ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1302
+ const startPos = 'win32' === process.platform ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1414
1303
  console.log(`[HealthCheck] Current mouse position: (${startPos.x}, ${startPos.y})`);
1415
- if (usePhysicalWindowsCoordinates) {
1304
+ if ('win32' === process.platform) {
1416
1305
  if (!this.displayGeometry) throw new Error('Windows display geometry is unavailable');
1417
1306
  const bounds = this.displayGeometry.bounds;
1418
1307
  const target = {
@@ -1478,7 +1367,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1478
1367
  debugDevice('Taking screenshot', {
1479
1368
  displayId: this.displayId
1480
1369
  });
1481
- if (this.usesPhysicalWindowsCoordinates()) return this.screenshotViaPowershell();
1370
+ if ('win32' === process.platform) return this.screenshotViaPowershell();
1482
1371
  const options = {
1483
1372
  format: 'png'
1484
1373
  };
@@ -1641,7 +1530,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1641
1530
  this.inputDriver.sendKey(key, modifiers);
1642
1531
  }
1643
1532
  resolveUntargetedScrollPoint(screenSize) {
1644
- if (this.usesPhysicalWindowsCoordinates()) {
1533
+ if ('win32' === process.platform) {
1645
1534
  const activeWindowRect = this.windowsPointerDriver.getActiveWindowRect();
1646
1535
  if (activeWindowRect) {
1647
1536
  const activeWindowCenter = {
@@ -1785,9 +1674,6 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1785
1674
  device_define_property(this, "options", void 0);
1786
1675
  device_define_property(this, "displayId", void 0);
1787
1676
  device_define_property(this, "displayGeometry", void 0);
1788
- device_define_property(this, "windowsCoordinateContext", {
1789
- mode: 'physical'
1790
- });
1791
1677
  device_define_property(this, "description", void 0);
1792
1678
  device_define_property(this, "destroyed", false);
1793
1679
  device_define_property(this, "xvfbInstance", void 0);
@@ -2934,7 +2820,7 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
2934
2820
  }
2935
2821
  const env_namespaceObject = require("@midscene/shared/env");
2936
2822
  function version() {
2937
- const currentVersion = "1.12.10-beta-20260920031616.0";
2823
+ const currentVersion = "1.13.0";
2938
2824
  console.log(`@midscene/computer v${currentVersion}`);
2939
2825
  return currentVersion;
2940
2826
  }
@@ -70,7 +70,6 @@ export declare class ComputerDevice implements AbstractInterface {
70
70
  private options?;
71
71
  private displayId?;
72
72
  private displayGeometry?;
73
- private windowsCoordinateContext;
74
73
  private description?;
75
74
  private destroyed;
76
75
  private xvfbInstance?;
@@ -88,8 +87,6 @@ export declare class ComputerDevice implements AbstractInterface {
88
87
  uri?: string;
89
88
  readonly inputPrimitives: ComputerInputPrimitives;
90
89
  constructor(options?: ComputerDeviceOpt);
91
- private usesPhysicalWindowsCoordinates;
92
- private assertLegacyWindowsCoordinateCompatibility;
93
90
  private moveGlobalPointer;
94
91
  private moveDisplayPointer;
95
92
  private performPointerDrag;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/computer",
3
- "version": "1.12.10-beta-20260920031616.0",
3
+ "version": "1.13.0",
4
4
  "description": "Midscene.js Computer Desktop Automation",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,8 +33,8 @@
33
33
  "@computer-use/libnut": "^4.2.0",
34
34
  "clipboardy": "^4.0.0",
35
35
  "screenshot-desktop": "^1.15.3",
36
- "@midscene/shared": "1.12.10-beta-20260920031616.0",
37
- "@midscene/core": "1.12.10-beta-20260920031616.0"
36
+ "@midscene/core": "1.13.0",
37
+ "@midscene/shared": "1.13.0"
38
38
  },
39
39
  "optionalDependencies": {
40
40
  "node-mac-permissions": "2.5.0"