웬디의 기묘한 이야기

글 작성자: WENDYS
반응형

마우스 후킹을 이용한 매크로 프로그램 제작

저번 포스팅에 이어 이번에도 마우스 후킹에 관련된 내용입니다.

아직 못 보셨다면 기본 마우스 후킹에 대한 내용을 보시고 보셔도 좋습니다.

https://wendys.tistory.com/107

 

[C/C++] 윈도우 메시지 후킹 마우스를 지배하는자 (windows mouse message hooking)

실전 윈도우 메시지 후킹 - 마우스를 지배하는 자 이제부터 실전입니다. 메시지 후킹에는 마우스 메시지, 키보드 메시지, 그 외 모든 윈도우 메시지를 가로챌 수 있습니다. 예를 들면 키보드 메시지 후킹을 이용한..

wendys.tistory.com

이번에는 저번 프로젝트에 이어서 마우스의 동작을 이용하여 스크롤 올리기 (HOME), 스크롤 내리기(END), 새로고침(F5), 화면 최대화, 화면 최소화, 화면 크기 복귀, 화면 닫기(Alt+F4) 등에 대한 처리를 해보도록 하겠습니다.

동작의 핵심은 오른쪽 마우스를 누른 상태에서 마우스의 액션을 감지하는 것에 있습니다.

 

예를 들어 오른쪽 마우스 누른 상태에서 마우스를 아래로 무브 하고 마우스를 떼면 에 대한 액션을 취하게 되고, 아래로 내리고 오른쪽으로 하게 되면 에 대한 정의된 액션을 취하게 되는 것이죠 잘 이해가 안 된다면 다음 영상을 한번 봐보시기 바랍니다.

 

 

처음엔 동작이 약간 헷갈릴 수도 있지만 익숙해지면 정말 편하게 이용하실 수 있습니다.

이제 left click event는 필요가 없어졌습니다. 오로지 right click event만을 사용하는 프로그램이 기 때문에 이제 필요한 이벤트는 WM_RBUTTONDOWN, WM_RBUTTONUP, WM_MOUSEMOVE 이 세 가지입니다.

 

이제 마우스 후킹의 콜백 함수에는 다음과 같은 코드를 이용하여 시작될 것입니다.

LRESULT hook_mouse_callback::new_function(
    __in int code,
    __in WPARAM wparam,
    __in LPARAM lparam
    ) {

    do {
        if (code < HC_ACTION) {
            break;
        }

        MOUSEHOOKSTRUCT* mouse_param = (MOUSEHOOKSTRUCT*)lparam;

        if (wparam == WM_RBUTTONDOWN) {

        }
        else if (wparam == WM_RBUTTONUP) {

        }
        else if (wparam == WM_MOUSEMOVE) {

        }
        else {
            break;
        }

    } while (false);

    return ::CallNextHookEx(_hook, code, wparam, lparam);
}

동작 순서를 말하자면

1. 오른쪽 마우스 다운 이벤트 발생 시 마우스 액션 캡처 시작

2. 오른쪽 마우스 다운 상태로 마우스 무브 시  방향에 대한 목록 작성

3. 오른쪽 마우스 업 이벤트 발생 시 방향 목록을 획득하여 그에 대한 액션 처리

 

??? : 이게 끝입니다. 참 쉽죠

 

그런 줄 알았으나 여기서 한 가지 문제가 발생합니다.

마우스 액션을 캡처하겠다는 건 알았는데 마우스가 움직이는 방향을 어떻게  형태로 획득하고 목록으로 작성을 할 수 있을까요??

 

1차 문제

방향을 잡기 위해선 시작 지점과 끝 지점이 있어야 한다입니다. 하지만 마우스는 이동이 너무나도 자유롭기 때문에 그것을 감지해내는 것에 아이디어가 필요합니다.

2차 문제

방향을 잡긴 잡겠는데 얼마만큼 이동했을 때 그것을 방향으로 인식을 하느냐도 문제입니다. 얼마만큼의 기준이 없다면 마우스를 한번 흔드는 것만으로 수십 개의 방향으로 인식이 될 수 있기 때문입니다.

 

해결방법

방향을 잡는 것보다 먼저 이동 거리를 계산하는 방법을 제시해드리겠습니다. 이는 정형화된 방법이 아닐 수 있지만 제가 이렇게 사용을 하기 때문에 알려드리는 방법이며, 이 외에도 여러 가지 방법이 존재할 것으로 예상됩니다.

일단 캡처를 시작할 때 현재 시작 POINT를 멤버 변수에 기록해놓습니다. _latest_mouse_point 가 되겠죠

그리고 오른쪽 마우스 다운 상태에서 마우스 MOVE시 current point와 _latest_mouse_point를 비교하게 되면 2차 문제였던 거리를 계산할 수 있게 됩니다. 2차 문제가 해결돼야 1차 문제를 해결할 수 있어요

 

개발자는 글로 보는 것보다 코드를 보는 게 더 직관적이니 코드로 한번 보겠습니다.

 

LRESULT hook_mouse_callback::new_function(
    __in int code,
    __in WPARAM wparam,
    __in LPARAM lparam
    ) {

    do {
        if (code < HC_ACTION) {
            break;
        }

        MOUSEHOOKSTRUCT* mouse_param = (MOUSEHOOKSTRUCT*)lparam;

        if (wparam == WM_RBUTTONDOWN) {
            _is_right_button_down = true;

            _latest_mouse_point = mouse_param->pt;
        }
        else if (wparam == WM_MOUSEMOVE) {
            if (_is_right_button_down) {

                POINT current_point = mouse_param->pt;

                double distance = get_distance(_latest_mouse_point, current_point);
                if (distance < 50) { // 거리가 50이상이어야 하나의 방향으로 감지
                    break;
                }

                //
                // 방향 결정 ← ↑ ↓ → 목록 추가 (ToDo.)
                //
				

                //
                // 기준 포인트를 현재 포인트로 변환
                //

                _latest_mouse_point = current_point;
            }
        }
        else if (wparam == WM_RBUTTONUP) {
            _is_right_button_down = false;
        }
        else {
            break;
        }

    } while (false);

    return ::CallNextHookEx(_hook, code, wparam, lparam);
}

current point와 latest point를 구했습니다. 이제 distance 값을 구하면 자신이 지정한 거리를 기준으로 삼을 수 있습니다.

그렇다면 distance를 구하는 방법은.. 다들 수학 잘하시니까 간단하게 구하실 수 있으리라 믿습니다.

근데 그걸 코드로 짜는 게 귀찮으실 테니 이걸 참고하시는 거죠?

inline double get_distance(
    __in const POINT p1, 
    __in const POINT p2
    ) {
    double distance = 0.0;
    distance = sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2));

    return distance;
}

생각보다 아주 간단합니다. 그렇다면 위의 코드에 이것만 추가해서 정말 길이가 잘 계산되는지 확인해볼까요??

 

아주 잘 나오네요 0은 시작 지점이니 MOUSE MOVE가 일어나기 전이라서 표시가 안 되는 게 맞고 마우스를 우클릭 상태로 쭉쭉 움직임에 따라 distance 값이 계속 증가하는 모습을 볼 수 있습니다.

 

Sample Download

처음부터 직접 개발을 하시면 좋겠지만 그렇지 않은분들은 아래 샘플 프로젝트를 통하여 이것저것 시도해보시길 바랍니다.

analog_note_mouse_hook.zip
0.07MB

 

반응형