From e5aa5d1d5c0fccebed55ddbb36257df3da75f57c Mon Sep 17 00:00:00 2001 From: bangae1 Date: Wed, 22 Oct 2025 14:56:52 +0900 Subject: [PATCH] asdf --- agent-renderer.js | 16 +++++++++ main.js | 85 +++++++++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 44 deletions(-) diff --git a/agent-renderer.js b/agent-renderer.js index 031ae4b..f71a9c7 100644 --- a/agent-renderer.js +++ b/agent-renderer.js @@ -2,6 +2,7 @@ let peerConnection = null; let currentStream = null; +let dataChannel = null; let connection = false; // 메인 프로세스로부터 명령 수신 (IPC) console.log('electronAPI:', window.electronAPI); @@ -53,6 +54,16 @@ window.electronAPI.receive('start-webrtc', async (data) => { window.electronAPI.send('icecandidate', {type: 'icecandidate', targetId: data.targetId, server:'agent', 'candidate': event.candidate}); }, 2000) } + + peerConnection.ondatachannel = (event) => { + console.log('datachannel', event); + dataChannel = event.channel; + dataChannel.onmessage = (event) => { + window.electronAPI.send('inputEvent', JSON.parse(event.data)) + } + } + + }); window.electronAPI.receive('displays', async (data) => { @@ -66,5 +77,10 @@ window.electronAPI.receive('icecandidate', async (data) => { } }); +window.electronAPI.receive('disconnect', async (data) => { + peerConnection.close(); + peerConnection = null; +}); + // desktopCapturer 사용을 위해 preload 필요 // → 다음 단계에서 preload.js 설정 \ No newline at end of file diff --git a/main.js b/main.js index bd47428..9c943de 100644 --- a/main.js +++ b/main.js @@ -3,17 +3,16 @@ const { app, BrowserWindow, Tray, Menu, nativeImage, dialog, ipcMain } = require const path = require('path'); const io = require('socket.io-client'); const { desktopCapturer } = require('electron'); -const { mouse, Point, straightTo, keyboard, Key, clipboard } = require('@nut-tree-fork/nut-js') +const { mouse, Point, straightTo, keyboard, Key, clipboard, Button} = require('@nut-tree-fork/nut-js') // 고유 직원 ID const EMPLOYEE_ID = "psn14020"; // 시그널링 서버 주소 -const SIGNALING_SERVER = 'http://localhost:3001'; +const SIGNALING_SERVER = 'http://192.168.0.148:3001'; let tray = null; let mainWindow = null; let socket = null; -let peerConnection = null; let displayId = null; let offer = null; let sources = null; @@ -69,31 +68,44 @@ async function sendAvailableDisplays() { console.error('디스플레이 목록 가져오기 실패:', err); } } - +const keyMap = { + Enter: Key.Enter, + Backspace: Key.Backspace, + Tab: Key.Tab, + Escape: Key.Escape, + ArrowDown: Key.Down, + ArrowUp: Key.Up, + ArrowLeft: Key.Left, + ArrowRight: Key.Right, +} // 🖱️ 입력 이벤트 처리 (robotjs 필요) -function setupInputHandler() { +async function setupInputHandler(data) { // robotjs는 별도 설치 및 권한 필요 - socket.on('inputEvent', async({ type, ...data }) => { - try { - if (type === 'mouse') { - const { x, y, action } = data; - const targetPoint = new Point(x, y) - await mouse.move(straightTo(targetPoint)); - if (action === 'click') { - await mouse.leftClick(); - } - } else if (type === 'keyboard') { - const { key } = data; - // 간단한 키 매핑 (보안상 복잡한 키는 제한 권장) - if (key.length === 1 || ['Enter', 'Backspace', 'Tab', 'Escape'].includes(key)) { - await keyboard.pressKey(key.toLowerCase()); - } - } - } catch (err) { - console.error('입력 이벤트 처리 오류:', err); + if (data.type === 'mouse') { + const { x, y, action } = data; + if(x === null || y === null) return + const targetPoint = new Point(x, y) + await mouse.move(straightTo(targetPoint)); + console.log(x, y , action) + if (action === 'click') { + await mouse.click(Button.LEFT) } - }); + } else if (data.type === 'keyboard') { + const { key } = data; + // 간단한 키 매핑 (보안상 복잡한 키는 제한 권장) + console.log(key) + if(['Enter', 'Backspace', 'Tab', 'Escape' + , 'ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight'].includes(key)) { + await keyboard.pressKey(keyMap[key]); + await keyboard.releaseKey(keyMap[key]); + } else if(key.length === 1) { + await keyboard.type(key.toLowerCase()); + } + // if (key.length === 1 || ['Enter', 'Backspace', 'Tab', 'Escape'].includes(key)) { + // await keyboard.type(key.toLowerCase()); + // } + } } // 시그널링 연결 @@ -120,10 +132,7 @@ function connectToSignaling() { socket.on('disconnect', () => { console.log('시그널링 서버와 연결 끊김'); - if (peerConnection) { - peerConnection.close(); - peerConnection = null; - } + rendererWindow.webContents.send('disconnect'); }); socket.on('responseOffer', async (data) => { @@ -175,22 +184,6 @@ app.on('window-all-closed', () => { // Windows/Linux에서 종료하지 않음 }); -ipcMain.on('input-event-from-renderer', (event, data) => { - // 여기서 robotjs로 입력 실행 (메인 프로세스에서만 가능) - try { - const robot = require('robotjs'); - if (data.type === 'mouse') { - robot.moveMouse(Math.round(data.x), Math.round(data.y)); - if (data.action === 'click') robot.mouseClick(); - } else if (data.type === 'keyboard') { - robot.keyTap(data.key); - } - } catch (e) { - console.error('robotjs 오류:', e); - } -}) - - ipcMain.on('requestAnswer', (event, data) => { socket.emit('requestAnswer', data); }) @@ -203,4 +196,8 @@ ipcMain.on('icecandidate', (event, data) => { ipcMain.on('start', (event, data) => { console.log('start', data); socket.emit('start', data); +}) + +ipcMain.on('inputEvent', (event, data) => { + setupInputHandler(data) }) \ No newline at end of file