#!/usr/bin/env node /** * 测试 ADB Keyboard 发送文字:尝试多种 broadcast 方式直到成功。 * 用法: node test-adbkeyboard-send.js [文本] * 例: node test-adbkeyboard-send.js 192.168.42.129:5555 创建小红书笔记 */ const path = require('path') const fs = require('fs') const { spawnSync } = require('child_process') const projectRoot = path.resolve(__dirname, '..', '..') const config = require(path.join(projectRoot, 'config.js')) const adbPath = config.adbPath?.path ? path.resolve(projectRoot, config.adbPath.path) : path.join(projectRoot, 'lib', 'scrcpy-adb', 'adb.exe') const PKG = 'com.android.adbkeyboard' const TEST_TEXT = process.argv[3] || '测试' function deviceArgs(device) { return device && String(device).includes(':') ? ['-s', device] : [] } function shell(device, cmd, timeout = 5000) { const args = [...deviceArgs(device), 'shell', cmd] const r = spawnSync(adbPath, args, { encoding: 'utf-8', timeout }) return { ok: r.status === 0, out: (r.stdout || '').trim(), err: (r.stderr || '').trim() } } function broadcast(device, action, extraKey, value, component) { const args = [...deviceArgs(device), 'shell', 'am', 'broadcast', '-a', action, '--es', extraKey, value] if (component) args.splice(args.length - 2, 0, '-n', component) const r = spawnSync(adbPath, args, { encoding: 'utf-8', timeout: 10000 }) return r.status === 0 } function getReceivers(device) { const { out } = shell(device, `dumpsys package ${PKG}`, 8000) const receivers = [] const re = /Receiver #\d+.*?ComponentInfo\{([^}]+)\}/gs let m while ((m = re.exec(out)) !== null) { const comp = m[1].trim() if (comp.startsWith(PKG)) receivers.push(comp) } const alt = out.match(new RegExp(PKG + '/[^\\s\\n\\r]+', 'g')) if (alt) alt.forEach(c => { if (!receivers.includes(c)) receivers.push(c) }) return [...new Set(receivers)] } function setIme(device, imeId) { return shell(device, `ime set ${imeId}`, 5000).ok } function getCurrentIme(device) { return shell(device, 'settings get secure default_input_method', 3000).out } function findAdbKeyboardIme(device) { const { out } = shell(device, 'ime list -a', 5000) const lines = (out || '').split(/\r?\n/) for (const line of lines) { const t = line.trim().replace(/:$/, '') if (t.includes('/') && t.toLowerCase().includes('adbkeyboard')) return t } return `${PKG}/.AdbIME` } function main() { const device = process.argv[2] if (!device) { console.error('用法: node test-adbkeyboard-send.js [文本]') process.exit(2) } const prevIme = getCurrentIme(device) const imeId = findAdbKeyboardIme(device) console.log('当前 IME:', prevIme) console.log('切换到:', imeId) if (!setIme(device, imeId)) { console.error('切换 IME 失败') process.exit(1) } const base64 = Buffer.from(TEST_TEXT, 'utf8').toString('base64') const methods = [ { name: 'ADB_INPUT_B64 隐式', fn: () => broadcast(device, 'ADB_INPUT_B64', 'msg', base64, null) }, { name: `ADB_INPUT_B64 -n ${PKG}/.AdbReceiver`, fn: () => broadcast(device, 'ADB_INPUT_B64', 'msg', base64, `${PKG}/.AdbReceiver`) }, { name: `ADB_INPUT_B64 -n ${PKG}/.Receiver`, fn: () => broadcast(device, 'ADB_INPUT_B64', 'msg', base64, `${PKG}/.Receiver`) }, { name: `ADB_INPUT_B64 -n ${imeId}`, fn: () => broadcast(device, 'ADB_INPUT_B64', 'msg', base64, imeId) }, { name: 'ADB_INPUT_TEXT 隐式', fn: () => broadcast(device, 'ADB_INPUT_TEXT', 'msg', TEST_TEXT, null) }, { name: `ADB_INPUT_TEXT -n ${PKG}/.AdbReceiver`, fn: () => broadcast(device, 'ADB_INPUT_TEXT', 'msg', TEST_TEXT, `${PKG}/.AdbReceiver`) }, ] const receivers = getReceivers(device) console.log('包内 Receiver 组件:', receivers.length ? receivers : '(未解析到)') receivers.forEach(comp => { methods.push({ name: `ADB_INPUT_B64 -n ${comp}`, fn: () => broadcast(device, 'ADB_INPUT_B64', 'msg', base64, comp) }) }) for (const m of methods) { const ok = m.fn() console.log(ok ? '[OK]' : '[FAIL]', m.name) if (ok) { if (prevIme) setIme(device, prevIme) console.log('发送成功,已切回原 IME。请查看设备输入框是否出现文字:', TEST_TEXT) process.exit(0) } } if (prevIme) setIme(device, prevIme) console.error('所有方式均失败') process.exit(1) } main()