다음을 통해 공유


기타 마우스 작업

이전 섹션에서는 마우스 클릭 및 마우스 이동에 대해 설명했습니다. 마우스로 수행할 수 있는 몇 가지 다른 작업은 다음과 같습니다.

UI 요소 끌기

UI가 UI 요소의 끌기를 지원하는 경우 마우스 내리기 메시지 처리기에서 호출해야 하는 다른 함수인 DragDetect가 있습니다. DragDetect 함수는 사용자가 끌기로 해석되어야 하는 마우스 제스처를 시작하면 TRUE를 반환합니다. 다음 코드에서는 이 함수를 사용하는 방법을 보여 줍니다.

    case WM_LBUTTONDOWN: 
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            if (DragDetect(m_hwnd, pt))
            {
                // Start dragging.
            }
        }
        return 0;

프로그램이 끌어서 놓기를 지원하는 경우 모든 마우스 클릭이 끌기로 해석되지 않도록 하려고 합니다. 그렇지 않으면 사용자가 단순히 클릭하려고 하다가(예: 선택하기 위해) 실수로 무언가를 끌 수도 있습니다. 그러나 마우스가 특히 민감한 경우 클릭하는 동안 마우스를 완벽하게 유지하기가 어려울 수 있습니다. 따라서 Windows는 몇 픽셀의 끌기 임계값을 정의합니다. 사용자가 마우스 단추를 누르면 마우스가 이 임계값을 초과하지 않는 한, 끌기로 간주되지 않습니다. DragDetect 함수는 이 임계값에 도달했는지 여부를 테스트합니다. 이 함수가 TRUE를 반환하는 경우 마우스 클릭을 끌기로 해석할 수 있습니다. 그렇지 않으면 끌기로 해석하지 않습니다.

참고

DragDetectFALSE를 반환하면 사용자가 마우스 단추를 놓을 때 Windows에서 WM_LBUTTONUP 메시지를 표시하지 않습니다. 따라서 프로그램이 현재 끌기를 지원하는 모드에 있지 않으면 DragDetect를 호출하지 마세요. (예를 들어 끌 수 있는 UI 요소가 이미 선택된 경우). 이 모듈의 끝에 DragDetect 함수를 사용하는 더 긴 코드 예제가 표시됩니다.

 

커서 제한

경우에 따라 커서를 클라이언트 영역 또는 클라이언트 영역의 일부로 제한하려고 할 수 있습니다. ClipCursor 함수는 커서의 이동을 지정된 사각형으로 제한합니다. 이 사각형은 클라이언트 좌표가 아닌 화면 좌표로 제공되므로 점 (0, 0)은 화면의 왼쪽 위 모서리를 의미합니다. 클라이언트 좌표를 화면 좌표로 변환하려면 ClientToScreen 함수를 호출합니다.

다음 코드는 커서를 창의 클라이언트 영역으로 제한합니다.

    // Get the window client area.
    RECT rc;
    GetClientRect(m_hwnd, &rc);

    // Convert the client area to screen coordinates.
    POINT pt = { rc.left, rc.top };
    POINT pt2 = { rc.right, rc.bottom };
    ClientToScreen(m_hwnd, &pt);
    ClientToScreen(m_hwnd, &pt2);
    SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);

    // Confine the cursor.
    ClipCursor(&rc);

ClipCursorRECT 구조체를 사용하지만 ClientToScreenPOINT 구조체를 사용합니다. 사각형은 왼쪽 위 점과 오른쪽 아래 점으로 정의됩니다. 커서를 창 외부 영역을 포함하는 사각형 영역으로 제한할 수 있지만 커서를 클라이언트 영역으로 제한하는 것이 함수를 사용하는 일반적인 방법입니다. 커서를 창 외부의 영역으로 제한하는 것은 비정상적이며 사용자는 이를 버그로 인식할 수 있습니다.

이러한 제한을 제거하려면 값이 NULLClipCursor를 호출합니다.

ClipCursor(NULL);

마우스 추적 이벤트: 마우스로 가리키기 및 이동하기

다른 두 개의 마우스 메시지는 기본적으로 사용하지 않도록 설정되지만 일부 애플리케이션에 유용할 수 있습니다.

  • WM_MOUSEHOVER: 커서를 고정된 기간 동안 클라이언트 영역 위에 두었습니다.
  • WM_MOUSELEAVE: 커서를 클라이언트 영역을 밖으로 이동했습니다.

이러한 메시지를 사용하도록 설정하려면 TrackMouseEvent 함수를 호출합니다.

    TRACKMOUSEEVENT tme;
    tme.cbSize = sizeof(tme);
    tme.hwndTrack = hwnd;
    tme.dwFlags = TME_HOVER | TME_LEAVE;
    tme.dwHoverTime = HOVER_DEFAULT;
    TrackMouseEvent(&tme);

