@midscene/computer 1.12.2 → 1.12.3-beta-20260828085408.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 +239 -75
- package/dist/es/index.mjs +239 -75
- package/dist/lib/cli.js +239 -75
- package/dist/lib/index.js +239 -75
- package/dist/types/index.d.ts +7 -4
- package/package.json +3 -3
package/dist/lib/cli.js
CHANGED
|
@@ -54,6 +54,7 @@ function _define_property(obj, key, value) {
|
|
|
54
54
|
else obj[key] = value;
|
|
55
55
|
return obj;
|
|
56
56
|
}
|
|
57
|
+
const MOUSE_COORDINATE_TOLERANCE_PX = 5;
|
|
57
58
|
class ComputerInputDriver {
|
|
58
59
|
destroy() {
|
|
59
60
|
if (this.destroyed) return;
|
|
@@ -69,6 +70,15 @@ class ComputerInputDriver {
|
|
|
69
70
|
moveMouse(x, y) {
|
|
70
71
|
this.getLibnutOrThrow('moveMouse').moveMouse(x, y);
|
|
71
72
|
}
|
|
73
|
+
assertMousePosition(targetX, targetY, context) {
|
|
74
|
+
const current = this.getMousePos();
|
|
75
|
+
const drift = {
|
|
76
|
+
x: current.x - targetX,
|
|
77
|
+
y: current.y - targetY
|
|
78
|
+
};
|
|
79
|
+
if (Math.abs(drift.x) > MOUSE_COORDINATE_TOLERANCE_PX || Math.abs(drift.y) > MOUSE_COORDINATE_TOLERANCE_PX) throw new Error(`${context}: expected (${targetX}, ${targetY}), got (${current.x}, ${current.y}), drift=(${drift.x}, ${drift.y})`);
|
|
80
|
+
return drift;
|
|
81
|
+
}
|
|
72
82
|
focusActiveWindow() {
|
|
73
83
|
const lib = this.getLibnutOrThrow('focusActiveWindow');
|
|
74
84
|
if ('function' != typeof lib.getActiveWindow || 'function' != typeof lib.focusWindow) return false;
|
|
@@ -209,6 +219,83 @@ class ComputerInputDriver {
|
|
|
209
219
|
this.pendingInputDelayWaits = new Set();
|
|
210
220
|
}
|
|
211
221
|
}
|
|
222
|
+
function windows_pointer_define_property(obj, key, value) {
|
|
223
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
224
|
+
value: value,
|
|
225
|
+
enumerable: true,
|
|
226
|
+
configurable: true,
|
|
227
|
+
writable: true
|
|
228
|
+
});
|
|
229
|
+
else obj[key] = value;
|
|
230
|
+
return obj;
|
|
231
|
+
}
|
|
232
|
+
const WINDOWS_POINTER_TOLERANCE_PX = 5;
|
|
233
|
+
function assertFinitePoint(point, context) {
|
|
234
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) throw new Error(`${context} must contain finite coordinates, got (${point.x}, ${point.y})`);
|
|
235
|
+
}
|
|
236
|
+
function parseWindowsPointerPosition(output, context) {
|
|
237
|
+
const match = output.trim().match(/^(-?\d+),(-?\d+)$/);
|
|
238
|
+
if (!match) throw new Error(`${context} returned an invalid cursor position: ${JSON.stringify(output.trim())}`);
|
|
239
|
+
return {
|
|
240
|
+
x: Number(match[1]),
|
|
241
|
+
y: Number(match[2])
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function windowsPointerPositionScript() {
|
|
245
|
+
return `
|
|
246
|
+
Add-Type -AssemblyName System.Windows.Forms, System.Drawing
|
|
247
|
+
$position = [System.Windows.Forms.Cursor]::Position
|
|
248
|
+
[Console]::Out.Write(('{0},{1}' -f $position.X, $position.Y))
|
|
249
|
+
`.trim();
|
|
250
|
+
}
|
|
251
|
+
function windowsPointerMoveScript(point, options) {
|
|
252
|
+
assertFinitePoint(point, 'Windows pointer target');
|
|
253
|
+
if (options?.smoothSteps !== void 0 && !Number.isFinite(options.smoothSteps) || options?.smoothDelayMs !== void 0 && !Number.isFinite(options.smoothDelayMs)) throw new Error('Windows pointer smoothing options must be finite numbers');
|
|
254
|
+
const targetX = Math.round(point.x);
|
|
255
|
+
const targetY = Math.round(point.y);
|
|
256
|
+
const smoothSteps = Math.max(1, Math.round(options?.smoothSteps ?? 1));
|
|
257
|
+
const smoothDelayMs = Math.max(0, Math.round(options?.smoothDelayMs ?? 0));
|
|
258
|
+
return `
|
|
259
|
+
Add-Type -AssemblyName System.Windows.Forms, System.Drawing
|
|
260
|
+
$targetX = ${targetX}
|
|
261
|
+
$targetY = ${targetY}
|
|
262
|
+
$smoothSteps = ${smoothSteps}
|
|
263
|
+
$smoothDelayMs = ${smoothDelayMs}
|
|
264
|
+
$start = [System.Windows.Forms.Cursor]::Position
|
|
265
|
+
for ($step = 1; $step -le $smoothSteps; $step += 1) {
|
|
266
|
+
$x = [int][Math]::Round($start.X + (($targetX - $start.X) * $step / [double]$smoothSteps))
|
|
267
|
+
$y = [int][Math]::Round($start.Y + (($targetY - $start.Y) * $step / [double]$smoothSteps))
|
|
268
|
+
[System.Windows.Forms.Cursor]::Position = [System.Drawing.Point]::new($x, $y)
|
|
269
|
+
if ($smoothDelayMs -gt 0 -and $step -lt $smoothSteps) {
|
|
270
|
+
Start-Sleep -Milliseconds $smoothDelayMs
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
[System.Windows.Forms.Cursor]::Position = [System.Drawing.Point]::new($targetX, $targetY)
|
|
274
|
+
$position = [System.Windows.Forms.Cursor]::Position
|
|
275
|
+
[Console]::Out.Write(('{0},{1}' -f $position.X, $position.Y))
|
|
276
|
+
`.trim();
|
|
277
|
+
}
|
|
278
|
+
class WindowsPointerDriver {
|
|
279
|
+
getPosition() {
|
|
280
|
+
return parseWindowsPointerPosition(this.options.runPowershell(windowsPointerPositionScript()), 'Windows pointer query');
|
|
281
|
+
}
|
|
282
|
+
moveTo(point, options) {
|
|
283
|
+
return parseWindowsPointerPosition(this.options.runPowershell(windowsPointerMoveScript(point, options)), 'Windows pointer move');
|
|
284
|
+
}
|
|
285
|
+
constructor(options){
|
|
286
|
+
windows_pointer_define_property(this, "options", void 0);
|
|
287
|
+
this.options = options;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function windowsPointerDrift(expected, actual) {
|
|
291
|
+
return {
|
|
292
|
+
x: actual.x - expected.x,
|
|
293
|
+
y: actual.y - expected.y
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function windowsPointerIsWithinTolerance(drift) {
|
|
297
|
+
return Math.abs(drift.x) <= WINDOWS_POINTER_TOLERANCE_PX && Math.abs(drift.y) <= WINDOWS_POINTER_TOLERANCE_PX;
|
|
298
|
+
}
|
|
212
299
|
const interrupt_namespaceObject = require("@midscene/shared/cli/interrupt");
|
|
213
300
|
const debugXvfb = (0, logger_namespaceObject.getDebug)('computer:xvfb');
|
|
214
301
|
const xvfbCleanupMonitorScript = String.raw`
|
|
@@ -487,19 +574,33 @@ function runPowershell(script) {
|
|
|
487
574
|
windowsHide: true
|
|
488
575
|
});
|
|
489
576
|
}
|
|
490
|
-
function
|
|
577
|
+
function readWindowsDisplayGeometries() {
|
|
491
578
|
const script = `
|
|
492
579
|
Add-Type -AssemblyName System.Windows.Forms
|
|
493
580
|
$s = [System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
|
|
494
|
-
|
|
581
|
+
$b = $_.Bounds
|
|
582
|
+
[PSCustomObject]@{
|
|
583
|
+
id = $_.DeviceName
|
|
584
|
+
name = $_.DeviceName
|
|
585
|
+
primary = $_.Primary
|
|
586
|
+
bounds = [PSCustomObject]@{ x = $b.X; y = $b.Y; width = $b.Width; height = $b.Height }
|
|
587
|
+
}
|
|
495
588
|
}
|
|
496
589
|
ConvertTo-Json @($s) -Compress
|
|
497
590
|
`.trim();
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
591
|
+
const output = runPowershell(script).trim();
|
|
592
|
+
if (!output) throw new Error('Windows display enumeration returned no data');
|
|
593
|
+
const parsed = JSON.parse(output);
|
|
594
|
+
if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
|
|
595
|
+
const displays = parsed.filter(isWindowsDisplayGeometry);
|
|
596
|
+
if (displays.length !== parsed.length || 0 === displays.length) throw new Error('Windows display enumeration returned invalid geometry');
|
|
597
|
+
return displays;
|
|
598
|
+
}
|
|
599
|
+
function listWindowsDisplays(geometries = readWindowsDisplayGeometries()) {
|
|
600
|
+
return geometries.map((display)=>({
|
|
601
|
+
id: display.id,
|
|
602
|
+
name: display.name,
|
|
603
|
+
primary: display.primary
|
|
503
604
|
}));
|
|
504
605
|
}
|
|
505
606
|
let device_libnut = null;
|
|
@@ -601,6 +702,16 @@ function getDisplayInfoBinary() {
|
|
|
601
702
|
function isFiniteNumber(value) {
|
|
602
703
|
return 'number' == typeof value && Number.isFinite(value);
|
|
603
704
|
}
|
|
705
|
+
function isDisplayBounds(value) {
|
|
706
|
+
if (!value || 'object' != typeof value) return false;
|
|
707
|
+
const bounds = value;
|
|
708
|
+
return isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
|
|
709
|
+
}
|
|
710
|
+
function isWindowsDisplayGeometry(value) {
|
|
711
|
+
if (!value || 'object' != typeof value) return false;
|
|
712
|
+
const candidate = value;
|
|
713
|
+
return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && isDisplayBounds(candidate.bounds);
|
|
714
|
+
}
|
|
604
715
|
function isDarwinDisplayGeometry(value) {
|
|
605
716
|
if (!value || 'object' != typeof value) return false;
|
|
606
717
|
const candidate = value;
|
|
@@ -643,9 +754,11 @@ function readDarwinFrontmostApplication() {
|
|
|
643
754
|
return;
|
|
644
755
|
}
|
|
645
756
|
}
|
|
646
|
-
async function pressMouseAtGlobalPoint(inputDriver, targetX, targetY, holdDuration, reason) {
|
|
647
|
-
|
|
648
|
-
|
|
757
|
+
async function pressMouseAtGlobalPoint(inputDriver, targetX, targetY, current, holdDuration, reason) {
|
|
758
|
+
const drift = {
|
|
759
|
+
x: current.x - targetX,
|
|
760
|
+
y: current.y - targetY
|
|
761
|
+
};
|
|
649
762
|
debugComputerInput('tap mouse moved %o', {
|
|
650
763
|
reason,
|
|
651
764
|
target: {
|
|
@@ -653,10 +766,7 @@ async function pressMouseAtGlobalPoint(inputDriver, targetX, targetY, holdDurati
|
|
|
653
766
|
y: targetY
|
|
654
767
|
},
|
|
655
768
|
current,
|
|
656
|
-
drift
|
|
657
|
-
x: current.x - targetX,
|
|
658
|
-
y: current.y - targetY
|
|
659
|
-
}
|
|
769
|
+
drift
|
|
660
770
|
});
|
|
661
771
|
await inputDriver.withMouseButton('left', async ()=>{
|
|
662
772
|
debugComputerInput('tap mouse down %o', {
|
|
@@ -675,9 +785,18 @@ function resolveDarwinDisplayGeometryFromList(displayId, displays) {
|
|
|
675
785
|
if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays.find((display)=>0 === display.screenIndex) || displays[0];
|
|
676
786
|
return displays.find((display)=>display.screenIndex === screenIndex) || displays.find((display)=>display.cgDisplayId === screenIndex);
|
|
677
787
|
}
|
|
678
|
-
function
|
|
679
|
-
if (
|
|
680
|
-
|
|
788
|
+
function resolveWindowsDisplayGeometryFromList(displayId, displays) {
|
|
789
|
+
if (!displays.length) return;
|
|
790
|
+
if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
|
|
791
|
+
return displays.find((display)=>display.id === displayId);
|
|
792
|
+
}
|
|
793
|
+
function resolveDisplayGeometry(displayId, windowsDisplays) {
|
|
794
|
+
if ('darwin' === process.platform) return resolveDarwinDisplayGeometryFromList(displayId, readDarwinDisplayGeometries());
|
|
795
|
+
if ('win32' === process.platform) {
|
|
796
|
+
const geometry = resolveWindowsDisplayGeometryFromList(displayId, windowsDisplays ?? readWindowsDisplayGeometries());
|
|
797
|
+
if (!geometry) throw new Error(displayId ? `Requested Windows display not found: ${displayId}` : 'No Windows displays were detected');
|
|
798
|
+
return geometry;
|
|
799
|
+
}
|
|
681
800
|
}
|
|
682
801
|
function mapDisplayLocalPointToGlobal(point, geometry) {
|
|
683
802
|
if (!geometry) return point;
|
|
@@ -763,6 +882,30 @@ function normalizePrimaryKey(key) {
|
|
|
763
882
|
return KEY_NAME_MAP[lowerKey] || lowerKey;
|
|
764
883
|
}
|
|
765
884
|
class ComputerDevice {
|
|
885
|
+
async moveGlobalPointer(point, context, smooth) {
|
|
886
|
+
if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
|
|
887
|
+
const target = {
|
|
888
|
+
x: Math.round(point.x),
|
|
889
|
+
y: Math.round(point.y)
|
|
890
|
+
};
|
|
891
|
+
if ('win32' === process.platform) {
|
|
892
|
+
const actual = this.windowsPointerDriver.moveTo(target, {
|
|
893
|
+
smoothSteps: smooth?.smoothSteps,
|
|
894
|
+
smoothDelayMs: smooth?.smoothDelay
|
|
895
|
+
});
|
|
896
|
+
const drift = windowsPointerDrift(target, actual);
|
|
897
|
+
if (!windowsPointerIsWithinTolerance(drift)) throw new Error(`${context}: expected (${target.x}, ${target.y}), got (${actual.x}, ${actual.y}), drift=(${drift.x}, ${drift.y})`);
|
|
898
|
+
await this.inputDriver.delay(CLICK_SETTLE_DELAY);
|
|
899
|
+
return actual;
|
|
900
|
+
}
|
|
901
|
+
if (smooth) await this.inputDriver.smoothMoveMouse(target.x, target.y, smooth.smoothSteps, smooth.smoothDelay);
|
|
902
|
+
else this.inputDriver.moveMouse(target.x, target.y);
|
|
903
|
+
await this.inputDriver.delay(CLICK_SETTLE_DELAY);
|
|
904
|
+
return target;
|
|
905
|
+
}
|
|
906
|
+
moveDisplayPointer(point, context, smooth) {
|
|
907
|
+
return this.moveGlobalPointer(this.toGlobalPoint(point), context, smooth);
|
|
908
|
+
}
|
|
766
909
|
async focusKeyboardTarget(element, delayMs) {
|
|
767
910
|
const [x, y] = element.center;
|
|
768
911
|
if ('darwin' === process.platform) await this.inputPrimitives.pointer.tap({
|
|
@@ -770,11 +913,10 @@ class ComputerDevice {
|
|
|
770
913
|
y
|
|
771
914
|
});
|
|
772
915
|
else {
|
|
773
|
-
|
|
916
|
+
await this.moveDisplayPointer({
|
|
774
917
|
x,
|
|
775
918
|
y
|
|
776
|
-
});
|
|
777
|
-
this.inputDriver.moveMouse(Math.round(point.x), Math.round(point.y));
|
|
919
|
+
}, 'Mouse did not reach the keyboard focus target');
|
|
778
920
|
this.inputDriver.mouseClick('left');
|
|
779
921
|
}
|
|
780
922
|
await this.inputDriver.delay(delayMs);
|
|
@@ -793,7 +935,7 @@ class ComputerDevice {
|
|
|
793
935
|
}));
|
|
794
936
|
} catch (error) {
|
|
795
937
|
debugDevice(`Failed to list displays: ${error}`);
|
|
796
|
-
|
|
938
|
+
throw new Error(`Failed to list displays: ${error}`);
|
|
797
939
|
}
|
|
798
940
|
}
|
|
799
941
|
async connect() {
|
|
@@ -822,9 +964,10 @@ class ComputerDevice {
|
|
|
822
964
|
}
|
|
823
965
|
}
|
|
824
966
|
device_libnut = await getLibnut();
|
|
825
|
-
|
|
967
|
+
const windowsDisplayGeometries = 'win32' === process.platform ? readWindowsDisplayGeometries() : void 0;
|
|
968
|
+
this.displayGeometry = resolveDisplayGeometry(this.displayId, windowsDisplayGeometries);
|
|
826
969
|
const size = await this.size();
|
|
827
|
-
const displays = await ComputerDevice.listDisplays();
|
|
970
|
+
const displays = windowsDisplayGeometries ? listWindowsDisplays(windowsDisplayGeometries) : await ComputerDevice.listDisplays();
|
|
828
971
|
const headlessInfo = this.xvfbInstance ? `\nHeadless: true (Xvfb on ${this.xvfbInstance.display})` : '';
|
|
829
972
|
this.description = `
|
|
830
973
|
Type: Computer
|
|
@@ -834,7 +977,7 @@ Screen Size: ${size.width}x${size.height}
|
|
|
834
977
|
Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ') : 'Unknown'}${headlessInfo}
|
|
835
978
|
`;
|
|
836
979
|
debugDevice('Computer device connected', this.description);
|
|
837
|
-
await this.healthCheck();
|
|
980
|
+
await this.healthCheck(displays);
|
|
838
981
|
} catch (error) {
|
|
839
982
|
if (this.xvfbInstance) {
|
|
840
983
|
if (!this.options?.keepXvfbAliveUntilProcessExit) this.xvfbInstance.stop();
|
|
@@ -853,9 +996,9 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
853
996
|
throw new Error(`Unable to connect to computer device: ${error}`);
|
|
854
997
|
}
|
|
855
998
|
}
|
|
856
|
-
async healthCheck() {
|
|
999
|
+
async healthCheck(displays) {
|
|
857
1000
|
console.log('[HealthCheck] Starting health check...');
|
|
858
|
-
console.log("[HealthCheck] @midscene/computer v1.12.
|
|
1001
|
+
console.log("[HealthCheck] @midscene/computer v1.12.3-beta-20260828085408.0");
|
|
859
1002
|
console.log('[HealthCheck] Taking screenshot...');
|
|
860
1003
|
const screenshotTimeout = 15000;
|
|
861
1004
|
let timeoutId;
|
|
@@ -867,23 +1010,38 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
867
1010
|
timeoutPromise
|
|
868
1011
|
]);
|
|
869
1012
|
console.log(`[HealthCheck] Screenshot succeeded (length=${base64.length})`);
|
|
870
|
-
console.log('[HealthCheck]
|
|
871
|
-
const startPos = this.inputDriver.getMousePos();
|
|
1013
|
+
console.log('[HealthCheck] Verifying mouse control...');
|
|
1014
|
+
const startPos = 'win32' === process.platform ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
|
|
872
1015
|
console.log(`[HealthCheck] Current mouse position: (${startPos.x}, ${startPos.y})`);
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1016
|
+
if ('win32' === process.platform) {
|
|
1017
|
+
if (!this.displayGeometry) throw new Error('Windows display geometry is unavailable');
|
|
1018
|
+
const bounds = this.displayGeometry.bounds;
|
|
1019
|
+
const target = {
|
|
1020
|
+
x: Math.round(bounds.x + bounds.width / 2),
|
|
1021
|
+
y: Math.round(bounds.y + bounds.height / 2)
|
|
1022
|
+
};
|
|
1023
|
+
try {
|
|
1024
|
+
const actual = this.windowsPointerDriver.moveTo(target);
|
|
1025
|
+
const drift = windowsPointerDrift(target, actual);
|
|
1026
|
+
if (!windowsPointerIsWithinTolerance(drift)) throw new Error(`Windows screenshot-space pointer verification: expected (${target.x}, ${target.y}), got (${actual.x}, ${actual.y}), drift=(${drift.x}, ${drift.y})`);
|
|
1027
|
+
} finally{
|
|
1028
|
+
this.windowsPointerDriver.moveTo(startPos);
|
|
1029
|
+
}
|
|
1030
|
+
console.log(`[HealthCheck] Mouse verified in screenshot-space display bounds (${bounds.x}, ${bounds.y}, ${bounds.width}, ${bounds.height})`);
|
|
1031
|
+
} else {
|
|
1032
|
+
const offsetX = Math.floor(40 * Math.random()) + 10;
|
|
1033
|
+
const offsetY = Math.floor(40 * Math.random()) + 10;
|
|
1034
|
+
const targetX = startPos.x + offsetX;
|
|
1035
|
+
const targetY = startPos.y + offsetY;
|
|
1036
|
+
console.log(`[HealthCheck] Moving mouse to (${targetX}, ${targetY})...`);
|
|
1037
|
+
try {
|
|
1038
|
+
this.inputDriver.moveMouse(targetX, targetY);
|
|
1039
|
+
await (0, utils_namespaceObject.sleep)(CLICK_SETTLE_DELAY);
|
|
1040
|
+
this.inputDriver.assertMousePosition(targetX, targetY, 'Mouse health check failed');
|
|
1041
|
+
} finally{
|
|
1042
|
+
this.inputDriver.moveMouse(startPos.x, startPos.y);
|
|
1043
|
+
console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
|
|
1044
|
+
}
|
|
887
1045
|
}
|
|
888
1046
|
if ('win32' === process.platform && !this.isRunningAsAdmin()) {
|
|
889
1047
|
const hint = [
|
|
@@ -893,10 +1051,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
893
1051
|
].join(' ');
|
|
894
1052
|
warnDevice(`[HealthCheck] ${hint}`);
|
|
895
1053
|
}
|
|
896
|
-
this.inputDriver.moveMouse(startPos.x, startPos.y);
|
|
897
|
-
console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
|
|
898
1054
|
console.log('[HealthCheck] Listing monitors...');
|
|
899
|
-
const displays = await ComputerDevice.listDisplays();
|
|
900
1055
|
if (displays.length > 0) {
|
|
901
1056
|
console.log(`[HealthCheck] Found ${displays.length} monitor(s):`);
|
|
902
1057
|
for (const display of displays){
|
|
@@ -1079,10 +1234,14 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
|
|
|
1079
1234
|
resolveUntargetedScrollPoint(screenSize) {
|
|
1080
1235
|
if ('win32' === process.platform) {
|
|
1081
1236
|
const activeWindowRect = this.inputDriver.getActiveWindowRect();
|
|
1082
|
-
if (activeWindowRect)
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1237
|
+
if (activeWindowRect) {
|
|
1238
|
+
const activeWindowCenter = {
|
|
1239
|
+
x: activeWindowRect.x + activeWindowRect.width / 2,
|
|
1240
|
+
y: activeWindowRect.y + activeWindowRect.height / 2
|
|
1241
|
+
};
|
|
1242
|
+
const bounds = this.displayGeometry?.bounds;
|
|
1243
|
+
if (!bounds || activeWindowCenter.x >= bounds.x && activeWindowCenter.x < bounds.x + bounds.width && activeWindowCenter.y >= bounds.y && activeWindowCenter.y < bounds.y + bounds.height) return activeWindowCenter;
|
|
1244
|
+
}
|
|
1086
1245
|
}
|
|
1087
1246
|
return this.toGlobalPoint({
|
|
1088
1247
|
x: screenSize.width / 2,
|
|
@@ -1093,17 +1252,16 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
|
|
|
1093
1252
|
if (param.locate) {
|
|
1094
1253
|
const element = param.locate;
|
|
1095
1254
|
const [x, y] = element.center;
|
|
1096
|
-
|
|
1255
|
+
await this.moveDisplayPointer({
|
|
1097
1256
|
x,
|
|
1098
1257
|
y
|
|
1099
|
-
});
|
|
1100
|
-
this.inputDriver.moveMouse(Math.round(point.x), Math.round(point.y));
|
|
1258
|
+
}, 'Mouse did not reach the scroll target');
|
|
1101
1259
|
return;
|
|
1102
1260
|
}
|
|
1103
1261
|
const screenSize = await this.size();
|
|
1104
1262
|
if ('win32' === process.platform && this.inputDriver.focusActiveWindow()) await this.inputDriver.delay(CLICK_FOCUS_SETTLE_DELAY);
|
|
1105
1263
|
const point = this.resolveUntargetedScrollPoint(screenSize);
|
|
1106
|
-
this.
|
|
1264
|
+
await this.moveGlobalPointer(point, 'Mouse did not reach the scroll viewport');
|
|
1107
1265
|
await this.inputDriver.delay(MOUSE_MOVE_EFFECT_WAIT);
|
|
1108
1266
|
return screenSize;
|
|
1109
1267
|
}
|
|
@@ -1228,6 +1386,9 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
|
|
|
1228
1386
|
runPhasedScroll,
|
|
1229
1387
|
debug: (message)=>debugDevice(message)
|
|
1230
1388
|
}));
|
|
1389
|
+
device_define_property(this, "windowsPointerDriver", new WindowsPointerDriver({
|
|
1390
|
+
runPowershell
|
|
1391
|
+
}));
|
|
1231
1392
|
device_define_property(this, "useAppleScript", void 0);
|
|
1232
1393
|
device_define_property(this, "adminCheckCache", void 0);
|
|
1233
1394
|
device_define_property(this, "uri", void 0);
|
|
@@ -1252,15 +1413,17 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
|
|
|
1252
1413
|
},
|
|
1253
1414
|
holdDuration,
|
|
1254
1415
|
displayId: this.displayId,
|
|
1255
|
-
displayGeometry: this.displayGeometry
|
|
1256
|
-
screenIndex: this.displayGeometry.screenIndex,
|
|
1257
|
-
cgDisplayId: this.displayGeometry.cgDisplayId,
|
|
1258
|
-
bounds: this.displayGeometry.bounds
|
|
1259
|
-
} : void 0
|
|
1416
|
+
displayGeometry: this.displayGeometry
|
|
1260
1417
|
});
|
|
1261
1418
|
const frontmostBefore = 'darwin' === process.platform ? readDarwinFrontmostApplication() : void 0;
|
|
1262
|
-
await this.
|
|
1263
|
-
|
|
1419
|
+
const current = await this.moveGlobalPointer({
|
|
1420
|
+
x: targetX,
|
|
1421
|
+
y: targetY
|
|
1422
|
+
}, 'Mouse did not reach the tap target', {
|
|
1423
|
+
smoothSteps: SMOOTH_MOVE_STEPS_TAP,
|
|
1424
|
+
smoothDelay: SMOOTH_MOVE_DELAY_TAP
|
|
1425
|
+
});
|
|
1426
|
+
await pressMouseAtGlobalPoint(this.inputDriver, targetX, targetY, current, holdDuration, 'primary');
|
|
1264
1427
|
if (frontmostBefore && 'darwin' === process.platform) {
|
|
1265
1428
|
await (0, utils_namespaceObject.sleep)(CLICK_FOCUS_SETTLE_DELAY);
|
|
1266
1429
|
const frontmostAfter = readDarwinFrontmostApplication();
|
|
@@ -1271,42 +1434,43 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
|
|
|
1271
1434
|
focusChanged
|
|
1272
1435
|
});
|
|
1273
1436
|
if (focusChanged) {
|
|
1274
|
-
this.
|
|
1275
|
-
|
|
1437
|
+
const followUpCurrent = await this.moveGlobalPointer({
|
|
1438
|
+
x: targetX,
|
|
1439
|
+
y: targetY
|
|
1440
|
+
}, 'Mouse did not reach the focus follow-up target');
|
|
1441
|
+
await pressMouseAtGlobalPoint(this.inputDriver, targetX, targetY, followUpCurrent, holdDuration, 'focus-follow-up');
|
|
1276
1442
|
}
|
|
1277
1443
|
}
|
|
1278
1444
|
},
|
|
1279
1445
|
doubleClick: async ({ x, y })=>{
|
|
1280
|
-
|
|
1446
|
+
await this.moveDisplayPointer({
|
|
1281
1447
|
x,
|
|
1282
1448
|
y
|
|
1283
|
-
});
|
|
1284
|
-
this.inputDriver.moveMouse(Math.round(target.x), Math.round(target.y));
|
|
1449
|
+
}, 'Mouse did not reach the double-click target');
|
|
1285
1450
|
this.inputDriver.mouseClick('left', true);
|
|
1286
1451
|
},
|
|
1287
1452
|
rightClick: async ({ x, y })=>{
|
|
1288
|
-
|
|
1453
|
+
await this.moveDisplayPointer({
|
|
1289
1454
|
x,
|
|
1290
1455
|
y
|
|
1291
|
-
});
|
|
1292
|
-
this.inputDriver.moveMouse(Math.round(target.x), Math.round(target.y));
|
|
1456
|
+
}, 'Mouse did not reach the right-click target');
|
|
1293
1457
|
this.inputDriver.mouseClick('right');
|
|
1294
1458
|
},
|
|
1295
1459
|
hover: async ({ x, y })=>{
|
|
1296
|
-
|
|
1460
|
+
await this.moveDisplayPointer({
|
|
1297
1461
|
x,
|
|
1298
1462
|
y
|
|
1463
|
+
}, 'Mouse did not reach the hover target', {
|
|
1464
|
+
smoothSteps: SMOOTH_MOVE_STEPS_MOUSE_MOVE,
|
|
1465
|
+
smoothDelay: SMOOTH_MOVE_DELAY_MOUSE_MOVE
|
|
1299
1466
|
});
|
|
1300
|
-
await this.inputDriver.smoothMoveMouse(Math.round(target.x), Math.round(target.y), SMOOTH_MOVE_STEPS_MOUSE_MOVE, SMOOTH_MOVE_DELAY_MOUSE_MOVE);
|
|
1301
1467
|
await this.inputDriver.delay(MOUSE_MOVE_EFFECT_WAIT);
|
|
1302
1468
|
},
|
|
1303
1469
|
dragAndDrop: async (from, to)=>{
|
|
1304
|
-
|
|
1305
|
-
const globalTo = this.toGlobalPoint(to);
|
|
1306
|
-
this.inputDriver.moveMouse(Math.round(globalFrom.x), Math.round(globalFrom.y));
|
|
1470
|
+
await this.moveDisplayPointer(from, 'Mouse did not reach the drag start target');
|
|
1307
1471
|
await this.inputDriver.withMouseButton('left', async ()=>{
|
|
1308
1472
|
await this.inputDriver.delay(100);
|
|
1309
|
-
this.
|
|
1473
|
+
await this.moveDisplayPointer(to, 'Mouse did not reach the drag end target');
|
|
1310
1474
|
await this.inputDriver.delay(100);
|
|
1311
1475
|
});
|
|
1312
1476
|
}
|
|
@@ -2265,7 +2429,7 @@ const tools = new ComputerMidsceneTools({
|
|
|
2265
2429
|
});
|
|
2266
2430
|
(0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-computer', {
|
|
2267
2431
|
stripPrefix: 'computer_',
|
|
2268
|
-
version: "1.12.
|
|
2432
|
+
version: "1.12.3-beta-20260828085408.0",
|
|
2269
2433
|
extraCommands: (0, core_namespaceObject.createReportCliCommands)()
|
|
2270
2434
|
}).catch((e)=>{
|
|
2271
2435
|
process.exit((0, cli_namespaceObject.reportCLIError)(e));
|