@midscene/ios 1.9.2 → 1.9.3-beta-20260608113104.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/bin.mjs CHANGED
@@ -200,6 +200,7 @@ const debugIOS = getDebug('webdriver:ios');
200
200
  const WDA_MJPEG_SCREENSHOT_QUALITY = 50;
201
201
  const WDA_MJPEG_FRAMERATE = 30;
202
202
  const WDA_MJPEG_SCALING_FACTOR = 50;
203
+ const XCUI_KEY_MODIFIER_COMMAND = 16;
203
204
  class IOSWebDriverClient extends WebDriverClient {
204
205
  async launchApp(bundleId) {
205
206
  this.ensureSession();
@@ -398,14 +399,57 @@ class IOSWebDriverClient extends WebDriverClient {
398
399
  return false;
399
400
  }
400
401
  }
401
- async typeText(text) {
402
+ async pasteText(text) {
402
403
  this.ensureSession();
404
+ const cleanText = text.trim();
405
+ if (!cleanText) return;
403
406
  try {
404
- const cleanText = text.trim();
405
- await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
406
- value: cleanText.split('')
407
+ await this.setPasteboardText(cleanText);
408
+ await this.sendPasteShortcut();
409
+ debugIOS(`Pasted text: "${text}"`);
410
+ } catch (error) {
411
+ debugIOS(`Failed to paste text "${text}": ${error}`);
412
+ throw new Error(`Failed to paste text: ${error}`);
413
+ }
414
+ }
415
+ async setPasteboardText(text) {
416
+ this.ensureSession();
417
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/setPasteboard`, {
418
+ content: Buffer.from(text, 'utf8').toString('base64'),
419
+ contentType: 'plaintext'
420
+ });
421
+ }
422
+ async sendPasteShortcut() {
423
+ this.ensureSession();
424
+ const elementId = await this.getActiveElement() ?? '0';
425
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/element/${elementId}/keyboardInput`, {
426
+ keys: [
427
+ {
428
+ key: 'v',
429
+ modifierFlags: XCUI_KEY_MODIFIER_COMMAND
430
+ }
431
+ ]
432
+ });
433
+ }
434
+ async typeText(text, options) {
435
+ this.ensureSession();
436
+ const cleanText = text.trim();
437
+ if (!cleanText) return;
438
+ const chars = Array.from(cleanText);
439
+ const delayMs = options?.delayMs ?? 0;
440
+ try {
441
+ if (delayMs > 0) for(let i = 0; i < chars.length; i++){
442
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
443
+ value: [
444
+ chars[i]
445
+ ]
446
+ });
447
+ if (i < chars.length - 1) await sleep(delayMs);
448
+ }
449
+ else await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
450
+ value: chars
407
451
  });
