ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [9] - Mouse
    Graphics 2021. 7. 12. 22:57

    Keyboard와 닮은 부분이 많습니다. Inner Class로 Event를 가지고 있다는 점, Copy assignment, Copy constructor가 배제되어 있다는 점까지 같습니다. 역시. Event를 받는 FIFO Queue를 가지고 있습니다. 

    Mouse를 위한 상태 변수( State Variable )를 몇 개 갖고 있습니다. 마우스 커서의 X, Y위치, 왼쪽/오른쪽 버튼의 상태입니다. Event를 위한 Queue는 키보드와는 다르게 단 하나만을 갖고 있습니다. 이유는 당연히 마우스에는 Character-Event의 구분이 없기 때문입니다. 

    Mouse Class 내의 Event Class의 Enumeration type class

    여러가지 마우스가 갖고 있을 수 있는 상태의 타입을 확인할 수 있습니다. 

    마우스의 위치를 각각 X, Y를 따로 받을 수도 있으나 pair로 받을 수도 있습니다. 그 외의 것들은 보는 즉시 이해가 됩니다. hw3d/hw3d at T8-End · planetchili/hw3d (github.com)/

     Keyboard와 마찬가지로 Mouse도 사용을 하려면 Window class에 Instance를 만들어 주어야 합니다. Mouse의 활성화와 사용 역시 HandleMsg함수가 될 것입니다. 키보드와 함께.

    WM_MOUSEMOVE에 대한 MSDN의 문서

    WM_MOUSEMOVE나 기타 등등은 대체로 이해하기 쉽습니다. 다만 WM_MOUSEWHEEL은 조금 특별한 Message입니다. WM_MOUSEWHEEL message (Winuser.h) - Win32 apps | Microsoft Docs

    마우스 휠을 떠올려보면 굴러갈 때마다 생기는 변화량이 있습니다. 그리고 이 값은 wParam에 존재하고 그 값을 unpack했을 때 양수라면 위로, 음수라면 아래로 굴러갔다는 것을 암시합니다. 물론 이 wParam이 양수, 음수를 나타내는 것은 아니고 매크로의 계산 결과가 그렇다는 것입니다. 이제 키보드와 마우스를 다룰 방법이 생겼으니 당장 무언가를 해보는 게 좋겠습니다. 이런 걸 해보도록 하겠습니다. 마우스를 움직일 때마다 그 좌표를 Title로 설정하는 겁니다.

    잘 동작합니다

    About Cursor

    창모드로 게임을 하고 있다는 가정을 하겠습니다. 종종 우리는 마우스가 Client영역 밖으로 나가는 때를 마주할 수 있습니다. 이때 행동을 정의하는 것도 필요합니다. 이 ChiliFrameWork에서는 그런 경우에 두 가지의 행동을 정의했습니다.

    일단 마우스가 Client 영역 내부 존재 여부에 관련하는 몇 개의 함수가 있습니다. IsInWindow, OnMouseLeave, OnMouseEnter. 당연히 이름으로부터 IsInWindow가 마우스가 Client 영역 안에 있는지 없는지 확인해줄 것이라고 기대할 수 있습니다. 만약 마우스가 Client를 빠져나가면 OnMouseLeave가 호출되고 반대의 경우엔 OnMouseEnter가 호출될 것입니다. 

    lParam에서 마우스에 관련한 정보를 뽑아오고 마우스의 좌표를 계산하여 Client 영역 내에 존재 여부를 확인합니다. 만약, 마우스가 Client 영역 내부에 있다면 다시 이 마우스가 영역 밖에서 되돌아온 것인지 아니면 원래 존재했던 것인지 판단합니다. SetCapture은 Windows API로 MSDN에 잘 설명되어 있습니다. SetCapture function (winuser.h) - Win32 apps | Microsoft Docs

    else에선 마우스가 Client 영역에 존재하지 않을 경우를 처리합니다. 어떻게 되었든 마우스는 Client를 떠나버렸는데 그 직전의 마우스가 버튼이 눌린 상태였는가? 바로 이걸 확인해줍니다. 사실 정의된 MK_LBUTTON | MK_RBUTTON을 사용할 수 있지만 이왕이면 만든 함수를 다시 사용하는 것이 기쁜 일이겠지요? 그래서 각 값을 MASK로 사용해서 wParam으로부터 어떤 버튼이 눌려있었는지 확인합니다. 만약 눌려 있었다면 계속 위치 정보를 받으며 마우스를 따라갑니다. 반대로 아무것도 누르지 않은 채로 Client 영역을 떠났다면 더 이상 마우스의 정보를 받지 않게 됩니다. 실험까지 진행합시다.

    어차피 Enter 이후에 바로 마우스의 움직임에 대한 함수가 실행되기 때문에 Type::Enter에 대한 처리는 하는 것과 안 하는 것에 거의 차이를 느낄 수 없습니다
    잘 됩니다

    마우스를 질질 끌어보기도 하고 그냥 나가보기도 하면 모두 정상 작동 됩니다.

    Mouse Wheel Message

    위에서 마우스의 휠은 조금 특별하다고 했습니다. 상위 16bits는 휠이 회전한 거리를 나타냅니다. 보통 120이라는 값으로 정해져 있는데 어떤 Resolution(특히 Finer-Resolution)에서는 같은 거리를 가더라도 더 많은 회전을 요구할 가능성이 있습니다. 마우스의 휠의 감도라고 생각하면 편합니다. 반대로 60만 가면 되는데 120을 돌리고 있을 가능성 역시 존재합니다. 또, 어떤 마우스의 휠은 한 번만 돌려도 120을 가는데 어떤 마우스는 120을 못 갈 수도 있습니다. 따라서 정확하게 그리고 보편적으로 마우스의 휠을 사용하려면 WHEEL_DELTA_WPARAM이라는 값을 확인해야 합니다. 그리고 이 값이 기본적으로 120이나 -120에 도달할 때까지 계속 더하는 겁니다. 

    이 WheelDeltaCarry에 계속 값을 축적하고 이 값이 일정 값에 이를 때 비로소 Event를 생성하기로 합니다. 또, OnWheelUp/OnWheelDown 말고 OnWheelDelta라는 함수를 추가로 생성합니다.

    보면 마우스의 x와 y의 좌표, delta 값을 받습니다. wheelDeltaCarry에 계속 delta값을 받다가 Threshold로 설정한 WHEEL_DELTA보다 크면 그때 비로소 OnWheelUp Event를 발생 시키는 것입니다. 이러면 Window.cpp에서 Message Handle의 Mouse 부분을 바꿔줄 필요가 생깁니다.

    아래처럼 바꾸면 됩니다

    실험까지 하면 좋겠습니다.

     

    'Graphics' 카테고리의 다른 글

    [11] - Space and transforms - 1  (0) 2021.07.13
    [10] - App class  (0) 2021.07.13
    [8] - Keyboard  (0) 2021.07.12
    [7] - ICON  (0) 2021.07.10
    [6] - Error Handling  (0) 2021.07.10
Designed by Tistory.