input.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import { ipcMain } from 'electron';
  2. import { exec } from 'child_process';
  3. import { promisify } from 'util';
  4. import { getCachedAdbPath } from '../config.js';
  5. const execAsync = promisify(exec);
  6. // 发送 tap 事件到设备
  7. export async function sendTap(ipPort, x, y) {
  8. if (!ipPort) {
  9. return { success: false, error: '缺少设备 ID' };
  10. }
  11. if (typeof x !== 'number' || typeof y !== 'number') {
  12. return { success: false, error: '坐标必须是数字' };
  13. }
  14. try {
  15. const adbPath = getCachedAdbPath();
  16. const command = `${adbPath} -s ${ipPort} shell input tap ${x} ${y}`;
  17. await execAsync(command, {
  18. timeout: 5000,
  19. maxBuffer: 1024 * 1024
  20. });
  21. return { success: true };
  22. } catch (error) {
  23. console.error('Tap 失败:', error.message);
  24. return { success: false, error: error.message };
  25. }
  26. }
  27. // 发送 swipe 事件到设备
  28. export async function sendSwipe(ipPort, x1, y1, x2, y2, duration = 300) {
  29. if (!ipPort) {
  30. return { success: false, error: '缺少设备 ID' };
  31. }
  32. if (typeof x1 !== 'number' || typeof y1 !== 'number' || typeof x2 !== 'number' || typeof y2 !== 'number') {
  33. return { success: false, error: '坐标必须是数字' };
  34. }
  35. try {
  36. const adbPath = getCachedAdbPath();
  37. const command = `${adbPath} -s ${ipPort} shell input swipe ${x1} ${y1} ${x2} ${y2} ${duration}`;
  38. await execAsync(command, {
  39. timeout: 5000,
  40. maxBuffer: 1024 * 1024
  41. });
  42. return { success: true };
  43. } catch (error) {
  44. console.error('Swipe 失败:', error.message);
  45. return { success: false, error: error.message };
  46. }
  47. }
  48. // 转义文字中的特殊字符
  49. function escapeText(text) {
  50. return text
  51. .replace(/\\/g, '\\\\') // 先转义反斜杠
  52. .replace(/'/g, "'\\''") // 转义单引号
  53. .replace(/ /g, '%s') // 空格转换为 %s
  54. .replace(/&/g, '\\&') // 转义 &
  55. .replace(/</g, '\\<') // 转义 <
  56. .replace(/>/g, '\\>') // 转义 >
  57. .replace(/\(/g, '\\(') // 转义 (
  58. .replace(/\)/g, '\\)') // 转义 )
  59. .replace(/;/g, '\\;') // 转义 ;
  60. .replace(/\|/g, '\\|') // 转义 |
  61. .replace(/\*/g, '\\*') // 转义 *
  62. .replace(/\?/g, '\\?') // 转义 ?
  63. .replace(/`/g, '\\`') // 转义 `
  64. .replace(/\$/g, '\\$') // 转义 $
  65. .replace(/"/g, '\\"'); // 转义 "
  66. }
  67. // 发送文字到设备
  68. export async function sendText(ipPort, text) {
  69. if (!ipPort) {
  70. return { success: false, error: '缺少设备 ID' };
  71. }
  72. if (typeof text !== 'string') {
  73. return { success: false, error: '文字必须是字符串' };
  74. }
  75. try {
  76. const adbPath = getCachedAdbPath();
  77. // 对于换行,使用 KEYCODE_ENTER
  78. if (text.includes('\n')) {
  79. // 如果有换行,分段发送
  80. const lines = text.split('\n');
  81. for (let i = 0; i < lines.length; i++) {
  82. if (lines[i]) {
  83. const escapedLine = escapeText(lines[i]);
  84. await execAsync(`${adbPath} -s ${ipPort} shell input text "${escapedLine}"`, {
  85. timeout: 5000,
  86. maxBuffer: 1024 * 1024
  87. });
  88. }
  89. // 发送换行(除了最后一行)
  90. if (i < lines.length - 1) {
  91. await execAsync(`${adbPath} -s ${ipPort} shell input keyevent KEYCODE_ENTER`, {
  92. timeout: 5000,
  93. maxBuffer: 1024 * 1024
  94. });
  95. }
  96. }
  97. } else {
  98. // 没有换行,直接发送
  99. const escapedText = escapeText(text);
  100. const command = `${adbPath} -s ${ipPort} shell input text "${escapedText}"`;
  101. await execAsync(command, {
  102. timeout: 5000,
  103. maxBuffer: 1024 * 1024
  104. });
  105. }
  106. return { success: true };
  107. } catch (error) {
  108. console.error('发送文字失败:', error.message);
  109. return { success: false, error: error.message };
  110. }
  111. }
  112. // 发送按键事件到设备
  113. export async function sendKeyEvent(ipPort, keyCode) {
  114. if (!ipPort) {
  115. return { success: false, error: '缺少设备 ID' };
  116. }
  117. if (typeof keyCode !== 'string') {
  118. return { success: false, error: '按键代码必须是字符串' };
  119. }
  120. try {
  121. const adbPath = getCachedAdbPath();
  122. const command = `${adbPath} -s ${ipPort} shell input keyevent ${keyCode}`;
  123. await execAsync(command, {
  124. timeout: 5000,
  125. maxBuffer: 1024 * 1024
  126. });
  127. return { success: true };
  128. } catch (error) {
  129. console.error('发送按键失败:', error.message);
  130. return { success: false, error: error.message };
  131. }
  132. }
  133. // 注册 IPC 处理器
  134. export function registerIpcHandlers() {
  135. // IPC 处理程序:发送 tap 事件到设备
  136. ipcMain.handle('send-tap', async (event, ipPort, x, y) => {
  137. return await sendTap(ipPort, x, y);
  138. });
  139. // IPC 处理程序:发送 swipe 事件到设备
  140. ipcMain.handle('send-swipe', async (event, ipPort, x1, y1, x2, y2, duration = 300) => {
  141. return await sendSwipe(ipPort, x1, y1, x2, y2, duration);
  142. });
  143. // IPC 处理程序:发送文字到设备
  144. ipcMain.handle('send-text', async (event, ipPort, text) => {
  145. return await sendText(ipPort, text);
  146. });
  147. // IPC 处理程序:发送按键事件到设备
  148. ipcMain.handle('send-key-event', async (event, ipPort, keyCode) => {
  149. return await sendKeyEvent(ipPort, keyCode);
  150. });
  151. }