Home 캡스톤일지 | ~ 10.16 robotjs 이용한 마우스 커서 이동
Post
Cancel

캡스톤일지 | ~ 10.16 robotjs 이용한 마우스 커서 이동

어쩌다보니 12시가 넘어서 16일까지의 캡스톤 일지가 되어버림


image

회사에서 퍼블리셔분들이 퍼블 나올때마다 표로 정리해주신게 생각나서 해본 테스트 페이지 꾸미기 및 폴더 정리
블로그 포스팅 제쳐두고 한시간 남짓 했는디 시험기간에는 공부빼고 다 재밌는듯
어제까지 고민하던 것들이 오늘 잘 풀려서 기분이 조타
통시 공부는 내일부터 할꺼다.. 증말루..


해결3. 파이썬 개발

저번 포스팅에 이어 해결방법 3은 스크립트로 불가한 마우스 조작 기능을 파이썬으로 구현하여 노드에 연결하는 것이다.
새로 가상환경 만들어서 미디어파이프를 다시 설치해볼까 하였지만.. 역시나 잘 안돼서 깔끔히 포기했다.

노드에서 미디어파이프 적용하여 검지 손가락의 포인트 알아냄

  • 파이썬 함수로 좌표값을 전달 (혹은 파이썬 파일에 바로 전달하여 .py 실행)
  • 전달받은 좌표값으로 마우스 커서 이동 (*단 실시간으로 계속 이어져야함!)

파이썬 라이브러리 pyautogui 📄 https://wikidocs.net/85581

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pyautogui 
import sys

x = sys.argv[1]
y = sys.argv[2]

def move_mouse(x, y):
    pyautogui.moveTo(x, y)
    print(x, y)

if __name__ == '__main__':
    // 파이썬 파일 실행  바로 실행됨
    x = sys.argv[1]
    y = sys.argv[2]
    print(x, y)
    pyautogui.moveTo(x, y)

노드에서 파이썬 실행을 위한 노드 기본 내장 모듈 child_process 📄 https://curryyou.tistory.com/225

1
2
3
4
const result = cp.spawn('python', ['test.py'], x, y);
  result.stdout.on('data', (result)=>{
    console.log(result.toString());
});

x, y 좌표가 생길때마다 바로 파이썬 파일을 실행시켜보기도 하고, 파이썬 실행을 연결한 api를 만들어 이를 호출하는 식으로도 해봤는데 안된다.. (.py의 로그는 남는데 마우스 조작이 안됐던걸로 기억)

노드 마우스 커서 조작하기 robotjs

📄 RobotJS - Node.js Desktop Automation http://robotjs.io/ image

파이썬 라이브러리 쓰다 생각난.. 노드.. 노드에도 비슷한 라이브러리가 있지 않을까하고 찾아보다 발견한 모듈 robotjs

1
npm install robotjs

공식 문서에 나와있는 코드 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var robot = require("robotjs");
 
// Speed up the mouse.
robot.setMouseDelay(2);
 
var twoPI = Math.PI * 2.0;
var screenSize = robot.getScreenSize();
var height = (screenSize.height / 2) - 10;
var width = screenSize.width;
 
for (var x = 0; x < width; x++) {
    y = height * Math.sin((twoPI * x) / width) + height;
    robot.moveMouse(x, y);
}

실행하면 마우스 커서를 움직이지 않아도 혼자 빙글빙글 돈다!
이제 미디어파이프를 통해 얻은 검지손가락의 x와 y의 좌표를 robotjs의 moveMouse 메서드로 넘겨주면 되는데..

1
2
3
4
5
6
7
8
9
10
11
12
13
var robot = require("robotjs");

function move(x, y) {

    var screenSize = robot.getScreenSize();
    var height = (screenSize.height / 2) - 10;
    var width = screenSize.width;

    x = x * width;
    y = y * height;

    robot.moveMouse(x, y);
}

