| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- #!/usr/bin/env node
- /**
- * 测试 ADB Keyboard 发送文字:尝试多种 broadcast 方式直到成功。
- * 用法: node test-adbkeyboard-send.js <device_id> [文本]
- * 例: 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, 'configs', '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 <device_id> [文本]')
- 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()
|