. 키보드 훅

훅 타입중에 개념적으로 가장 이해하기 쉽고 간단한 키보드 훅 프로시저를 작성해 보자. 다음 예제는 키보드 메시지를 훅킹하여 메시지에 대한 정보를 작업영역에 보여준다.

 

KeyHook

char Mes[]="키보드 테스트 프로그램입니다.";

char Mes2[128];

char Mes3[128];

int Count=0;

HHOOK hKeyHook;

LRESULT CALLBACK KeyHookProc(int nCode, WPARAM wParam, LPARAM lParam)

{

   if (nCode>=0) {

      InvalidateRect(hWndMain,NULL,TRUE);

      if (wParam == VK_F2) {

          wsprintf(Mes2,"F2 입력이 금지된 키입니다.");

          return 1;

      } else {

          wsprintf(Mes2,"nCode=%d, wParam=%u, lParam=%08x, Count=%d",

             nCode, wParam, lParam,Count++);

      }

   }

   return CallNextHookEx(hKeyHook,nCode,wParam,lParam);

}

 

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

   HDC hdc;

   PAINTSTRUCT ps;

 

   switch(iMessage) {

   case WM_CREATE:

      hKeyHook=SetWindowsHookEx(WH_KEYBOARD,KeyHookProc,NULL,GetCurrentThreadId());

      return 0;

   case WM_KEYDOWN:

      wsprintf(Mes3,"실제 받은 : %u",wParam);

      InvalidateRect(hWnd,NULL,TRUE);

      return 0;

   case WM_PAINT:

      hdc=BeginPaint(hWnd, &ps);

      TextOut(hdc,100,10,Mes,strlen(Mes));

      TextOut(hdc,100,30,Mes2,strlen(Mes2));

      TextOut(hdc,100,50,Mes3,strlen(Mes3));

      EndPaint(hWnd, &ps);

      return 0;

   case WM_DESTROY:

      UnhookWindowsHookEx(hKeyHook);

      PostQuitMessage(0);

      return 0;

   }

   return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}

 

실행 결과는 다음과 같다.

WM_CRAETE에서 SetWindowsHookEx 함수로 KeyHookProc 훅 프로시저를 WH_KEYBOARD 훅 타입의 훅 체인에 추가하였다. 현재 스레드의 ID를 주었으므로 자기 자신의 키보드 메시지만 감시하는 지역 훅이다. 사용자가 키보드를 누르거나 뗄 때 즉, WM_KEYDOWN, WM_KEYUP 메시지가 발생하면 KeyHookProc 훅 프로시저가 호출될 것이다. WM_DESTROY에서는 설치한 훅 프로시저를 해제하도록 했다.

훅 프로시저로 전달된 nCode 인수가 음수일 경우는 어떤 처리도 해서는 안 되며 곧바로 훅 체인의 다음 훅 프로시저로 메시지를 넘겨주어야 한다. 예제에서는 nCode가 0보다 크거나 같을 때만 메시지를 감시하도록 했다. 훅 프로시저는 전달된 메시지의 내용을 점검한 후 메시지를 변경하거나 없애버릴 수도 있고 아니면 그대로 체인의 다음 함수에게 전달할 수도 있다.

이 예제는 훅 프로시저가 특정 키입력을 거부할 수도 있다는 것을 보여 주기 위해 F2 키가 입력되었을 경우 0이 아닌 값(보통 1 또는 TRUE)을 리턴하여 이 키에 대한 입력 메시지가 다음 훅 프로시저로 전달되지 않도록 했다. 시스템은 훅 프로시저가 0이 아닌 값을 리턴하면 이 메시지를 중간에서 없애버리며 다음 훅 프로시저로 전달되지 않으므로 결국 목표 윈도우는 이 메시지를 받지 못하게 된다. F2가 아닌 경우는 어떤 키가 입력되었는지 wParam과 lParam에 대한 정보를 화면에 출력하도록 했다.

키보드 훅 프로시저는 WM_KEYDOWN, WM_KEYUP 메시지에 대해 호출되므로 키가 눌러지거나 떨어질 때 모두 호출된다. 만약 훅 프로시저내에서 키가 눌러진 것인지 떨어진 것인지를 구분하고 싶다면 lParam의 최상위 비트가 1인지 아닌지를 점검해 보면 된다. if ((lParam & 0x80000000)==0) 조건문이 참이면 WM_KEYDOWN 메시지가 전달된 것이고 거짓이면 WM_KEYUP이 전달된 것이다.

위 예제에서 훅 타입을 WH_MOUSE로 바꾸면 마우스 메시지를 훅킹할 것이다. 훅을 설치, 해제하는 방법은 동일하되 nCode 인수의 의미나 wParam, lParam으로 전달되는 추가 정보의 의미는 달라진다. 지역 훅은 사용 방법이 쉽고 별다른 제약 사항이나 주의 사항이 없어 위험하지도 않은 편이다.