2012-06-05

Mouse hook

(마우스 커서는 폼 밖에 있으나 x,y 좌표를 계속 받는다.)

풀소스 및 출처 : CodeSummoner, http://www.codeproject.com/Articles/28064/Global-Mouse-and-Keyboard-Library

keyboard와 mouse를 후킹 하는 라이브러리.

지난 번, keyboard hook과의 차이점은

keyboardHook.cs와 mouseHook.cs에서 globalHook.cs을 상속 받아 구현했다.
globalHook.cs에서 필요한 DllImport,
키보드 데이터 스트럭쳐와 마우스 데이터 스트럭쳐 정의,
후킹에 필요한 상수 정의,
후킹이 실행됬는지에 대한 Property정의,
Application.ApplicationExit+= new EventHandler(Application_ApplicationExit)으로 unhook() 함수를 대신하고
후킹의 콜백 프로시져는 HookCallbackProcedure로 가상 함수로 구현되었다.
SetWindowHookEx는 Hook()에서 Start()로 변경되었다.

테스트 실행에서 이미 디버깅되 실행파일로 나와 있는 샘플을 실행할 땐 정상 작동했으나, 직접 F5로 실행해보면 제대로 동작하지 못한다. 중간에 소스코드에 무슨 변화가 있던 것 같다.
임시로 hInstance가 Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]로 되어 있던 것을 LoadLibrary("User32")로 변경하면.. 일단 실행이 된다.

globalHook.cs에 마우스훅스트럭쳐를 보면 마우스 좌표를 기억하기 위한 point형을 사용하고 있다.

        protected class MouseLLHookStruct // MSDN MSLLHOOKSTRUCT와 동일
        {
            public POINT pt;  //마우스 좌표
            public int mouseData; // 메세지가 WM_MOUSEWHEEL일 경우, 휠을 움직인 델타값. X-button일 경우 어떤 X-button인지 저장.
            public int flags; // event injected 플래그
            public int time; // 메시지에 대한 time stamp, 키보드훅과 동일
            public int dwExtraInfo; // additional inform(?), MSDN에는 UintPtr type을 쓴다.
        }


        protected class POINT
        {
            public int x;
            public int y;
        }


mouseHook.cs에 overriding된 훅 프로시져(HookCallbackProcedure)의 내용은 크게 MouseButtons 객체에 후킹된 버튼 기억, 유저 어플리케이션에 전달될 MouseEventArgs 정의, 후킹된 이벤트에 따라 유저 어플리케이션으로 이밴트 발생이 있다.



protected override int HookCallbackProcedure(int nCode, int wParam, IntPtr lParam)
// nCode는 후킹할 대상, WH_MOUSE_LL (=14)

// wParam에는 마우스 메시지가..
// lParam에는 마우스의 훅 정보가 담긴 스트럭쳐의 포인터 (여기서는 MouseLLHookStruct)

MouseButtons button = GetButton(wParam); // 마우스 버튼 객체 정의

// MouseEventArgs 정의
MouseEventArgs e = new MouseEventArgs(
                    button,
                    (eventType == MouseEventType.DoubleClick ? 2 : 1),
                    mouseHookStruct.pt.x,
                    mouseHookStruct.pt.y,
                    (eventType == MouseEventType.MouseWheel ? (short)((mouseHookStruct.mouseData >> 16) & 0xffff) : 0));



        private MouseButtons GetButton(Int32 wParam) // case에 따라  "Left", "Right", "Middle", "None"을 return, MouseEventArgs.Button property에 기록된다.
        {

            switch (wParam)
            {

                case WM_LBUTTONDOWN:
                case WM_LBUTTONUP:
                case WM_LBUTTONDBLCLK:
                    return MouseButtons.Left;
                case WM_RBUTTONDOWN:
                case WM_RBUTTONUP:
                case WM_RBUTTONDBLCLK:
                    return MouseButtons.Right;
                case WM_MBUTTONDOWN:
                case WM_MBUTTONUP:
                case WM_MBUTTONDBLCLK:
                    return MouseButtons.Middle;
                default:
                    return MouseButtons.None;

            }

        }




유저 어플리케이션에서 이 라이브러리를 사용하는 방법은 지난 번 키보드 훅을 사용할 때와 같다.
MouseHook 객체를 생성하고, 생성한 객체의 이밴트에 이밴트핸들러를 추가하고, 어떤 일을 할지 이밴트핸들러를 정의해주면 된다.

using MouseKeyboardLibrary; //네임스페이스 사용
MouseHook mh = new MouseHook(); 마우스 훅 인스턴스 생성


mh.MouseMove += new MouseEventHandler(mh_MouseMove); //MouseHook에 정의된 이벤트에 유저 이벤트핸들러 추가
mh.MouseDown += new MouseEventHandler(mh_mousedown); //마우스 버튼 관련 이밴트 핸들러 추가
mh.Start(); // 마우스 훅 시작.



        private void mh_MouseMove(object sender,MouseEventArgs e) // 이벤트핸들러 구성
        {
            xyCoordinator(e.X, e.Y); //좌표 표시용 함수 호출
            textBox3.Text = mh.IsStarted.ToString(); //test, 후킹 중인지 상태 표시
        }

        private void xyCoordinator(int x, int y) //좌표 표시용 함수
        {
            textBox1.Text = String.Format("x= {0}", x);
            textBox2.Text = String.Format("y= {0}", y);
        }

        private void mh_mousedown(object sender, MouseEventArgs e)
        {
            textBox3.Text = e.Button.ToString(); // "Left" or "Right" 누른 마우스 버튼 표시
        }






댓글 없음:

댓글 쓰기