@midscene/android 1.3.11 → 1.3.12-beta-20260211105759.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.mjs CHANGED
@@ -556,7 +556,7 @@ const IME_STRATEGY_ALWAYS_YADB = 'always-yadb';
556
556
  const IME_STRATEGY_YADB_FOR_NON_ASCII = 'yadb-for-non-ascii';
557
557
  const debugDevice = (0, logger_.getDebug)('android:device');
558
558
  function escapeForShell(text) {
559
- return text.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/`/g, '\\`').replace(/\$/g, '\\$').replace(/\n/g, '\\n');
559
+ return text.replace(/'/g, "'\\''").replace(/\n/g, '\\n');
560
560
  }
561
561
  class AndroidDevice {
562
562
  actionSpace() {
@@ -827,7 +827,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
827
827
  async execYadb(keyboardContent) {
828
828
  await this.ensureYadb();
829
829
  const adb = await this.getAdb();
830
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
830
+ await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard '${keyboardContent}'`);
831
831
  }
832
832
  async getElementsInfo() {
833
833
  return [];
@@ -1275,17 +1275,24 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1275
1275
  shouldUseYadbForText(text) {
1276
1276
  const hasNonAscii = /[\x80-\uFFFF]/.test(text);
1277
1277
  const hasFormatSpecifiers = /%[a-zA-Z]/.test(text);
1278
- return hasNonAscii || hasFormatSpecifiers;
1278
+ const hasShellSpecialChars = /[\\`$]/.test(text);
1279
+ const hasBothQuotes = text.includes('"') && text.includes("'");
1280
+ return hasNonAscii || hasFormatSpecifiers || hasShellSpecialChars || hasBothQuotes;
1279
1281
  }
1280
1282
  async keyboardType(text, options) {
1281
1283
  if (!text) return;
1282
1284
  const adb = await this.getAdb();
1283
- const shouldUseYadb = this.shouldUseYadbForText(text);
1284
1285
  const IME_STRATEGY = (this.options?.imeStrategy || globalConfigManager.getEnvConfigValue(MIDSCENE_ANDROID_IME_STRATEGY)) ?? IME_STRATEGY_YADB_FOR_NON_ASCII;
1285
1286
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
1286
- const escapedText = escapeForShell(text);
1287
- if (IME_STRATEGY === IME_STRATEGY_ALWAYS_YADB || IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII && shouldUseYadb) await this.execYadb(escapedText);
1288
- else await adb.inputText(escapedText);
1287
+ const useYadb = IME_STRATEGY === IME_STRATEGY_ALWAYS_YADB || IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII && this.shouldUseYadbForText(text);
1288
+ if (useYadb) await this.execYadb(escapeForShell(text));
1289
+ else {
1290
+ const segments = text.split('\n');
1291
+ for(let i = 0; i < segments.length; i++){
1292
+ if (segments[i].length > 0) await adb.inputText(segments[i]);
1293
+ if (i < segments.length - 1) await adb.keyevent(66);
1294
+ }
1295
+ }
1289
1296
  if (true === shouldAutoDismissKeyboard) await this.hideKeyboard(options);
1290
1297
  }
1291
1298
  normalizeKeyName(key) {
@@ -653,7 +653,7 @@ const IME_STRATEGY_ALWAYS_YADB = 'always-yadb';
653
653
  const IME_STRATEGY_YADB_FOR_NON_ASCII = 'yadb-for-non-ascii';
654
654
  const debugDevice = (0, logger_.getDebug)('android:device');
655
655
  function escapeForShell(text) {
656
- return text.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/`/g, '\\`').replace(/\$/g, '\\$').replace(/\n/g, '\\n');
656
+ return text.replace(/'/g, "'\\''").replace(/\n/g, '\\n');
657
657
  }
658
658
  class AndroidDevice {
659
659
  actionSpace() {
@@ -924,7 +924,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
924
924
  async execYadb(keyboardContent) {
925
925
  await this.ensureYadb();
926
926
  const adb = await this.getAdb();
927
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
927
+ await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard '${keyboardContent}'`);
928
928
  }
929
929
  async getElementsInfo() {
930
930
  return [];
@@ -1372,17 +1372,24 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1372
1372
  shouldUseYadbForText(text) {
1373
1373
  const hasNonAscii = /[\x80-\uFFFF]/.test(text);
1374
1374
  const hasFormatSpecifiers = /%[a-zA-Z]/.test(text);
1375
- return hasNonAscii || hasFormatSpecifiers;
1375
+ const hasShellSpecialChars = /[\\`$]/.test(text);
1376
+ const hasBothQuotes = text.includes('"') && text.includes("'");
1377
+ return hasNonAscii || hasFormatSpecifiers || hasShellSpecialChars || hasBothQuotes;
1376
1378
  }
1377
1379
  async keyboardType(text, options) {
1378
1380
  if (!text) return;
1379
1381
  const adb = await this.getAdb();
1380
- const shouldUseYadb = this.shouldUseYadbForText(text);
1381
1382
  const IME_STRATEGY = (this.options?.imeStrategy || globalConfigManager.getEnvConfigValue(MIDSCENE_ANDROID_IME_STRATEGY)) ?? IME_STRATEGY_YADB_FOR_NON_ASCII;
1382
1383
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
1383
- const escapedText = escapeForShell(text);
1384
- if (IME_STRATEGY === IME_STRATEGY_ALWAYS_YADB || IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII && shouldUseYadb) await this.execYadb(escapedText);
1385
- else await adb.inputText(escapedText);
1384
+ const useYadb = IME_STRATEGY === IME_STRATEGY_ALWAYS_YADB || IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII && this.shouldUseYadbForText(text);
1385
+ if (useYadb) await this.execYadb(escapeForShell(text));
1386
+ else {
1387
+ const segments = text.split('\n');
1388
+ for(let i = 0; i < segments.length; i++){
1389
+ if (segments[i].length > 0) await adb.inputText(segments[i]);
1390
+ if (i < segments.length - 1) await adb.keyevent(66);
1391
+ }
1392
+ }
1386
1393
  if (true === shouldAutoDismissKeyboard) await this.hideKeyboard(options);
1387
1394
  }
1388
1395
  normalizeKeyName(key) {
package/dist/lib/index.js CHANGED
@@ -589,7 +589,7 @@ var __webpack_exports__ = {};
589
589
  const IME_STRATEGY_YADB_FOR_NON_ASCII = 'yadb-for-non-ascii';
590
590
  const debugDevice = (0, logger_.getDebug)('android:device');
591
591
  function escapeForShell(text) {
592
- return text.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/`/g, '\\`').replace(/\$/g, '\\$').replace(/\n/g, '\\n');
592
+ return text.replace(/'/g, "'\\''").replace(/\n/g, '\\n');
593
593
  }
594
594
  class AndroidDevice {
595
595
  actionSpace() {
@@ -860,7 +860,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
860
860
  async execYadb(keyboardContent) {
861
861
  await this.ensureYadb();
862
862
  const adb = await this.getAdb();
863
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
863
+ await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard '${keyboardContent}'`);
864
864
  }
865
865
  async getElementsInfo() {
866
866
  return [];
@@ -1308,17 +1308,24 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1308
1308
  shouldUseYadbForText(text) {
1309
1309
  const hasNonAscii = /[\x80-\uFFFF]/.test(text);
1310
1310
  const hasFormatSpecifiers = /%[a-zA-Z]/.test(text);
1311
- return hasNonAscii || hasFormatSpecifiers;
1311
+ const hasShellSpecialChars = /[\\`$]/.test(text);
1312
+ const hasBothQuotes = text.includes('"') && text.includes("'");
1313
+ return hasNonAscii || hasFormatSpecifiers || hasShellSpecialChars || hasBothQuotes;
1312
1314
  }
1313
1315
  async keyboardType(text, options) {
1314
1316
  if (!text) return;
1315
1317
  const adb = await this.getAdb();
1316
- const shouldUseYadb = this.shouldUseYadbForText(text);
1317
1318
  const IME_STRATEGY = (this.options?.imeStrategy || env_namespaceObject.globalConfigManager.getEnvConfigValue(env_namespaceObject.MIDSCENE_ANDROID_IME_STRATEGY)) ?? IME_STRATEGY_YADB_FOR_NON_ASCII;
1318
1319
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
1319
- const escapedText = escapeForShell(text);
1320
- if (IME_STRATEGY === IME_STRATEGY_ALWAYS_YADB || IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII && shouldUseYadb) await this.execYadb(escapedText);
1321
- else await adb.inputText(escapedText);
1320
+ const useYadb = IME_STRATEGY === IME_STRATEGY_ALWAYS_YADB || IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII && this.shouldUseYadbForText(text);
1321
+ if (useYadb) await this.execYadb(escapeForShell(text));
1322
+ else {
1323
+ const segments = text.split('\n');
1324
+ for(let i = 0; i < segments.length; i++){
1325
+ if (segments[i].length > 0) await adb.inputText(segments[i]);
1326
+ if (i < segments.length - 1) await adb.keyevent(66);
1327
+ }
1328
+ }
1322
1329
  if (true === shouldAutoDismissKeyboard) await this.hideKeyboard(options);
1323
1330
  }
1324
1331
  normalizeKeyName(key) {
@@ -684,7 +684,7 @@ var __webpack_exports__ = {};
684
684
  const IME_STRATEGY_YADB_FOR_NON_ASCII = 'yadb-for-non-ascii';
685
685
  const debugDevice = (0, logger_.getDebug)('android:device');
686
686
  function escapeForShell(text) {
687
- return text.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/`/g, '\\`').replace(/\$/g, '\\$').replace(/\n/g, '\\n');
687
+ return text.replace(/'/g, "'\\''").replace(/\n/g, '\\n');
688
688
  }
689
689
  class AndroidDevice {
690
690
  actionSpace() {
@@ -955,7 +955,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
955
955
  async execYadb(keyboardContent) {
956
956
  await this.ensureYadb();
957
957
  const adb = await this.getAdb();
958
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
958
+ await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard '${keyboardContent}'`);
959
959
  }
960
960
  async getElementsInfo() {
961
961
  return [];
@@ -1403,17 +1403,24 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1403
1403
  shouldUseYadbForText(text) {
1404
1404
  const hasNonAscii = /[\x80-\uFFFF]/.test(text);
1405
1405
  const hasFormatSpecifiers = /%[a-zA-Z]/.test(text);
1406
- return hasNonAscii || hasFormatSpecifiers;
1406
+ const hasShellSpecialChars = /[\\`$]/.test(text);
1407
+ const hasBothQuotes = text.includes('"') && text.includes("'");
1408
+ return hasNonAscii || hasFormatSpecifiers || hasShellSpecialChars || hasBothQuotes;
1407
1409
  }
1408
1410
  async keyboardType(text, options) {
1409
1411
  if (!text) return;
1410
1412
  const adb = await this.getAdb();
1411
- const shouldUseYadb = this.shouldUseYadbForText(text);
1412
1413
  const IME_STRATEGY = (this.options?.imeStrategy || env_namespaceObject.globalConfigManager.getEnvConfigValue(env_namespaceObject.MIDSCENE_ANDROID_IME_STRATEGY)) ?? IME_STRATEGY_YADB_FOR_NON_ASCII;
1413
1414
  const shouldAutoDismissKeyboard = options?.autoDismissKeyboard ?? this.options?.autoDismissKeyboard ?? true;
1414
- const escapedText = escapeForShell(text);
1415
- if (IME_STRATEGY === IME_STRATEGY_ALWAYS_YADB || IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII && shouldUseYadb) await this.execYadb(escapedText);
1416
- else await adb.inputText(escapedText);
1415
+ const useYadb = IME_STRATEGY === IME_STRATEGY_ALWAYS_YADB || IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII && this.shouldUseYadbForText(text);
1416
+ if (useYadb) await this.execYadb(escapeForShell(text));
1417
+ else {
1418
+ const segments = text.split('\n');
1419
+ for(let i = 0; i < segments.length; i++){
1420
+ if (segments[i].length > 0) await adb.inputText(segments[i]);
1421
+ if (i < segments.length - 1) await adb.keyevent(66);
1422
+ }
1423
+ }
1417
1424
  if (true === shouldAutoDismissKeyboard) await this.hideKeyboard(options);
1418
1425
  }
1419
1426
  normalizeKeyName(key) {
@@ -144,12 +144,15 @@ export declare class AndroidDevice implements AbstractInterface {
144
144
  scrollRight(distance?: number, startPoint?: Point): Promise<void>;
145
145
  ensureYadb(): Promise<void>;
146
146
  /**
147
- * Check if text contains characters that may cause issues with ADB inputText
148
- * This includes:
149
- * - Non-ASCII characters (Unicode characters like ö, é, ñ, Chinese, Japanese, etc.)
150
- * - Format specifiers that may be interpreted by shell (%, $)
151
- * - Special shell characters that need escaping
152
- * - Control characters like newlines, tabs, carriage returns
147
+ * Check if text contains characters that may cause issues with ADB inputText.
148
+ * appium-adb's inputText has known bugs with certain characters:
149
+ * - Backslash causes broken shell quoting
150
+ * - Backtick is not escaped at all
151
+ * - Text containing both " and ' throws an error
152
+ * - Dollar sign can cause variable expansion issues
153
+ *
154
+ * For these characters, we route through yadb which handles them correctly
155
+ * via escapeForShell + double-quoted shell context.
153
156
  */
154
157
  private shouldUseYadbForText;
155
158
  keyboardType(text: string, options?: AndroidDeviceInputOpt): Promise<void>;
@@ -145,12 +145,15 @@ declare class AndroidDevice implements AbstractInterface {
145
145
  scrollRight(distance?: number, startPoint?: Point): Promise<void>;
146
146
  ensureYadb(): Promise<void>;
147
147
  /**
148
- * Check if text contains characters that may cause issues with ADB inputText
149
- * This includes:
150
- * - Non-ASCII characters (Unicode characters like ö, é, ñ, Chinese, Japanese, etc.)
151
- * - Format specifiers that may be interpreted by shell (%, $)
152
- * - Special shell characters that need escaping
153
- * - Control characters like newlines, tabs, carriage returns
148
+ * Check if text contains characters that may cause issues with ADB inputText.
149
+ * appium-adb's inputText has known bugs with certain characters:
150
+ * - Backslash causes broken shell quoting
151
+ * - Backtick is not escaped at all
152
+ * - Text containing both " and ' throws an error
153
+ * - Dollar sign can cause variable expansion issues
154
+ *
155
+ * For these characters, we route through yadb which handles them correctly
156
+ * via escapeForShell + double-quoted shell context.
154
157
  */
155
158
  private shouldUseYadbForText;
156
159
  keyboardType(text: string, options?: AndroidDeviceInputOpt): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/android",
3
- "version": "1.3.11",
3
+ "version": "1.3.12-beta-20260211105759.0",
4
4
  "description": "Android automation library for Midscene",
5
5
  "keywords": [
6
6
  "Android UI automation",
@@ -38,8 +38,8 @@
38
38
  "@yume-chan/stream-extra": "^1.0.0",
39
39
  "appium-adb": "12.12.1",
40
40
  "sharp": "^0.34.3",
41
- "@midscene/shared": "1.3.11",
42
- "@midscene/core": "1.3.11"
41
+ "@midscene/shared": "1.3.12-beta-20260211105759.0",
42
+ "@midscene/core": "1.3.12-beta-20260211105759.0"
43
43
  },
44
44
  "optionalDependencies": {
45
45
  "@ffmpeg-installer/ffmpeg": "^1.1.0"
@@ -53,7 +53,7 @@
53
53
  "tsx": "^4.19.2",
54
54
  "vitest": "3.0.5",
55
55
  "zod": "3.24.3",
56
- "@midscene/playground": "1.3.11"
56
+ "@midscene/playground": "1.3.12-beta-20260211105759.0"
57
57
  },
58
58
  "license": "MIT",
59
59
  "scripts": {