여기서부터는 마주친 문제들

  1. 이상하게 html파일에서 스크립트가 안불러와진다.. image

  2. 기억이 잘 안나지만 위의 문제를 어찌어찌 해결했는데 이번엔 스크립트 파일의 require가 안먹는다.
    ReferenceError: require is not defined.

    🙆‍♀️ 참고 https://stackoverflow.com/questions/50011068/javascript-require-doesnt-work-inside-html
    노드 실행이 아니라 브라우저에 스크립트로 불러왔을 때는 require()를 못쓰는것 같다.

  3. 파이썬 연동할때처럼 api 호출방식으로 바꿔봤다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
     app.post('/robo', (req, res) => {
    
         var screenSize = robot.getScreenSize();
         var height = (screenSize.height / 2) - 10;
         var width = screenSize.width;
         var x = req.body['locx'] * width;
         var y = req.body['locy'] * height;
            
         console.log(x, y);
            
         robot.moveMouse(x, y);
     });
    

    되긴하는데.. 처음에 잠깐 버벅이고 그게 끝이다.. 사실 하면서도 실시간으로 마우스 위치가 변해야하는걸 api 요청으로 처리하는게 맞나 싶긴 했다.

  4. 미디어파이프처럼 cdn으로 robotjs를 읽어오려고 하였지만 이 방법도 실패
    🤷🏼‍♀️ https://www.jsdelivr.com/package/npm/robotjs?tab=collection

    1
    
     <script src="https://cdn.jsdelivr.net/npm/robotjs@0.6.0/index.min.js"></script>
    

    그러다 생각난 방법이 바로 소켓 통신!!

노드 socket.io 실시간 통신

1
npm install socket.io

📄 Nodejs 서버에서 Socket.IO로 실시간 통신하기 https://fred16157.github.io/node.js/nodejs-socketio-communication-basic/

위의 블로그를 따라하며 감을 좀 잡고 필요한 부분만 골라서 썼다.

  1. app.js 수정 및 추가
    모듈 require 추가
    1
    2
    
     var robot = require("robotjs");
     var io = require('socket.io')(server);
    

    앱과 소켓 서버 생성

    1
    2
    3
    4
    
     const port = 3000;
     const app = express();
     var server = require('http').createServer(app);
     var io = require('socket.io')(server);
    

    서버 구동

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     // 이전 app 실행 코드
     app.listen(port, () => {
     console.log(`Server is Running! http://localhost:${port}`)
     });
    
     // 바뀐 코드
     server.listen(3000, function() {
     console.log(`Server is Running! http://localhost:${port}`);
     });
    
  2. 클라이언트에서 서버로 미디어파이프 결과값 전달
    socket.io 스크립트 태그 추가
    1
    
     <script src="/socket.io/socket.io.js"></script>
    

    서버 데이터 전송 스크립트

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
     var socket = io();
    
     ...
    
     function onResults(results) {
            
         // 이전과 동일
    
         drawConnectors(canvasCtx, landmarks, HAND_CONNECTIONS, {color: '#4badb3', lineWidth: 5});
         drawLandmarks(canvasCtx, landmarks, {color: '#e04e04', lineWidth: 2});
    
         var x = landmarks[8]['x']; // 검지손가락의 좌표(전체 대비 비율값으로 나옴)
         var y = landmarks[8]['y'];
         var location = [x, y];
    
         socket.emit('location', location); // 소켓 이용하여 위치 정보 전달
            
         ...
     }
    
  3. 서버(node)에서 robotjs를 이용해 마우스 조작
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
     io.on('connection', (socket) => { // 소켓 연결이 들어오면 실행
     // 클라이언트에서 수신받은 정보
     socket.on('location', (msg) => {
         // console.log('Message received: ' + msg);
    
         var screenSize = robot.getScreenSize();
         var height = (screenSize.height / 2) - 10;
         var width = screenSize.width;
    
         // 마우스 커서 이동시킬 좌표
         var x = (width - msg[0] * width);
         var y = msg[1] * height;
    
         robot.moveMouse(x, y);
     });
     });
    

    마우스 커서의 이동할 위치를 설정할 때 전체 가로 길이에서 전달받은 가로 길이를 빼는 이유는 카메라를 좌우반전한 상태로 쓰고있기 때문


결과는 두둥


허허 성공했다 드디어 🥳



다행히 회의 전까지 끝내서 팀원들에게 행복하고 뿌듯한 마음으로 공유할 수 있었다..
현지도 지난 회의때 더 해보기로했던 캔버스 위 메뉴판 레이아웃과 나아가 선택하는 모션 인식까지 성공했다!
커서 이동도 안되고 동적 제스처 모델학습이 안되서 눈앞이 깜깜하고 요 며칠 너무 스트레스였는데.. 어찌저찌 잘 풀려서 증말 다행ㅠㅠ
시험 끝나고 어서 주문 시스템 기능 개발을 마무리져야겠다.
오늘은 블로그 쓰고 깃 정리하고 엄마랑 아란이랑 장보고 하루 끝!

아 깃 주소도 올려야쥥 ✏️ https://github.com/ijo0r98/capstone

This post is licensed under CC BY 4.0 by the author.

캡스톤일지 | ~ 10.13 미디어파이프 이용한 정적제스처 인식과 문제 발생

캡스톤일지 | ~ 10.21 NodeJS TDD 웹개발 훑어보기(2)