API 마우스

IT/개발공부 / / 2020. 9. 10. 20:53
728x90
반응형

마우스 관련 정보

윈도우 환경에서 사용되는 각종요소들의 크기 및 환경 설정 값을 얻을 때는 아래의 함수를 사용합니다.

int GetSystemMetrics(int nIndex);

nIndex 값에 다라 다양한 정보도 얻을 수 있습니다. 마우스 관련 정보를 얻기 위해서는 아래의 상수값 들을 사용하면 됩니다.

 

nIndex Description
SM_MOUSEPRESENT 마우스가 존재 하지 않으면 0, 존재하면 0이 아닌 값이 리턴 된다.
SM_MOUSEWHEELPRESENT 마우스 휠이 존재하면 0 아닌 값이 리턴된다.
SM_CMOUSEBUTTONS 마우스 버튼의 개수가 리턴된다.
SM_CX(CY)DOUBLECLK 더블 클릭으로 처리되는 간격이 리턴된다.
case WM_LBUTTONDOWN:
   {
      BOOL bPresent = GetSystemMetrics(SM_MOUSEPRESENT);
      BOOL bWheel = GetSystemMetrics(SM_MOUSEWHEELPRESENT);
      int nBtn = GetSystemMetrics(SM_CMOUSEBUTTONS);
      int scx = GetSystemMetrics( SM_CXSCREEN );
      int scy = GetSystemMetrics( SM_CYSCREEN );
      TCHAR info[128];
      wsprintf( info, _TEXT("%s %s is installed. (%d Buttons)\n"),
      (bWheel ? _TEXT("Wheel") : _TEXT("") ),
         ( bPresent ? _TEXT("Mouse") : _TEXT("No Mouse" )), nBtn);
      TCHAR temp[64];
      wsprintf( temp, _TEXT("\nScreen Resolution : %d * %d"), scx, scy);
      wcscat( info, temp);
      MessageBox(NULL, info , TEXT(""), MB_OK);
   }
   return 0;

위 소스는 시스템 정보를 얻어오는 예제입니다.

 

윈도우의 명칭

윈도우의 명칭

윈도우는 크게 Client 영역과 Non-Client 영역으로 나눌 수 있습니다.

Clinet 영역 사용자로부터 마우스, 키보드 입력을 받고 사용자에게 출력을 보여주기 위한 영역
Non Client 영역 Client 이외의 영역
캡션바, 메뉴, 최대화, 최소화, 닫기버튼, 스크롤바, 상태바, 등으로 구성된다.

 

마우스 메시지

마우스 메시지의 종류

마우스 메시지는 크게 Client 영역 메시지와 Non-Client 영역 메시지로 구분할 수 있습니다.

Client 영역 메시지 Non Client 영역 메시지 기타
WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBLCLK WM_RBUTTONDOWN WM_RBUTTONUP WM_RBUTTONDBLCLK WM_MBUTTONDOWN WM_MBUTTONUP WM_MBUTTONDBLCLK WM_MOUSEMOVE WM_NCLBUTTONDOWN WM_NCLBUTTONUP WM_NCLBUTTONDBLCLK WM_NCRBUTTONDOWN WM_NCRBUTTONUP WM_NCRBUTTONDBLCLK WM_NCMBUTTONDOWN WM_NCMBUTTONUP WM_NCMBUTTONDBLCLK WM_NCMOUSEMOVE WM_NCHITTEST
WM_MOUSEWHEEL

 

더블 클릭 메시지 발생하기

OS가 더블 클릭 메시지를 발생하려면 많은 비용이 듭니다. 그래서 더블클릭 멧지ㅣ는 기본적으로는 발생하지 않습니다. 특정 윈도우를 만들고 더블클릭 메시지를 받고 싶다면 아래처럼 클래스 스타일을 변경해야 합니다.

WNDCLASS wc;

……

wc.style = CS_DBLCLKS; // 더블클릭 메시지를 나오게 하는 클래스 스타일
RegisterClass(&wc);

 

마우스 부가 정보(클라이언트 영역)

마우스 메시지가 발생할 때 IParam에는 메시지 발생 당시의 마우스 좌표가 들어 있습니다. 상위 16비트에는 Y 좌표가 하위 16비트에는 X 좌표가 들어있습니다.

 

또한 클라이언트 영영 마우스 메시지일 경우 클라이언트 좌표로, 비클라이언트 영역 메시지일경우에는 스크린 좌표로 들어옵니다. 아래의 매크로를 사용하면 IParam으로 부터 쉽게 x,y 좌표를 얻을 수 있습니다.

 

IParam

POINTS pt = MAKEPOINTS(lParam);
----------------------------------
int x = LOWORD(lParam);
int y = HIWORD(lParam);

wParam에는 마우스 버튼의 상태와 키보드 조합 키(Shift, Ctrl)의 상태가 전달됩니다. 조합키 상태는 다음 값들과 비트 연산을 해보면 알 수 있습니다.