408
- debugIOS(`Typed text: "${text}"`);
452
+ debugIOS(`Typed text: "${text}" (delayMs=${delayMs})`);
409
453
  } catch (error) {
410
454
  debugIOS(`Failed to type text "${text}": ${error}`);
411
455
  throw new Error(`Failed to type text: ${error}`);
@@ -868,13 +912,25 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
868
912
  async typeText(text, options) {
869
913
  if (!text) return;
870
914
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
871
- debugDevice(`Typing text: "${text}"`);
915
+ const delayMs = options?.keyboardTypeDelay ?? this.options?.keyboardTypeDelay ?? 80;
916
+ const keyboardInputStrategy = options?.keyboardInputStrategy ?? this.options?.keyboardInputStrategy ?? 'paste';
917
+ debugDevice(`Input text: "${text}" (strategy=${keyboardInputStrategy}, delayMs=${delayMs})`);
872
918
  try {
873
919
  await sleep(200);
874
- await this.wdaBackend.typeText(text);
920
+ if ('type' === keyboardInputStrategy) await this.wdaBackend.typeText(text, {
921
+ delayMs
922
+ });
923
+ else try {
924
+ await this.wdaBackend.pasteText(text);
925
+ } catch (pasteError) {
926
+ debugDevice(`Failed to paste text with WDA, falling back to typing: ${pasteError}`);
927
+ await this.wdaBackend.typeText(text, {
928
+ delayMs
929
+ });
930
+ }
875
931
  await sleep(300);
876
932
  } catch (error) {
877
- debugDevice(`Failed to type text with WDA: ${error}`);
933
+ debugDevice(`Failed to input text with WDA: ${error}`);
878
934
  throw error;
879
935
  }
880
936
  if (shouldAutoDismissKeyboard) await this.hideKeyboard();
package/dist/es/cli.mjs CHANGED
@@ -199,6 +199,7 @@ const debugIOS = getDebug('webdriver:ios');
199
199
  const WDA_MJPEG_SCREENSHOT_QUALITY = 50;
200
200
  const WDA_MJPEG_FRAMERATE = 30;
201
201
  const WDA_MJPEG_SCALING_FACTOR = 50;
202
+ const XCUI_KEY_MODIFIER_COMMAND = 16;
202
203
  class IOSWebDriverClient extends WebDriverClient {
203
204
  async launchApp(bundleId) {
204
205
  this.ensureSession();
@@ -397,14 +398,57 @@ class IOSWebDriverClient extends WebDriverClient {
397
398
  return false;
398
399
  }
399
400
  }
400
- async typeText(text) {
401
+ async pasteText(text) {
401
402
  this.ensureSession();
403
+ const cleanText = text.trim();
404
+ if (!cleanText) return;
402
405
  try {
403
- const cleanText = text.trim();
404
- await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
405
- value: cleanText.split('')
406
+ await this.setPasteboardText(cleanText);
407
+ await this.sendPasteShortcut();
408
+ debugIOS(`Pasted text: "${text}"`);
409
+ } catch (error) {
410
+ debugIOS(`Failed to paste text "${text}": ${error}`);
411
+ throw new Error(`Failed to paste text: ${error}`);
412
+ }
413
+ }
414
+ async setPasteboardText(text) {
415
+ this.ensureSession();
416
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/setPasteboard`, {
417
+ content: Buffer.from(text, 'utf8').toString('base64'),
418
+ contentType: 'plaintext'
419
+ });
420
+ }
421
+ async sendPasteShortcut() {
422
+ this.ensureSession();
423
+ const elementId = await this.getActiveElement() ?? '0';
424
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/element/${elementId}/keyboardInput`, {
425
+ keys: [
426
+ {
427
+ key: 'v',
428
+ modifierFlags: XCUI_KEY_MODIFIER_COMMAND
429
+ }
430
+ ]
431
+ });
432
+ }
433
+ async typeText(text, options) {
434
+ this.ensureSession();
435
+ const cleanText = text.trim();
436
+ if (!cleanText) return;
437
+ const chars = Array.from(cleanText);
438
+ const delayMs = options?.delayMs ?? 0;
439
+ try {
440
+ if (delayMs > 0) for(let i = 0; i < chars.length; i++){
441
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
442
+ value: [
443
+ chars[i]
444
+ ]
445
+ });
446
+ if (i < chars.length - 1) await sleep(delayMs);
447
+ }
448
+ else await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
449
+ value: chars
406
450
  });
407
- debugIOS(`Typed text: "${text}"`);
451
+ debugIOS(`Typed text: "${text}" (delayMs=${delayMs})`);
408
452
  } catch (error) {
409
453
  debugIOS(`Failed to type text "${text}": ${error}`);
410
454
  throw new Error(`Failed to type text: ${error}`);
@@ -867,13 +911,25 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
867
911
  async typeText(text, options) {
868
912
  if (!text) return;
869
913
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
870
- debugDevice(`Typing text: "${text}"`);
914
+ const delayMs = options?.keyboardTypeDelay ?? this.options?.keyboardTypeDelay ?? 80;
915
+ const keyboardInputStrategy = options?.keyboardInputStrategy ?? this.options?.keyboardInputStrategy ?? 'paste';
916
+ debugDevice(`Input text: "${text}" (strategy=${keyboardInputStrategy}, delayMs=${delayMs})`);
871
917
  try {
872
918
  await sleep(200);
873
- await this.wdaBackend.typeText(text);
919
+ if ('type' === keyboardInputStrategy) await this.wdaBackend.typeText(text, {
920
+ delayMs
921
+ });
922
+ else try {
923
+ await this.wdaBackend.pasteText(text);
924
+ } catch (pasteError) {
925
+ debugDevice(`Failed to paste text with WDA, falling back to typing: ${pasteError}`);
926
+ await this.wdaBackend.typeText(text, {
927
+ delayMs
928
+ });
929
+ }
874
930
  await sleep(300);
875
931
  } catch (error) {
876
- debugDevice(`Failed to type text with WDA: ${error}`);
932
+ debugDevice(`Failed to input text with WDA: ${error}`);
877
933
  throw error;
878
934
  }
879
935
  if (shouldAutoDismissKeyboard) await this.hideKeyboard();
@@ -1453,7 +1509,7 @@ class IOSMidsceneTools extends BaseMidsceneTools {
1453
1509
  const tools = new IOSMidsceneTools();
1454
1510
  runToolsCLI(tools, 'midscene-ios', {
1455
1511
  stripPrefix: 'ios_',
1456
- version: "1.9.2",
1512
+ version: "1.9.3-beta-20260608113104.0",
1457
1513
  extraCommands: createReportCliCommands()
1458
1514
  }).catch((e)=>{
1459
1515
  process.exit(reportCLIError(e));
package/dist/es/index.mjs CHANGED
@@ -20,6 +20,7 @@ const debugIOS = getDebug('webdriver:ios');
20
20
  const WDA_MJPEG_SCREENSHOT_QUALITY = 50;
21
21
  const WDA_MJPEG_FRAMERATE = 30;
22
22
  const WDA_MJPEG_SCALING_FACTOR = 50;
23
+ const XCUI_KEY_MODIFIER_COMMAND = 16;
23
24
  class IOSWebDriverClient extends WebDriverClient {
24
25
  async launchApp(bundleId) {
25
26
  this.ensureSession();
@@ -218,14 +219,57 @@ class IOSWebDriverClient extends WebDriverClient {
218
219
  return false;
219
220
  }
220
221
  }
221
- async typeText(text) {
222
+ async pasteText(text) {
222
223
  this.ensureSession();
224
+ const cleanText = text.trim();
225
+ if (!cleanText) return;
223
226
  try {
224
- const cleanText = text.trim();
225
- await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
226
- value: cleanText.split('')
227
+ await this.setPasteboardText(cleanText);
228
+ await this.sendPasteShortcut();
229
+ debugIOS(`Pasted text: "${text}"`);
230
+ } catch (error) {
231
+ debugIOS(`Failed to paste text "${text}": ${error}`);
232
+ throw new Error(`Failed to paste text: ${error}`);
233
+ }
234
+ }
235
+ async setPasteboardText(text) {
236
+ this.ensureSession();
237
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/setPasteboard`, {
238
+ content: Buffer.from(text, 'utf8').toString('base64'),
239
+ contentType: 'plaintext'
240
+ });
241
+ }
242
+ async sendPasteShortcut() {
243
+ this.ensureSession();
244
+ const elementId = await this.getActiveElement() ?? '0';
245
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/element/${elementId}/keyboardInput`, {
246
+ keys: [
247
+ {
248
+ key: 'v',
249
+ modifierFlags: XCUI_KEY_MODIFIER_COMMAND
250
+ }
251
+ ]
252
+ });
253
+ }
254
+ async typeText(text, options) {
255
+ this.ensureSession();
256
+ const cleanText = text.trim();
257
+ if (!cleanText) return;
258
+ const chars = Array.from(cleanText);
259
+ const delayMs = options?.delayMs ?? 0;
260
+ try {
261
+ if (delayMs > 0) for(let i = 0; i < chars.length; i++){
262
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
263
+ value: [
264
+ chars[i]
265
+ ]
266
+ });
267
+ if (i < chars.length - 1) await sleep(delayMs);
268
+ }
269
+ else await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
270
+ value: chars
227
271
  });
228
- debugIOS(`Typed text: "${text}"`);
272
+ debugIOS(`Typed text: "${text}" (delayMs=${delayMs})`);
229
273
  } catch (error) {
230
274
  debugIOS(`Failed to type text "${text}": ${error}`);
231
275
  throw new Error(`Failed to type text: ${error}`);
@@ -688,13 +732,25 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
688
732
  async typeText(text, options) {
689
733
  if (!text) return;
690
734
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
691
- debugDevice(`Typing text: "${text}"`);
735
+ const delayMs = options?.keyboardTypeDelay ?? this.options?.keyboardTypeDelay ?? 80;
736
+ const keyboardInputStrategy = options?.keyboardInputStrategy ?? this.options?.keyboardInputStrategy ?? 'paste';
737
+ debugDevice(`Input text: "${text}" (strategy=${keyboardInputStrategy}, delayMs=${delayMs})`);
692
738
  try {
693
739
  await sleep(200);
694
- await this.wdaBackend.typeText(text);
740
+ if ('type' === keyboardInputStrategy) await this.wdaBackend.typeText(text, {
741
+ delayMs
742
+ });
743
+ else try {
744
+ await this.wdaBackend.pasteText(text);
745
+ } catch (pasteError) {
746
+ debugDevice(`Failed to paste text with WDA, falling back to typing: ${pasteError}`);
747
+ await this.wdaBackend.typeText(text, {
748
+ delayMs
749
+ });
750
+ }
695
751
  await sleep(300);
696
752
  } catch (error) {
697
- debugDevice(`Failed to type text with WDA: ${error}`);
753
+ debugDevice(`Failed to input text with WDA: ${error}`);
698
754
  throw error;
699
755
  }
700
756
  if (shouldAutoDismissKeyboard) await this.hideKeyboard();
@@ -199,6 +199,7 @@ const debugIOS = getDebug('webdriver:ios');
199
199
  const WDA_MJPEG_SCREENSHOT_QUALITY = 50;
200
200
  const WDA_MJPEG_FRAMERATE = 30;
201
201
  const WDA_MJPEG_SCALING_FACTOR = 50;
202
+ const XCUI_KEY_MODIFIER_COMMAND = 16;
202
203
  class IOSWebDriverClient extends WebDriverClient {
203
204
  async launchApp(bundleId) {
204
205
  this.ensureSession();
@@ -397,14 +398,57 @@ class IOSWebDriverClient extends WebDriverClient {
397
398
  return false;
398
399
  }
399
400
  }
400
- async typeText(text) {
401
+ async pasteText(text) {
401
402
  this.ensureSession();
403
+ const cleanText = text.trim();
404
+ if (!cleanText) return;
402
405
  try {
403
- const cleanText = text.trim();
404
- await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
405
- value: cleanText.split('')
406
+ await this.setPasteboardText(cleanText);
407
+ await this.sendPasteShortcut();
408
+ debugIOS(`Pasted text: "${text}"`);
409
+ } catch (error) {
410
+ debugIOS(`Failed to paste text "${text}": ${error}`);
411
+ throw new Error(`Failed to paste text: ${error}`);
412
+ }
413
+ }
414
+ async setPasteboardText(text) {
415
+ this.ensureSession();
416
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/setPasteboard`, {
417
+ content: Buffer.from(text, 'utf8').toString('base64'),
418
+ contentType: 'plaintext'
419
+ });
420
+ }
421
+ async sendPasteShortcut() {
422
+ this.ensureSession();
423
+ const elementId = await this.getActiveElement() ?? '0';
424
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/element/${elementId}/keyboardInput`, {
425
+ keys: [
426
+ {
427
+ key: 'v',
428
+ modifierFlags: XCUI_KEY_MODIFIER_COMMAND
429
+ }
430
+ ]
431
+ });
432
+ }
433
+ async typeText(text, options) {
434
+ this.ensureSession();
435
+ const cleanText = text.trim();
436
+ if (!cleanText) return;
437
+ const chars = Array.from(cleanText);
438
+ const delayMs = options?.delayMs ?? 0;
439
+ try {
440
+ if (delayMs > 0) for(let i = 0; i < chars.length; i++){
441
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
442
+ value: [
443
+ chars[i]
444
+ ]
445
+ });
446
+ if (i < chars.length - 1) await sleep(delayMs);
447
+ }
448
+ else await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
449
+ value: chars
406
450
  });
407
- debugIOS(`Typed text: "${text}"`);
451
+ debugIOS(`Typed text: "${text}" (delayMs=${delayMs})`);
408
452
  } catch (error) {
409
453
  debugIOS(`Failed to type text "${text}": ${error}`);
410
454
  throw new Error(`Failed to type text: ${error}`);
@@ -867,13 +911,25 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
867
911
  async typeText(text, options) {
868
912
  if (!text) return;
869
913
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
870
- debugDevice(`Typing text: "${text}"`);
914
+ const delayMs = options?.keyboardTypeDelay ?? this.options?.keyboardTypeDelay ?? 80;
915
+ const keyboardInputStrategy = options?.keyboardInputStrategy ?? this.options?.keyboardInputStrategy ?? 'paste';
916
+ debugDevice(`Input text: "${text}" (strategy=${keyboardInputStrategy}, delayMs=${delayMs})`);
871
917
  try {
872
918
  await sleep(200);
873
- await this.wdaBackend.typeText(text);
919
+ if ('type' === keyboardInputStrategy) await this.wdaBackend.typeText(text, {
920
+ delayMs
921
+ });
922
+ else try {
923
+ await this.wdaBackend.pasteText(text);
924
+ } catch (pasteError) {
925
+ debugDevice(`Failed to paste text with WDA, falling back to typing: ${pasteError}`);
926
+ await this.wdaBackend.typeText(text, {
927
+ delayMs
928
+ });
929
+ }
874
930
  await sleep(300);
875
931
  } catch (error) {
876
- debugDevice(`Failed to type text with WDA: ${error}`);
932
+ debugDevice(`Failed to input text with WDA: ${error}`);
877
933
  throw error;
878
934
  }
879
935
  if (shouldAutoDismissKeyboard) await this.hideKeyboard();
@@ -1457,7 +1513,7 @@ class IOSMCPServer extends BaseMCPServer {
1457
1513
  constructor(toolsManager){
1458
1514
  super({
1459
1515
  name: '@midscene/ios-mcp',
1460
- version: "1.9.2",
1516
+ version: "1.9.3-beta-20260608113104.0",
1461
1517
  description: 'Control the iOS device using natural language commands'
1462
1518
  }, toolsManager);
1463
1519
  }
package/dist/lib/bin.js CHANGED
@@ -225,6 +225,7 @@ const debugIOS = (0, logger_namespaceObject.getDebug)('webdriver:ios');
225
225
  const WDA_MJPEG_SCREENSHOT_QUALITY = 50;
226
226
  const WDA_MJPEG_FRAMERATE = 30;
227
227
  const WDA_MJPEG_SCALING_FACTOR = 50;
228
+ const XCUI_KEY_MODIFIER_COMMAND = 16;
228
229
  class IOSWebDriverClient extends webdriver_namespaceObject.WebDriverClient {
229
230
  async launchApp(bundleId) {
230
231
  this.ensureSession();
@@ -423,14 +424,57 @@ class IOSWebDriverClient extends webdriver_namespaceObject.WebDriverClient {
423
424
  return false;
424
425
  }
425
426
  }
426
- async typeText(text) {
427
+ async pasteText(text) {
427
428
  this.ensureSession();
429
+ const cleanText = text.trim();
430
+ if (!cleanText) return;
428
431
  try {
429
- const cleanText = text.trim();
430
- await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
431
- value: cleanText.split('')
432
+ await this.setPasteboardText(cleanText);
433
+ await this.sendPasteShortcut();
434
+ debugIOS(`Pasted text: "${text}"`);
435
+ } catch (error) {
436
+ debugIOS(`Failed to paste text "${text}": ${error}`);
437
+ throw new Error(`Failed to paste text: ${error}`);
438
+ }
439
+ }
440
+ async setPasteboardText(text) {
441
+ this.ensureSession();
442
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/setPasteboard`, {
443
+ content: Buffer.from(text, 'utf8').toString('base64'),
444
+ contentType: 'plaintext'
445
+ });
446
+ }
447
+ async sendPasteShortcut() {
448
+ this.ensureSession();
449
+ const elementId = await this.getActiveElement() ?? '0';
450
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/element/${elementId}/keyboardInput`, {
451
+ keys: [
452
+ {
453
+ key: 'v',
454
+ modifierFlags: XCUI_KEY_MODIFIER_COMMAND
455
+ }
456
+ ]
457
+ });
458
+ }
459
+ async typeText(text, options) {
460
+ this.ensureSession();
461
+ const cleanText = text.trim();
462
+ if (!cleanText) return;
463
+ const chars = Array.from(cleanText);
464
+ const delayMs = options?.delayMs ?? 0;
465
+ try {
466
+ if (delayMs > 0) for(let i = 0; i < chars.length; i++){
467
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
468
+ value: [
469
+ chars[i]
470
+ ]
471
+ });
472
+ if (i < chars.length - 1) await (0, core_utils_namespaceObject.sleep)(delayMs);
473
+ }
474
+ else await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
475
+ value: chars
432
476
  });
433
- debugIOS(`Typed text: "${text}"`);
477
+ debugIOS(`Typed text: "${text}" (delayMs=${delayMs})`);
434
478
  } catch (error) {
435
479
  debugIOS(`Failed to type text "${text}": ${error}`);
436
480
  throw new Error(`Failed to type text: ${error}`);
@@ -893,13 +937,25 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
893
937
  async typeText(text, options) {
894
938
  if (!text) return;
895
939
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
896
- debugDevice(`Typing text: "${text}"`);
940
+ const delayMs = options?.keyboardTypeDelay ?? this.options?.keyboardTypeDelay ?? 80;
941
+ const keyboardInputStrategy = options?.keyboardInputStrategy ?? this.options?.keyboardInputStrategy ?? 'paste';
942
+ debugDevice(`Input text: "${text}" (strategy=${keyboardInputStrategy}, delayMs=${delayMs})`);
897
943
  try {
898
944
  await (0, core_utils_namespaceObject.sleep)(200);
899
- await this.wdaBackend.typeText(text);
945
+ if ('type' === keyboardInputStrategy) await this.wdaBackend.typeText(text, {
946
+ delayMs
947
+ });
948
+ else try {
949
+ await this.wdaBackend.pasteText(text);
950
+ } catch (pasteError) {
951
+ debugDevice(`Failed to paste text with WDA, falling back to typing: ${pasteError}`);
952
+ await this.wdaBackend.typeText(text, {
953
+ delayMs
954
+ });
955
+ }
900
956
  await (0, core_utils_namespaceObject.sleep)(300);
901
957
  } catch (error) {
902
- debugDevice(`Failed to type text with WDA: ${error}`);
958
+ debugDevice(`Failed to input text with WDA: ${error}`);
903
959
  throw error;
904
960
  }
905
961
  if (shouldAutoDismissKeyboard) await this.hideKeyboard();
package/dist/lib/cli.js CHANGED
@@ -223,6 +223,7 @@ const debugIOS = (0, logger_namespaceObject.getDebug)('webdriver:ios');
223
223
  const WDA_MJPEG_SCREENSHOT_QUALITY = 50;
224
224
  const WDA_MJPEG_FRAMERATE = 30;
225
225
  const WDA_MJPEG_SCALING_FACTOR = 50;
226
+ const XCUI_KEY_MODIFIER_COMMAND = 16;
226
227
  class IOSWebDriverClient extends webdriver_namespaceObject.WebDriverClient {
227
228
  async launchApp(bundleId) {
228
229
  this.ensureSession();
@@ -421,14 +422,57 @@ class IOSWebDriverClient extends webdriver_namespaceObject.WebDriverClient {
421
422
  return false;
422
423
  }
423
424
  }
424
- async typeText(text) {
425
+ async pasteText(text) {
425
426
  this.ensureSession();
427
+ const cleanText = text.trim();
428
+ if (!cleanText) return;
426
429
  try {
427
- const cleanText = text.trim();
428
- await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
429
- value: cleanText.split('')
430
+ await this.setPasteboardText(cleanText);
431
+ await this.sendPasteShortcut();
432
+ debugIOS(`Pasted text: "${text}"`);
433
+ } catch (error) {
434
+ debugIOS(`Failed to paste text "${text}": ${error}`);
435
+ throw new Error(`Failed to paste text: ${error}`);
436
+ }
437
+ }
438
+ async setPasteboardText(text) {
439
+ this.ensureSession();
440
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/setPasteboard`, {
441
+ content: Buffer.from(text, 'utf8').toString('base64'),
442
+ contentType: 'plaintext'
443
+ });
444
+ }
445
+ async sendPasteShortcut() {
446
+ this.ensureSession();
447
+ const elementId = await this.getActiveElement() ?? '0';
448
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/element/${elementId}/keyboardInput`, {
449
+ keys: [
450
+ {
451
+ key: 'v',
452
+ modifierFlags: XCUI_KEY_MODIFIER_COMMAND
453
+ }
454
+ ]
455
+ });
456
+ }
457
+ async typeText(text, options) {
458
+ this.ensureSession();
459
+ const cleanText = text.trim();
460
+ if (!cleanText) return;
461
+ const chars = Array.from(cleanText);
462
+ const delayMs = options?.delayMs ?? 0;
463
+ try {
464
+ if (delayMs > 0) for(let i = 0; i < chars.length; i++){
465
+ await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
466
+ value: [
467
+ chars[i]
468
+ ]
469
+ });
470
+ if (i < chars.length - 1) await (0, core_utils_namespaceObject.sleep)(delayMs);
471
+ }
472
+ else await this.makeRequest('POST', `/session/${this.sessionId}/wda/keys`, {
473
+ value: chars
430
474
  });
431
- debugIOS(`Typed text: "${text}"`);
475
+ debugIOS(`Typed text: "${text}" (delayMs=${delayMs})`);
432
476
  } catch (error) {
433
477
  debugIOS(`Failed to type text "${text}": ${error}`);
434
478
  throw new Error(`Failed to type text: ${error}`);
@@ -891,13 +935,25 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
891
935
  async typeText(text, options) {
892
936
  if (!text) return;
893
937
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
894
- debugDevice(`Typing text: "${text}"`);
938
+ const delayMs = options?.keyboardTypeDelay ?? this.options?.keyboardTypeDelay ?? 80;
939
+ const keyboardInputStrategy = options?.keyboardInputStrategy ?? this.options?.keyboardInputStrategy ?? 'paste';
940
+ debugDevice(`Input text: "${text}" (strategy=${keyboardInputStrategy}, delayMs=${delayMs})`);
895
941
  try {
896
942
  await (0, core_utils_namespaceObject.sleep)(200);
897
- await this.wdaBackend.typeText(text);
943
+ if ('type' === keyboardInputStrategy) await this.wdaBackend.typeText(text, {
944
+ delayMs
945
+ });
946
+ else try {
947
+ await this.wdaBackend.pasteText(text);
948
+ } catch (pasteError) {
949
+ debugDevice(`Failed to paste text with WDA, falling back to typing: ${pasteError}`);
950
+ await this.wdaBackend.typeText(text, {
951
+ delayMs
952
+ });
953
+ }
898
954
  await (0, core_utils_namespaceObject.sleep)(300);
899
955
  } catch (error) {
900
- debugDevice(`Failed to type text with WDA: ${error}`);
956
+ debugDevice(`Failed to input text with WDA: ${error}`);
901
957
  throw error;
902
958
  }
903
959
  if (shouldAutoDismissKeyboard) await this.hideKeyboard();
@@ -1477,7 +1533,7 @@ class IOSMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools {
1477
1533
  const tools = new IOSMidsceneTools();
1478
1534
  (0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-ios', {
1479
1535
  stripPrefix: 'ios_',
1480
- version: "1.9.2",
1536
+ version: "1.9.3-beta-20260608113104.0",
1481
1537
  extraCommands: (0, core_namespaceObject.createReportCliCommands)()
1482
1538
  }).catch((e)=>{
1483
1539
  process.exit((0, cli_namespaceObject.reportCLIError)(e));