|
|
@@ -168,6 +168,107 @@ ipcMain.handle('send-swipe', async (event, ipPort, x1, y1, x2, y2, duration = 30
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+// IPC 处理程序:发送文字到设备
|
|
|
+ipcMain.handle('send-text', async (event, ipPort, text) => {
|
|
|
+ if (!ipPort) {
|
|
|
+ return { success: false, error: '缺少设备 ID' };
|
|
|
+ }
|
|
|
+ if (typeof text !== 'string') {
|
|
|
+ return { success: false, error: '文字必须是字符串' };
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ // ADB input text 需要转义特殊字符
|
|
|
+ // 使用单引号包裹,并转义单引号
|
|
|
+ const escapedText = text
|
|
|
+ .replace(/\\/g, '\\\\') // 先转义反斜杠
|
|
|
+ .replace(/'/g, "'\\''") // 转义单引号
|
|
|
+ .replace(/ /g, '%s') // 空格转换为 %s
|
|
|
+ .replace(/&/g, '\\&') // 转义 &
|
|
|
+ .replace(/</g, '\\<') // 转义 <
|
|
|
+ .replace(/>/g, '\\>') // 转义 >
|
|
|
+ .replace(/\(/g, '\\(') // 转义 (
|
|
|
+ .replace(/\)/g, '\\)') // 转义 )
|
|
|
+ .replace(/;/g, '\\;') // 转义 ;
|
|
|
+ .replace(/\|/g, '\\|') // 转义 |
|
|
|
+ .replace(/\*/g, '\\*') // 转义 *
|
|
|
+ .replace(/\?/g, '\\?') // 转义 ?
|
|
|
+ .replace(/`/g, '\\`') // 转义 `
|
|
|
+ .replace(/\$/g, '\\$') // 转义 $
|
|
|
+ .replace(/"/g, '\\"'); // 转义 "
|
|
|
+
|
|
|
+ // 对于换行,使用 KEYCODE_ENTER
|
|
|
+ if (text.includes('\n')) {
|
|
|
+ // 如果有换行,分段发送
|
|
|
+ const lines = text.split('\n');
|
|
|
+ for (let i = 0; i < lines.length; i++) {
|
|
|
+ if (lines[i]) {
|
|
|
+ const escapedLine = lines[i]
|
|
|
+ .replace(/\\/g, '\\\\')
|
|
|
+ .replace(/'/g, "'\\''")
|
|
|
+ .replace(/ /g, '%s')
|
|
|
+ .replace(/&/g, '\\&')
|
|
|
+ .replace(/</g, '\\<')
|
|
|
+ .replace(/>/g, '\\>')
|
|
|
+ .replace(/\(/g, '\\(')
|
|
|
+ .replace(/\)/g, '\\)')
|
|
|
+ .replace(/;/g, '\\;')
|
|
|
+ .replace(/\|/g, '\\|')
|
|
|
+ .replace(/\*/g, '\\*')
|
|
|
+ .replace(/\?/g, '\\?')
|
|
|
+ .replace(/`/g, '\\`')
|
|
|
+ .replace(/\$/g, '\\$')
|
|
|
+ .replace(/"/g, '\\"');
|
|
|
+
|
|
|
+ await execAsync(`adb -s ${ipPort} shell input text "${escapedLine}"`, {
|
|
|
+ timeout: 5000,
|
|
|
+ maxBuffer: 1024 * 1024
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 发送换行(除了最后一行)
|
|
|
+ if (i < lines.length - 1) {
|
|
|
+ await execAsync(`adb -s ${ipPort} shell input keyevent KEYCODE_ENTER`, {
|
|
|
+ timeout: 5000,
|
|
|
+ maxBuffer: 1024 * 1024
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 没有换行,直接发送
|
|
|
+ const command = `adb -s ${ipPort} shell input text "${escapedText}"`;
|
|
|
+ await execAsync(command, {
|
|
|
+ timeout: 5000,
|
|
|
+ maxBuffer: 1024 * 1024
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return { success: true };
|
|
|
+ } catch (error) {
|
|
|
+ console.error('发送文字失败:', error.message);
|
|
|
+ return { success: false, error: error.message };
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// IPC 处理程序:发送按键事件到设备
|
|
|
+ipcMain.handle('send-key-event', async (event, ipPort, keyCode) => {
|
|
|
+ if (!ipPort) {
|
|
|
+ return { success: false, error: '缺少设备 ID' };
|
|
|
+ }
|
|
|
+ if (typeof keyCode !== 'string') {
|
|
|
+ return { success: false, error: '按键代码必须是字符串' };
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const command = `adb -s ${ipPort} shell input keyevent ${keyCode}`;
|
|
|
+ await execAsync(command, {
|
|
|
+ timeout: 5000,
|
|
|
+ maxBuffer: 1024 * 1024
|
|
|
+ });
|
|
|
+ return { success: true };
|
|
|
+ } catch (error) {
|
|
|
+ console.error('发送按键失败:', error.message);
|
|
|
+ return { success: false, error: error.message };
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
// 应用启动逻辑:设置 CSP、创建窗口、监听激活事件
|
|
|
app.whenReady().then(() => {
|
|
|
setContentSecurityPolicy();
|