@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 CHANGED
@@ -29,6 +29,7 @@ function _define_property(obj, key, value) {
29
29
  else obj[key] = value;
30
30
  return obj;
31
31
  }
32
+ const MOUSE_COORDINATE_TOLERANCE_PX = 5;
32
33
  class ComputerInputDriver {
33
34
  destroy() {
34
35
  if (this.destroyed) return;
@@ -44,6 +45,15 @@ class ComputerInputDriver {
44
45
  moveMouse(x, y) {
45
46
  this.getLibnutOrThrow('moveMouse').moveMouse(x, y);
46
47
  }
48
+ assertMousePosition(targetX, targetY, context) {
49
+ const current = this.getMousePos();
50
+ const drift = {
51
+ x: current.x - targetX,
52
+ y: current.y - targetY
53
+ };
54
+ 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})`);
55
+ return drift;
56
+ }
47
57
  focusActiveWindow() {
48
58
  const lib = this.getLibnutOrThrow('focusActiveWindow');
49
59
  if ('function' != typeof lib.getActiveWindow || 'function' != typeof lib.focusWindow) return false;
@@ -184,6 +194,83 @@ class ComputerInputDriver {
184
194
  this.pendingInputDelayWaits = new Set();
185
195
  }
186
196
  }
197
+ function windows_pointer_define_property(obj, key, value) {
198
+ if (key in obj) Object.defineProperty(obj, key, {
199
+ value: value,
200
+ enumerable: true,
201
+ configurable: true,
202
+ writable: true
203
+ });
204
+ else obj[key] = value;
205
+ return obj;
206
+ }
207
+ const WINDOWS_POINTER_TOLERANCE_PX = 5;
208
+ function assertFinitePoint(point, context) {
209
+ if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) throw new Error(`${context} must contain finite coordinates, got (${point.x}, ${point.y})`);
210
+ }
211
+ function parseWindowsPointerPosition(output, context) {
212
+ const match = output.trim().match(/^(-?\d+),(-?\d+)$/);
213
+ if (!match) throw new Error(`${context} returned an invalid cursor position: ${JSON.stringify(output.trim())}`);
214
+ return {
215
+ x: Number(match[1]),
216
+ y: Number(match[2])
217
+ };
218
+ }
219
+ function windowsPointerPositionScript() {
220
+ return `
221
+ Add-Type -AssemblyName System.Windows.Forms, System.Drawing
222
+ $position = [System.Windows.Forms.Cursor]::Position
223
+ [Console]::Out.Write(('{0},{1}' -f $position.X, $position.Y))
224
+ `.trim();
225
+ }
226
+ function windowsPointerMoveScript(point, options) {
227
+ assertFinitePoint(point, 'Windows pointer target');
228
+ 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');
229
+ const targetX = Math.round(point.x);
230
+ const targetY = Math.round(point.y);
231
+ const smoothSteps = Math.max(1, Math.round(options?.smoothSteps ?? 1));
232
+ const smoothDelayMs = Math.max(0, Math.round(options?.smoothDelayMs ?? 0));
233
+ return `
234
+ Add-Type -AssemblyName System.Windows.Forms, System.Drawing
235
+ $targetX = ${targetX}
236
+ $targetY = ${targetY}
237
+ $smoothSteps = ${smoothSteps}
238
+ $smoothDelayMs = ${smoothDelayMs}
239
+ $start = [System.Windows.Forms.Cursor]::Position
240
+ for ($step = 1; $step -le $smoothSteps; $step += 1) {
241
+ $x = [int][Math]::Round($start.X + (($targetX - $start.X) * $step / [double]$smoothSteps))
242
+ $y = [int][Math]::Round($start.Y + (($targetY - $start.Y) * $step / [double]$smoothSteps))
243
+ [System.Windows.Forms.Cursor]::Position = [System.Drawing.Point]::new($x, $y)
244
+ if ($smoothDelayMs -gt 0 -and $step -lt $smoothSteps) {
245
+ Start-Sleep -Milliseconds $smoothDelayMs
246
+ }
247
+ }
248
+ [System.Windows.Forms.Cursor]::Position = [System.Drawing.Point]::new($targetX, $targetY)
249
+ $position = [System.Windows.Forms.Cursor]::Position
250
+ [Console]::Out.Write(('{0},{1}' -f $position.X, $position.Y))
251
+ `.trim();
252
+ }
253
+ class WindowsPointerDriver {
254
+ getPosition() {
255
+ return parseWindowsPointerPosition(this.options.runPowershell(windowsPointerPositionScript()), 'Windows pointer query');
256
+ }
257
+ moveTo(point, options) {
258
+ return parseWindowsPointerPosition(this.options.runPowershell(windowsPointerMoveScript(point, options)), 'Windows pointer move');
259
+ }
260
+ constructor(options){
261
+ windows_pointer_define_property(this, "options", void 0);
262
+ this.options = options;
263
+ }
264
+ }
265
+ function windowsPointerDrift(expected, actual) {
266
+ return {
267
+ x: actual.x - expected.x,
268
+ y: actual.y - expected.y
269
+ };
270
+ }
271
+ function windowsPointerIsWithinTolerance(drift) {
272
+ return Math.abs(drift.x) <= WINDOWS_POINTER_TOLERANCE_PX && Math.abs(drift.y) <= WINDOWS_POINTER_TOLERANCE_PX;
273
+ }
187
274
  const debugXvfb = getDebug('computer:xvfb');
188
275
  const xvfbCleanupMonitorScript = String.raw`
189
276
  const parentPid = Number(process.argv[1]);
@@ -461,19 +548,33 @@ function runPowershell(script) {
461
548
  windowsHide: true
462
549
  });
463
550
  }