설명
MK_CONTROL Ctrl 키가 눌러져 있다.
MK_LBUTTON 마우스 왼쪽 버튼이 눌러져 있다.
MK_RBUTTON 마우스 오른쪽 버튼이 눌러져 있다.
MK_MBUTTON 마우스 중간 버튼이 눌러져 있다.
MK_SHIFT Shift 키가 눌러져 있다.

 

case WM_LBUTTONDOWN:
   {
      POINTS pt = MAKEPOINTS(lParam);
      POINT pt1 = { LOWORD(lParam),HIWORD(lParam)};
      TCHAR buf[50];
      wsprintf(buf, TEXT("(%d:%d)\r\n(%d:%d)"), pt.x, pt.y, pt1.x, pt1.y);
      MessageBox(NULL, buf, TEXT(""), MB_OK);
   }

case WM_RBUTTONDOWN:
   {
      if(wParam & MK_SHIFT)
      {
         MessageBox(NULL, TEXT("RBUTTON+SHIFT"), TEXT(""), MB_OK);
      }
      else if(wParam & MK_CONTROL)
      {
         MessageBox(NULL, TEXT("RBUTTON+CONTROL"), TEXT(""), MB_OK);
      }
}

위의 예제는 마우스 왼쪽 클릭시 좌표를 출력해주고 오른쪽 버튼과 컨트롤 조합키 클릭시 메시지를 출력해주는 예제입니다.

 

마우스 캡쳐

일반적으로 마우스 메시지는, 메시지가 발생할 당시 커서의 아래 있는 윈도우에게 전달됩니다. 하지만 SetCapture() 함수를 사용 하므로서 이런 행동을 변경할 수 있습니다. 특정 윈도우가 SetCapture() 함수를 사용해서 마우스를 캡쳐할 경우, 모든 마우스 메시지는 마우스를 캡쳐한 윈도우에게로 전달됩니다.

 

마우스 캡쳐 해제하기

마우스 캡쳐는 아래의 3가지 경우에 해지됩니다.

  • ReleaseCapture()함수를 호출 할 경우
  • 다른 윈도우가 마우스를 캡쳐 할 경우
  • 사용자가 다른 스레드가 만든 윈도우를 클릭 할 경우

마우스 캡쳐가 해지될 경우, 캡쳐를 잃은 윈도우에 WM_CAPTURECHANGED 메시지가 전달됩니다. 이때 IParam에는 새롭게 마우스 캡쳐 한 윈도우의 핸들이 들어 있습니다.

 

 

마우스 캡쳐 종류

  • Foreground Capture : Foreground 윈도우가 마우스를 캡쳐 한 경우, 모든 윈도우에서 발생한 마우스 메시지를 받을 수 있습니다.
  • Background Capture : Background 윈도우가 마우스를 캡쳐 할 경우, 동일 스레드 내의 마우스 메시지만을 받을 수 있습니다.

 

마우스 캡쳐는 커서가 윈도우를 벗어나더라도 계속 메시지를 받고자 할때 유용하게 사용됩니다. 주소 BUTTONDOWN에서 캡쳐를 BUTTONUP에서 Release를 해줍니다.

현재 어떤 윈도우가 캡쳐를 했는지를 알아내려면 GetCapture() 함수를 사용합니다.

마우스가 캡쳐 되어 있을 경우 WM_NCHITTEST, WM_SETCURSOR 메시지는 발생되지 않습니다.

 

void PrintWindowInfo( HWND hwnd )
{
   TCHAR Info[1024] = {0};
   TCHAR temp[256];
   RECT rcWin;
   GetClassName( hwnd, temp, 256);
   wsprintf( Info, TEXT("Window Class : %s\n"), temp);
   GetWindowText( hwnd, temp,256);
   wsprintf( Info + wcslen(Info), TEXT("Window Caption : %s\n"), temp);
   GetWindowRect( hwnd, &rcWin );
   wsprintf( Info + wcslen(Info), TEXT("Window Position : (%d,%d)-(%d,%d)"),
   rcWin.left, rcWin.top, rcWin.right, rcWin.bottom);
   MessageBox( 0, Info, TEXT("Window Info"), MB_OK);
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch( msg )
   {
   case WM_LBUTTONDOWN:
      SetCapture( hwnd );
      return 0;
      
   case WM_LBUTTONUP:
      if ( GetCapture() == hwnd )
      {
         ReleaseCapture();
         POINT pt;
         GetCursorPos( &pt );
         HWND hwndDest = WindowFromPoint( pt );
         PrintWindowInfo( hwndDest );
      }
      return 0;
   case WM_MOUSEMOVE:
   {
      short xPos, yPos;
      TCHAR temp[256];
      xPos = LOWORD(lParam);
      yPos = HIWORD(lParam);
      wsprintf( temp, TEXT("Cursor Position : (%d, %d)"), xPos, yPos);
      SetWindowText( hwnd, temp);
   }
   return 0;
728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기