| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- #!/usr/bin/env node
- const { execSync, spawnSync } = require('child_process')
- const path = require('path')
- const fs = require('fs')
- const configPath = process.env.STATIC_ROOT
- ? path.join(path.dirname(process.env.STATIC_ROOT), 'config.js')
- : path.join(__dirname, '..', '..', 'config.js')
- const projectRoot = path.dirname(path.resolve(configPath))
- const config = fs.existsSync(configPath) ? require(configPath) : {}
- /** 从 config 解析并返回 adb 可执行文件路径 */
- function getAdbPath() {
- const p = config.adbPath?.path
- if (p) return path.isAbsolute(p) ? p : path.resolve(projectRoot, p)
- return path.join(projectRoot, 'lib', 'scrcpy-adb', process.platform === 'win32' ? 'adb.exe' : 'adb')
- }
- /** 根据 deviceId 返回 adb -s 参数前缀,无设备时返回空串 */
- function getDeviceFlag(deviceId) {
- return deviceId && deviceId.includes(':') ? `-s ${deviceId} ` : ''
- }
- /** 执行 adb shell 命令 */
- function runShell(adbPath, deviceFlag, shellArgs, timeout = 1000) {
- const quoted = adbPath.includes(' ') ? `"${adbPath}"` : adbPath
- execSync(`${quoted} ${deviceFlag}shell ${shellArgs}`, { encoding: 'utf-8', timeout })
- }
- /** 执行 adb shell 并返回标准输出 */
- function runShellWithOutput(adbPath, deviceFlag, shellArgs, timeout = 1000) {
- const quoted = adbPath.includes(' ') ? `"${adbPath}"` : adbPath
- return execSync(`${quoted} ${deviceFlag}shell ${shellArgs}`, { encoding: 'utf-8', timeout })
- }
- /** 处理 tap:点击坐标(超时放宽以便 WiFi 连接时能完成) */
- function handleTap(adbPath, argv) {
- const coordX = argv[3]
- const coordY = argv[4]
- const deviceId = argv[5] || ''
- if (!coordX || !coordY) process.exit(1)
- const flag = getDeviceFlag(deviceId)
- runShell(adbPath, flag, `input tap ${coordX} ${coordY}`, 8000)
- }
- /** 根据方向与距离计算滑动的起止坐标(基于屏幕中心),返回 [startX, startY, endX, endY] */
- function getSwipeCoordsByDirection(direction, distance, centerX, centerY) {
- const half = Math.floor(distance / 2)
- switch (direction) {
- case 'up-down':
- return [centerX, centerY - half, centerX, centerY + half]
- case 'down-up':
- return [centerX, centerY + half, centerX, centerY - half]
- case 'left-right':
- return [centerX - half, centerY, centerX + half, centerY]
- case 'right-left':
- return [centerX + half, centerY, centerX - half, centerY]
- default:
- process.exit(1)
- }
- }
- /** 处理 swipe:按方向与距离从屏幕中心滑动 */
- function handleSwipe(adbPath, argv) {
- const direction = argv[3]
- const distance = parseInt(argv[4], 10)
- const duration = parseInt(argv[5], 10)
- const deviceId = argv[6] || ''
- if (!direction || !distance || !duration) process.exit(1)
- const flag = getDeviceFlag(deviceId)
- const sizeOut = runShellWithOutput(adbPath, flag, 'wm size', 1000)
- const sizeMatch = sizeOut.match(/(\d+)x(\d+)/)
- const centerX = Math.floor(parseInt(sizeMatch[1], 10) / 2)
- const centerY = Math.floor(parseInt(sizeMatch[2], 10) / 2)
- const [startX, startY, endX, endY] = getSwipeCoordsByDirection(direction, distance, centerX, centerY)
- runShell(adbPath, flag, `input swipe ${startX} ${startY} ${endX} ${endY} ${duration}`, 2000)
- }
- /** 处理 swipe-coords:按坐标滑动 */
- function handleSwipeCoords(adbPath, argv) {
- const x1 = argv[3]
- const y1 = argv[4]
- const x2 = argv[5]
- const y2 = argv[6]
- const duration = argv[7] || 300
- const deviceId = argv[8] || ''
- if (!x1 || !y1 || !x2 || !y2) process.exit(1)
- const flag = getDeviceFlag(deviceId)
- runShell(adbPath, flag, `input swipe ${x1} ${y1} ${x2} ${y2} ${duration}`, 2000)
- }
- /** 处理 keyevent:按键 */
- function handleKeyevent(adbPath, argv) {
- const keyCode = argv[3]
- const deviceId = argv[4] || ''
- if (!keyCode) process.exit(1)
- const flag = getDeviceFlag(deviceId)
- runShell(adbPath, flag, `input keyevent ${keyCode}`, 1000)
- }
- /** 简单 input text(供 type:input 等调用;adb method:input 的完整逻辑在 ef-compiler/actions/adb/input.js) */
- function handleText(adbPath, argv) {
- const text = argv[3]
- const deviceId = argv[4] || ''
- if (text === undefined) process.exit(1)
- const str = String(text)
- const shellArgs = deviceId && deviceId.includes(':') ? ['-s', deviceId, 'shell', 'input', 'text', str] : ['shell', 'input', 'text', str]
- const r = spawnSync(adbPath, shellArgs, { encoding: 'utf-8', timeout: 5000 })
- if (r.status !== 0) {
- const err = new Error(r.stderr || r.stdout || 'input text failed')
- err.status = r.status
- throw err
- }
- }
- const action = process.argv[2]
- if (!action) process.exit(1)
- const adbPath = getAdbPath()
- switch (action) {
- case 'tap':
- handleTap(adbPath, process.argv)
- break
- case 'swipe':
- handleSwipe(adbPath, process.argv)
- break
- case 'swipe-coords':
- handleSwipeCoords(adbPath, process.argv)
- break
- case 'keyevent':
- handleKeyevent(adbPath, process.argv)
- break
- case 'text':
- handleText(adbPath, process.argv)
- break
- default:
- process.exit(1)
- }
- process.exit(0)
|