464
- function listWindowsDisplays() {
551
+ function readWindowsDisplayGeometries() {
465
552
  const script = `
466
553
  Add-Type -AssemblyName System.Windows.Forms
467
554
  $s = [System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
468
- [PSCustomObject]@{ id = $_.DeviceName; name = $_.DeviceName; primary = $_.Primary }
555
+ $b = $_.Bounds
556
+ [PSCustomObject]@{
557
+ id = $_.DeviceName
558
+ name = $_.DeviceName
559
+ primary = $_.Primary
560
+ bounds = [PSCustomObject]@{ x = $b.X; y = $b.Y; width = $b.Width; height = $b.Height }
561
+ }
469
562
  }
470
563
  ConvertTo-Json @($s) -Compress
471
564
  `.trim();
472
- const parsed = JSON.parse(runPowershell(script).trim());
473
- return parsed.map((d)=>({
474
- id: String(d.id),
475
- name: d.name || String(d.id),
476
- primary: d.primary || false
565
+ const output = runPowershell(script).trim();
566
+ if (!output) throw new Error('Windows display enumeration returned no data');
567
+ const parsed = JSON.parse(output);
568
+ if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
569
+ const displays = parsed.filter(isWindowsDisplayGeometry);
570
+ if (displays.length !== parsed.length || 0 === displays.length) throw new Error('Windows display enumeration returned invalid geometry');
571
+ return displays;
572
+ }
573
+ function listWindowsDisplays(geometries = readWindowsDisplayGeometries()) {
574
+ return geometries.map((display)=>({
575
+ id: display.id,
576
+ name: display.name,
577
+ primary: display.primary
477
578
  }));
478
579
  }
479
580
  let device_libnut = null;
@@ -575,6 +676,16 @@ function getDisplayInfoBinary() {
575
676
  function isFiniteNumber(value) {
576
677
  return 'number' == typeof value && Number.isFinite(value);
577
678
  }
679
+ function isDisplayBounds(value) {
680
+ if (!value || 'object' != typeof value) return false;
681
+ const bounds = value;
682
+ return isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
683
+ }
684
+ function isWindowsDisplayGeometry(value) {
685
+ if (!value || 'object' != typeof value) return false;
686
+ const candidate = value;
687
+ return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && isDisplayBounds(candidate.bounds);
688
+ }
578
689
  function isDarwinDisplayGeometry(value) {
579
690
  if (!value || 'object' != typeof value) return false;
580
691
  const candidate = value;
@@ -617,9 +728,11 @@ function readDarwinFrontmostApplication() {
617
728
  return;
618
729
  }
619
730
  }
620
- async function pressMouseAtGlobalPoint(inputDriver, targetX, targetY, holdDuration, reason) {
621
- await inputDriver.delay(CLICK_SETTLE_DELAY);
622
- const current = inputDriver.getMousePos();
731
+ async function pressMouseAtGlobalPoint(inputDriver, targetX, targetY, current, holdDuration, reason) {
732
+ const drift = {
733
+ x: current.x - targetX,
734
+ y: current.y - targetY
735
+ };
623
736
  debugComputerInput('tap mouse moved %o', {
624
737
  reason,
625
738
  target: {
@@ -627,10 +740,7 @@ async function pressMouseAtGlobalPoint(inputDriver, targetX, targetY, holdDurati
627
740
  y: targetY
628
741
  },
629
742
  current,
630
- drift: {
631
- x: current.x - targetX,
632
- y: current.y - targetY
633
- }
743
+ drift
634
744
  });
635
745
  await inputDriver.withMouseButton('left', async ()=>{
636
746
  debugComputerInput('tap mouse down %o', {
@@ -649,9 +759,18 @@ function resolveDarwinDisplayGeometryFromList(displayId, displays) {
649
759
  if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays.find((display)=>0 === display.screenIndex) || displays[0];
650
760
  return displays.find((display)=>display.screenIndex === screenIndex) || displays.find((display)=>display.cgDisplayId === screenIndex);
651
761
  }
652
- function resolveDisplayGeometry(displayId) {
653
- if ('darwin' !== process.platform) return;
654
- return resolveDarwinDisplayGeometryFromList(displayId, readDarwinDisplayGeometries());
762
+ function resolveWindowsDisplayGeometryFromList(displayId, displays) {
763
+ if (!displays.length) return;
764
+ if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
765
+ return displays.find((display)=>display.id === displayId);
766
+ }
767
+ function resolveDisplayGeometry(displayId, windowsDisplays) {
768
+ if ('darwin' === process.platform) return resolveDarwinDisplayGeometryFromList(displayId, readDarwinDisplayGeometries());
769
+ if ('win32' === process.platform) {
770
+ const geometry = resolveWindowsDisplayGeometryFromList(displayId, windowsDisplays ?? readWindowsDisplayGeometries());
771
+ if (!geometry) throw new Error(displayId ? `Requested Windows display not found: ${displayId}` : 'No Windows displays were detected');
772
+ return geometry;
773
+ }
655
774
  }
656
775
  function mapDisplayLocalPointToGlobal(point, geometry) {
657
776
  if (!geometry) return point;
@@ -737,6 +856,30 @@ function normalizePrimaryKey(key) {
737
856
  return KEY_NAME_MAP[lowerKey] || lowerKey;
738
857
  }
739
858
  class ComputerDevice {
859
+ async moveGlobalPointer(point, context, smooth) {
860
+ if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
861
+ const target = {
862
+ x: Math.round(point.x),
863
+ y: Math.round(point.y)
864
+ };
865
+ if ('win32' === process.platform) {
866
+ const actual = this.windowsPointerDriver.moveTo(target, {
867
+ smoothSteps: smooth?.smoothSteps,
868
+ smoothDelayMs: smooth?.smoothDelay
869
+ });
870
+ const drift = windowsPointerDrift(target, actual);
871
+ if (!windowsPointerIsWithinTolerance(drift)) throw new Error(`${context}: expected (${target.x}, ${target.y}), got (${actual.x}, ${actual.y}), drift=(${drift.x}, ${drift.y})`);
872
+ await this.inputDriver.delay(CLICK_SETTLE_DELAY);
873
+ return actual;
874
+ }
875
+ if (smooth) await this.inputDriver.smoothMoveMouse(target.x, target.y, smooth.smoothSteps, smooth.smoothDelay);
876
+ else this.inputDriver.moveMouse(target.x, target.y);
877
+ await this.inputDriver.delay(CLICK_SETTLE_DELAY);
878
+ return target;
879
+ }
880
+ moveDisplayPointer(point, context, smooth) {
881
+ return this.moveGlobalPointer(this.toGlobalPoint(point), context, smooth);
882
+ }
740
883
  async focusKeyboardTarget(element, delayMs) {
741
884
  const [x, y] = element.center;
742
885
  if ('darwin' === process.platform) await this.inputPrimitives.pointer.tap({
@@ -744,11 +887,10 @@ class ComputerDevice {
744
887
  y
745
888
  });
746
889
  else {
747
- const point = this.toGlobalPoint({
890
+ await this.moveDisplayPointer({
748
891
  x,
749
892
  y
750
- });
751
- this.inputDriver.moveMouse(Math.round(point.x), Math.round(point.y));
893
+ }, 'Mouse did not reach the keyboard focus target');
752
894
  this.inputDriver.mouseClick('left');
753
895
  }
754
896
  await this.inputDriver.delay(delayMs);
@@ -767,7 +909,7 @@ class ComputerDevice {
767
909
  }));
768
910
  } catch (error) {
769
911
  debugDevice(`Failed to list displays: ${error}`);
770
- return [];
912
+ throw new Error(`Failed to list displays: ${error}`);
771
913
  }
772
914
  }
773
915
  async connect() {
@@ -796,9 +938,10 @@ class ComputerDevice {
796
938
  }
797
939
  }
798
940
  device_libnut = await getLibnut();
799
- this.displayGeometry = resolveDisplayGeometry(this.displayId);
941
+ const windowsDisplayGeometries = 'win32' === process.platform ? readWindowsDisplayGeometries() : void 0;
942
+ this.displayGeometry = resolveDisplayGeometry(this.displayId, windowsDisplayGeometries);
800
943
  const size = await this.size();
801
- const displays = await ComputerDevice.listDisplays();
944
+ const displays = windowsDisplayGeometries ? listWindowsDisplays(windowsDisplayGeometries) : await ComputerDevice.listDisplays();
802
945
  const headlessInfo = this.xvfbInstance ? `\nHeadless: true (Xvfb on ${this.xvfbInstance.display})` : '';
803
946
  this.description = `
804
947
  Type: Computer
@@ -808,7 +951,7 @@ Screen Size: ${size.width}x${size.height}
808
951
  Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ') : 'Unknown'}${headlessInfo}
809
952
  `;
810
953
  debugDevice('Computer device connected', this.description);
811
- await this.healthCheck();
954
+ await this.healthCheck(displays);
812
955
  } catch (error) {
813
956
  if (this.xvfbInstance) {
814
957
  if (!this.options?.keepXvfbAliveUntilProcessExit) this.xvfbInstance.stop();
@@ -827,9 +970,9 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
827
970
  throw new Error(`Unable to connect to computer device: ${error}`);
828
971
  }
829
972
  }
830
- async healthCheck() {
973
+ async healthCheck(displays) {
831
974
  console.log('[HealthCheck] Starting health check...');
832
- console.log("[HealthCheck] @midscene/computer v1.12.2");
975
+ console.log("[HealthCheck] @midscene/computer v1.12.3-beta-20260828085408.0");
833
976
  console.log('[HealthCheck] Taking screenshot...');
834
977
  const screenshotTimeout = 15000;
835
978
  let timeoutId;
@@ -841,23 +984,38 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
841
984
  timeoutPromise
842
985
  ]);
843
986
  console.log(`[HealthCheck] Screenshot succeeded (length=${base64.length})`);
844
- console.log('[HealthCheck] Moving mouse...');
845
- const startPos = this.inputDriver.getMousePos();
987
+ console.log('[HealthCheck] Verifying mouse control...');
988
+ const startPos = 'win32' === process.platform ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
846
989
  console.log(`[HealthCheck] Current mouse position: (${startPos.x}, ${startPos.y})`);
847
- const offsetX = Math.floor(40 * Math.random()) + 10;
848
- const offsetY = Math.floor(40 * Math.random()) + 10;
849
- const targetX = startPos.x + offsetX;
850
- const targetY = startPos.y + offsetY;
851
- console.log(`[HealthCheck] Moving mouse to (${targetX}, ${targetY})...`);
852
- this.inputDriver.moveMouse(targetX, targetY);
853
- await sleep(50);
854
- const movedPos = this.inputDriver.getMousePos();
855
- console.log(`[HealthCheck] Mouse position after move: (${movedPos.x}, ${movedPos.y})`);
856
- const deltaX = Math.abs(movedPos.x - targetX);
857
- const deltaY = Math.abs(movedPos.y - targetY);
858
- if (deltaX > 5 || deltaY > 5) {
859
- const msg = `[HealthCheck] WARNING: Mouse control may not be working. Expected (${targetX}, ${targetY}), got (${movedPos.x}, ${movedPos.y}), delta=(${deltaX}, ${deltaY})`;
860
- warnDevice(msg);
990
+ if ('win32' === process.platform) {
991
+ if (!this.displayGeometry) throw new Error('Windows display geometry is unavailable');
992
+ const bounds = this.displayGeometry.bounds;
993
+ const target = {
994
+ x: Math.round(bounds.x + bounds.width / 2),
995
+ y: Math.round(bounds.y + bounds.height / 2)
996
+ };
997
+ try {
998
+ const actual = this.windowsPointerDriver.moveTo(target);
999
+ const drift = windowsPointerDrift(target, actual);
1000
+ 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})`);
1001
+ } finally{
1002
+ this.windowsPointerDriver.moveTo(startPos);
1003
+ }
1004
+ console.log(`[HealthCheck] Mouse verified in screenshot-space display bounds (${bounds.x}, ${bounds.y}, ${bounds.width}, ${bounds.height})`);
1005
+ } else {
1006
+ const offsetX = Math.floor(40 * Math.random()) + 10;
1007
+ const offsetY = Math.floor(40 * Math.random()) + 10;
1008
+ const targetX = startPos.x + offsetX;
1009
+ const targetY = startPos.y + offsetY;
1010
+ console.log(`[HealthCheck] Moving mouse to (${targetX}, ${targetY})...`);
1011
+ try {
1012
+ this.inputDriver.moveMouse(targetX, targetY);
1013
+ await sleep(CLICK_SETTLE_DELAY);
1014
+ this.inputDriver.assertMousePosition(targetX, targetY, 'Mouse health check failed');
1015
+ } finally{
1016
+ this.inputDriver.moveMouse(startPos.x, startPos.y);
1017
+ console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
1018
+ }
861
1019
  }
862
1020
  if ('win32' === process.platform && !this.isRunningAsAdmin()) {
863
1021
  const hint = [
@@ -867,10 +1025,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
867
1025
  ].join(' ');
868
1026
  warnDevice(`[HealthCheck] ${hint}`);
869
1027
  }
870
- this.inputDriver.moveMouse(startPos.x, startPos.y);
871
- console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
872
1028
  console.log('[HealthCheck] Listing monitors...');
873
- const displays = await ComputerDevice.listDisplays();
874
1029
  if (displays.length > 0) {
875
1030
  console.log(`[HealthCheck] Found ${displays.length} monitor(s):`);
876
1031
  for (const display of displays){
@@ -1053,10 +1208,14 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1053
1208
  resolveUntargetedScrollPoint(screenSize) {
1054
1209
  if ('win32' === process.platform) {
1055
1210
  const activeWindowRect = this.inputDriver.getActiveWindowRect();
1056
- if (activeWindowRect) return {
1057
- x: activeWindowRect.x + activeWindowRect.width / 2,
1058
- y: activeWindowRect.y + activeWindowRect.height / 2
1059
- };
1211
+ if (activeWindowRect) {
1212
+ const activeWindowCenter = {
1213
+ x: activeWindowRect.x + activeWindowRect.width / 2,
1214
+ y: activeWindowRect.y + activeWindowRect.height / 2
1215
+ };
1216
+ const bounds = this.displayGeometry?.bounds;
1217
+ if (!bounds || activeWindowCenter.x >= bounds.x && activeWindowCenter.x < bounds.x + bounds.width && activeWindowCenter.y >= bounds.y && activeWindowCenter.y < bounds.y + bounds.height) return activeWindowCenter;
1218
+ }
1060
1219
  }
1061
1220
  return this.toGlobalPoint({
1062
1221
  x: screenSize.width / 2,
@@ -1067,17 +1226,16 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1067
1226
  if (param.locate) {
1068
1227
  const element = param.locate;
1069
1228
  const [x, y] = element.center;
1070
- const point = this.toGlobalPoint({
1229
+ await this.moveDisplayPointer({
1071
1230
  x,
1072
1231
  y
1073
- });
1074
- this.inputDriver.moveMouse(Math.round(point.x), Math.round(point.y));
1232
+ }, 'Mouse did not reach the scroll target');
1075
1233
  return;
1076
1234
  }
1077
1235
  const screenSize = await this.size();
1078
1236
  if ('win32' === process.platform && this.inputDriver.focusActiveWindow()) await this.inputDriver.delay(CLICK_FOCUS_SETTLE_DELAY);
1079
1237
  const point = this.resolveUntargetedScrollPoint(screenSize);
1080
- this.inputDriver.moveMouse(Math.round(point.x), Math.round(point.y));
1238
+ await this.moveGlobalPointer(point, 'Mouse did not reach the scroll viewport');
1081
1239
  await this.inputDriver.delay(MOUSE_MOVE_EFFECT_WAIT);
1082
1240
  return screenSize;
1083
1241
  }
@@ -1202,6 +1360,9 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1202
1360
  runPhasedScroll,
1203
1361
  debug: (message)=>debugDevice(message)
1204
1362
  }));
1363
+ device_define_property(this, "windowsPointerDriver", new WindowsPointerDriver({
1364
+ runPowershell
1365
+ }));
1205
1366
  device_define_property(this, "useAppleScript", void 0);
1206
1367
  device_define_property(this, "adminCheckCache", void 0);
1207
1368
  device_define_property(this, "uri", void 0);
@@ -1226,15 +1387,17 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1226
1387
  },
1227
1388
  holdDuration,
1228
1389
  displayId: this.displayId,
1229
- displayGeometry: this.displayGeometry ? {
1230
- screenIndex: this.displayGeometry.screenIndex,
1231
- cgDisplayId: this.displayGeometry.cgDisplayId,
1232
- bounds: this.displayGeometry.bounds
1233
- } : void 0
1390
+ displayGeometry: this.displayGeometry
1234
1391
  });
1235
1392
  const frontmostBefore = 'darwin' === process.platform ? readDarwinFrontmostApplication() : void 0;
1236
- await this.inputDriver.smoothMoveMouse(targetX, targetY, SMOOTH_MOVE_STEPS_TAP, SMOOTH_MOVE_DELAY_TAP);
1237
- await pressMouseAtGlobalPoint(this.inputDriver, targetX, targetY, holdDuration, 'primary');
1393
+ const current = await this.moveGlobalPointer({
1394
+ x: targetX,
1395
+ y: targetY
1396
+ }, 'Mouse did not reach the tap target', {
1397
+ smoothSteps: SMOOTH_MOVE_STEPS_TAP,
1398
+ smoothDelay: SMOOTH_MOVE_DELAY_TAP
1399
+ });
1400
+ await pressMouseAtGlobalPoint(this.inputDriver, targetX, targetY, current, holdDuration, 'primary');
1238
1401
  if (frontmostBefore && 'darwin' === process.platform) {
1239
1402
  await sleep(CLICK_FOCUS_SETTLE_DELAY);
1240
1403
  const frontmostAfter = readDarwinFrontmostApplication();
@@ -1245,42 +1408,43 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1245
1408
  focusChanged
1246
1409
  });
1247
1410
  if (focusChanged) {
1248
- this.inputDriver.moveMouse(targetX, targetY);
1249
- await pressMouseAtGlobalPoint(this.inputDriver, targetX, targetY, holdDuration, 'focus-follow-up');
1411
+ const followUpCurrent = await this.moveGlobalPointer({
1412
+ x: targetX,
1413
+ y: targetY
1414
+ }, 'Mouse did not reach the focus follow-up target');
1415
+ await pressMouseAtGlobalPoint(this.inputDriver, targetX, targetY, followUpCurrent, holdDuration, 'focus-follow-up');
1250
1416
  }
1251
1417
  }
1252
1418
  },
1253
1419
  doubleClick: async ({ x, y })=>{
1254
- const target = this.toGlobalPoint({
1420
+ await this.moveDisplayPointer({
1255
1421
  x,
1256
1422
  y
1257
- });
1258
- this.inputDriver.moveMouse(Math.round(target.x), Math.round(target.y));
1423
+ }, 'Mouse did not reach the double-click target');
1259
1424
  this.inputDriver.mouseClick('left', true);
1260
1425
  },
1261
1426
  rightClick: async ({ x, y })=>{
1262
- const target = this.toGlobalPoint({
1427
+ await this.moveDisplayPointer({
1263
1428
  x,
1264
1429
  y
1265
- });
1266
- this.inputDriver.moveMouse(Math.round(target.x), Math.round(target.y));
1430
+ }, 'Mouse did not reach the right-click target');
1267
1431
  this.inputDriver.mouseClick('right');
1268
1432
  },
1269
1433
  hover: async ({ x, y })=>{
1270
- const target = this.toGlobalPoint({
1434
+ await this.moveDisplayPointer({
1271
1435
  x,
1272
1436
  y
1437
+ }, 'Mouse did not reach the hover target', {
1438
+ smoothSteps: SMOOTH_MOVE_STEPS_MOUSE_MOVE,
1439
+ smoothDelay: SMOOTH_MOVE_DELAY_MOUSE_MOVE
1273
1440
  });
1274
- await this.inputDriver.smoothMoveMouse(Math.round(target.x), Math.round(target.y), SMOOTH_MOVE_STEPS_MOUSE_MOVE, SMOOTH_MOVE_DELAY_MOUSE_MOVE);
1275
1441
  await this.inputDriver.delay(MOUSE_MOVE_EFFECT_WAIT);
1276
1442
  },
1277
1443
  dragAndDrop: async (from, to)=>{
1278
- const globalFrom = this.toGlobalPoint(from);
1279
- const globalTo = this.toGlobalPoint(to);
1280
- this.inputDriver.moveMouse(Math.round(globalFrom.x), Math.round(globalFrom.y));
1444
+ await this.moveDisplayPointer(from, 'Mouse did not reach the drag start target');
1281
1445
  await this.inputDriver.withMouseButton('left', async ()=>{
1282
1446
  await this.inputDriver.delay(100);
1283
- this.inputDriver.moveMouse(Math.round(globalTo.x), Math.round(globalTo.y));
1447
+ await this.moveDisplayPointer(to, 'Mouse did not reach the drag end target');
1284
1448
  await this.inputDriver.delay(100);
1285
1449
  });
1286
1450
  }
@@ -2238,7 +2402,7 @@ const tools = new ComputerMidsceneTools({
2238
2402
  });
2239
2403
  runToolsCLI(tools, 'midscene-computer', {
2240
2404
  stripPrefix: 'computer_',
2241
- version: "1.12.2",
2405
+ version: "1.12.3-beta-20260828085408.0",
2242
2406
  extraCommands: createReportCliCommands()
2243
2407
  }).catch((e)=>{
2244
2408
  process.exit(reportCLIError(e));