TRACKMOUSEEVENT 구조체에는 함수에 대한 매개 변수가 포함되어 있습니다. 구조체의 dwFlags 멤버에는 관심 있는 추적 메시지를 지정하는 비트 플래그가 포함되어 있습니다. 여기에 표시된 대로 WM_MOUSEHOVERWM_MOUSELEAVE 둘 다 또는 둘 중 하나만 가져오도록 선택할 수 있습니다. dwHoverTime 멤버는 시스템이 가리키기 메시지를 생성하기 전에 마우스로 가리켜야 하는 시간을 지정합니다. 이 값은 밀리초 단위로 지정됩니다. 상수 HOVER_DEFAULT는 시스템 기본값을 사용하는 것을 의미합니다.

요청한 메시지 중 하나가 표시되면 TrackMouseEvent 함수가 다시 설정됩니다. 다른 추적 메시지를 가져오려면 다시 호출해야 합니다. 그러나 TrackMouseEvent를 다시 호출하기 전에 다음 마우스 이동 메시지까지 기다려야 합니다. 그렇지 않으면 창이 추적 메시지로 넘쳐나게 될 수 있습니다. 예를 들어 마우스로 가리키면 마우스가 고정된 동안 시스템에서 WM_MOUSEHOVER 메시지 스트림을 계속 생성합니다. 마우스를 다른 지점으로 이동하고 다시 마우스로 가리키기 전까지는 다른 WM_MOUSEHOVER 메시지를 원하지 않을 것입니다.

다음은 마우스 추적 이벤트를 관리하는 데 사용할 수 있는 작은 도우미 클래스입니다.

class MouseTrackEvents
{
    bool m_bMouseTracking;

public:
    MouseTrackEvents() : m_bMouseTracking(false)
    {
    }
    
    void OnMouseMove(HWND hwnd)
    {
        if (!m_bMouseTracking)
        {
            // Enable mouse tracking.
            TRACKMOUSEEVENT tme;
            tme.cbSize = sizeof(tme);
            tme.hwndTrack = hwnd;
            tme.dwFlags = TME_HOVER | TME_LEAVE;
            tme.dwHoverTime = HOVER_DEFAULT;
            TrackMouseEvent(&tme);
            m_bMouseTracking = true;
        }
    }
    void Reset(HWND hwnd)
    {
        m_bMouseTracking = false;
    }
};

다음 예제에서는 창 프로시저에서 이 클래스를 사용하는 방법을 보여 줍니다.

LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_MOUSEMOVE:
        mouseTrack.OnMouseMove(m_hwnd);  // Start tracking.

        // TODO: Handle the mouse-move message.

        return 0;

    case WM_MOUSELEAVE:

        // TODO: Handle the mouse-leave message.

        mouseTrack.Reset(m_hwnd);
        return 0;

    case WM_MOUSEHOVER:

        // TODO: Handle the mouse-hover message.

        mouseTrack.Reset(m_hwnd);
        return 0;

    }
    return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}

마우스 추적 이벤트에는 시스템의 추가 처리가 필요하므로 필요하지 않을 때는 사용하지 않도록 설정합니다.

완전히 하기 위해 시스템에 기본 가리키기 시간 제한을 쿼리하는 함수는 다음과 같습니다.

UINT GetMouseHoverTime()
{
    UINT msec; 
    if (SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &msec, 0))
    {   
        return msec;
    }
    else
    {
        return 0;
    }
}

마우스 휠

다음 함수는 마우스 휠이 있는지 여부를 확인합니다.

BOOL IsMouseWheelPresent()
{
    return (GetSystemMetrics(SM_MOUSEWHEELPRESENT) != 0);
}

사용자가 마우스 휠을 회전하면 포커스가 있는 창에 WM_MOUSEWHEEL 메시지가 표시됩니다. 이 메시지의 wParam 매개 변수에는 휠이 회전된 정도를 측정하는 ‘델타’라는 정수 값이 포함되어 있습니다. 델타는 임의의 단위를 사용합니다. 여기서 120개 단위는 하나의 "작업"을 수행하는 데 필요한 회전으로 정의됩니다. 물론 작업의 정의는 프로그램에 따라 달라집니다. 예를 들어 마우스 휠을 사용하여 텍스트를 스크롤하는 경우 각 120개 회전 단위는 텍스트 한 줄을 스크롤합니다.

델타의 부호는 회전 방향을 나타냅니다.

  • 양수: 사용자 반대쪽으로 앞으로 회전합니다.
  • 음수: 사용자 쪽으로 뒤로 회전합니다.

델타의 값은 몇 가지 추가 플래그와 함께 wParam에 배치됩니다. GET_WHEEL_DELTA_WPARAM 매크로를 사용하여 델타의 값을 가져옵니다.

int delta = GET_WHEEL_DELTA_WPARAM(wParam);

마우스 휠의 해상도가 높은 경우 델타의 절대값은 120보다 작을 수 있습니다. 이 경우 작업이 더 작은 증분으로 진행될 수 있다면 그렇게 할 수 있습니다. 예를 들어 텍스트가 한 줄보다 작은 증분만큼 스크롤할 수 있습니다. 그렇지 않으면 휠이 작업을 수행할 만큼 충분히 회전할 때까지 총 델타를 누적합니다. 사용하지 않는 델타를 변수에 저장하고 120개 단위가 누적되면(양수 또는 음수) 작업을 수행합니다.

다음

키보드 입력