import { ipcMain } from 'electron'; import { exec } from 'child_process'; import { promisify } from 'util'; import { getCachedAdbPath } from '../config.js'; const execAsync = promisify(exec); // 默认每次滚动距离(像素) const DEFAULT_SCROLL_DISTANCE = 100; // 默认滚动持续时间(毫秒),使用较长的时间模拟真实手指滑动 const DEFAULT_SCROLL_DURATION = 500; /** * 计算滚动操作的坐标(小幅度滚动) * @param {string} direction - 滚动方向: up-down, down-up, left-right, right-left * @param {number} width - 设备宽度 * @param {number} height - 设备高度 * @param {number} scrollDistance - 每次滚动距离(像素),默认10px * @returns {Object} 包含起始和结束坐标的对象 {x1, y1, x2, y2} */ function calculateScrollCoordinates(direction, width, height, scrollDistance = DEFAULT_SCROLL_DISTANCE) { // 滚动从屏幕中心开始 const centerX = Math.round(width / 2); const centerY = Math.round(height / 2); let x1, y1, x2, y2; switch (direction) { case 'up-down': // 从上往下滚动(向下滚动) x1 = x2 = centerX; y1 = centerY; y2 = centerY + scrollDistance; break; case 'down-up': // 从下往上滚动(向上滚动) x1 = x2 = centerX; y1 = centerY; y2 = centerY - scrollDistance; break; case 'left-right': // 从左往右滚动(向右滚动) y1 = y2 = centerY; x1 = centerX; x2 = centerX + scrollDistance; break; case 'right-left': // 从右往左滚动(向左滚动) y1 = y2 = centerY; x1 = centerX; x2 = centerX - scrollDistance; break; default: throw new Error(`未知的滚动方向: ${direction}`); } return { x1, y1, x2, y2 }; } /** * 发送滚动操作到设备 * 使用触摸屏事件模拟真实的手指滑动,避免触发 tap 事件 * @param {string} ipPort - 设备 ID * @param {string} direction - 滚动方向: up-down, down-up, left-right, right-left * @param {number} width - 设备宽度 * @param {number} height - 设备高度 * @param {number} scrollDistance - 每次滚动距离(像素),默认10px * @param {number} duration - 滚动持续时间(毫秒),默认500ms * @returns {Promise} 执行结果 {success, error?} */ export async function sendScroll(ipPort, direction, width, height, scrollDistance = DEFAULT_SCROLL_DISTANCE, duration = DEFAULT_SCROLL_DURATION) { if (!ipPort) { return { success: false, error: '缺少设备 ID' }; } if (!direction) { return { success: false, error: '缺少滚动方向' }; } const validDirections = ['up-down', 'down-up', 'left-right', 'right-left']; if (!validDirections.includes(direction)) { return { success: false, error: `无效的滚动方向: ${direction},应为: ${validDirections.join(', ')}` }; } if (typeof width !== 'number' || typeof height !== 'number') { return { success: false, error: '设备宽度和高度必须是数字' }; } if (width <= 0 || height <= 0) { return { success: false, error: '设备宽度和高度必须大于0' }; } try { const adbPath = getCachedAdbPath(); // 计算滚动坐标 const { x1, y1, x2, y2 } = calculateScrollCoordinates(direction, width, height, scrollDistance); // 使用 input touchscreen swipe 命令来模拟真实的触摸滑动 // 这个命令会模拟手指在屏幕上慢慢滑动,不会触发 tap 事件 // 使用较长的持续时间(至少 300ms)确保被识别为滑动而不是点击 const actualDuration = Math.max(duration, 300); // 确保至少 300ms const command = `${adbPath} -s ${ipPort} shell input touchscreen swipe ${x1} ${y1} ${x2} ${y2} ${actualDuration}`; await execAsync(command, { timeout: 10000, maxBuffer: 1024 * 1024 }); return { success: true }; } catch (error) { return { success: false, error: error.message }; } } // 注册 IPC 处理器 export function registerIpcHandlers() { // IPC 处理程序:发送滚动操作到设备 ipcMain.handle('send-scroll', async (event, ipPort, direction, width, height, scrollDistance, duration) => { return await sendScroll(ipPort, direction, width, height, scrollDistance, duration); }); }