다음을 통해 공유


고화질 마우스 이동 활용

표준 컴퓨터 마우스는 DPI(인치당 400개 점)로 데이터를 반환하는 반면, 고화질 마우스는 800DPI 이상의 데이터를 생성합니다. 이렇게 하면 고화질 마우스의 입력이 표준 마우스보다 훨씬 더 정확해집니다. 그러나 표준 WM_MOUSEMOVE 메시지를 통해 고화질 데이터를 가져올 수 없습니다. 일반적으로 게임은 고화질 마우스 디바이스의 이점을 누릴 수 있지만 WM_MOUSEMOVE 사용하여 마우스 데이터를 가져오는 게임은 마우스의 필터링되지 않은 전체 해상도에 액세스할 수 없습니다.

많은 회사에서 Microsoft 및 Logitech와 같은 고화질 마우스 디바이스를 제조하고 있습니다. 고해상도 마우스 디바이스의 인기가 높아짐에 따라 개발자는 이러한 디바이스에서 생성된 정보를 최적으로 사용하는 방법을 이해하는 것이 중요합니다. 이 문서에서는 1인칭 슈팅 게임과 같은 게임에서 고화질 마우스 입력의 성능을 최적화하는 가장 좋은 방법에 중점을 둡니다.

마우스 이동 데이터 검색

다음은 마우스 데이터를 검색하는 세 가지 기본 방법입니다.

데이터를 사용하는 방법에 따라 각 메서드에 장점과 단점이 있습니다.

WM_MOUSEMOVE

마우스 이동 데이터를 읽는 가장 간단한 방법은 WM_MOUSEMOVE 메시지를 통해서입니다. 다음은 WM_MOUSEMOVE 메시지에서 마우스 이동 데이터를 읽는 방법의 예입니다.

case WM_MOUSEMOVE:
{
    int xPosAbsolute = GET_X_PARAM(lParam); 
    int yPosAbsolute = GET_Y_PARAM(lParam);
    // ...
    break;
}

WM_MOUSEMOVE 데이터의 주요 단점은 화면 해상도로 제한된다는 것입니다. 즉, 마우스를 약간 이동하지만 포인터가 다음 픽셀로 이동하기에 충분하지 않으면 WM_MOUSEMOVE 메시지가 생성되지 않습니다. 따라서 이 메서드를 사용하여 마우스 이동을 읽으면 고화질 입력의 이점이 무효화됩니다.

그러나 WM_MOUSEMOVE 장점은 Windows가 원시 마우스 데이터에 포인터 가속(탄도라고도 함)을 적용하여 마우스 포인터가 고객이 예상한 대로 동작하게 한다는 것입니다. 따라서 WM_MOUSEMOVE 포인터 컨트롤(WM_INPUT 또는 DirectInput을 통해)에 대한 기본 옵션으로, 사용자에게 더 자연스러운 동작이 발생합니다. WM_MOUSEMOVE 마우스 포인터를 이동하는 데 이상적이지만 고화질 정밀도가 손실되므로 1인칭 카메라를 이동하는 데는 적합하지 않습니다.

WM_MOUSEMOVE 대한 자세한 내용은 WM_MOUSEMOVE 참조하세요.

WM_INPUT

마우스 데이터를 가져오는 두 번째 방법은 WM_INPUT 메시지를 읽는 것입니다. WM_INPUT 메시지 처리는 WM_MOUSEMOVE 메시지를 처리하는 것보다 더 복잡하지만 WM_INPUT 메시지는 HID(휴먼 인터페이스 디바이스) 스택에서 직접 읽고 고화질 결과를 반영합니다.

WM_INPUT 메시지에서 마우스 이동 데이터를 읽으려면 먼저 디바이스를 등록해야 합니다. 다음 코드는 이 예제를 제공합니다.

// you can #include <hidusage.h> for these defines
#ifndef HID_USAGE_PAGE_GENERIC
#define HID_USAGE_PAGE_GENERIC         ((USHORT) 0x01)
#endif
#ifndef HID_USAGE_GENERIC_MOUSE
#define HID_USAGE_GENERIC_MOUSE        ((USHORT) 0x02)
#endif

RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC; 
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; 
Rid[0].dwFlags = RIDEV_INPUTSINK;   
Rid[0].hwndTarget = hWnd;
RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));

다음 코드는 애플리케이션의 WinProc 처리기에서 WM_INPUT 메시지를 처리합니다.

case WM_INPUT: 
{
    UINT dwSize = sizeof(RAWINPUT);
    static BYTE lpb[sizeof(RAWINPUT)];

    GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));

    RAWINPUT* raw = (RAWINPUT*)lpb;

    if (raw->header.dwType == RIM_TYPEMOUSE) 
    {
        int xPosRelative = raw->data.mouse.lLastX;
        int yPosRelative = raw->data.mouse.lLastY;
    } 
    break;
}

WM_INPUT 사용하는 장점은 게임이 가능한 가장 낮은 수준에서 마우스에서 원시 데이터를 수신한다는 것입니다.

단점은 WM_INPUT 데이터에 적용된 탄도가 없다는 것입니다. 따라서 이 데이터로 커서를 운전하려는 경우 Windows에서처럼 커서가 동작하도록 추가적인 노력이 필요합니다. 포인터 탄도를 적용하는 방법에 대한 자세한 내용은 Windows XP용 포인터 탄도를 참조하세요.

WM_INPUT 대한 자세한 내용은 원시 입력 정보를 참조 하세요.

DirectInput

DirectInput 은 시스템의 입력 디바이스를 추상화하는 API 호출 집합입니다. 내부적으로 DirectInput은 WM_INPUT 데이터를 읽는 두 번째 스레드를 만들고 DirectInput API를 사용하면 WM_INPUT 직접 읽는 것보다 오버헤드가 더 많이 추가됩니다. DirectInput은 DirectInput 조이스틱에서 데이터를 읽는 데만 유용합니다. 그러나 Windows용 컨트롤러만 지원해야 하는 경우 대신 XInput을 사용합니다. 전반적으로 DirectInput을 사용하면 마우스 또는 키보드 장치에서 데이터를 읽을 때 이점이 없으며 이러한 시나리오에서 DirectInput을 사용하는 것은 권장되지 않습니다.

다음 코드에 표시된 DirectInput 사용의 복잡성을 앞에서 설명한 메서드와 비교합니다. DirectInput 마우스를 만들려면 다음 호출 집합이 필요합니다.

LPDIRECTINPUT8 pDI;
LPDIRECTINPUTDEVICE8 pMouse;

hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&pDI, NULL);
if(FAILED(hr))
    return hr;

hr = pDI->CreateDevice(GUID_SysMouse, &pMouse, NULL);
if(FAILED(hr))
    return hr;

hr = pMouse->SetDataFormat(&c_dfDIMouse2);
if(FAILED(hr))
    return hr;

hr = pMouse->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
if(FAILED(hr))
    return hr;

if(!bImmediate)
{
    DIPROPDWORD dipdw;
    dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
    dipdw.diph.dwObj        = 0;
    dipdw.diph.dwHow        = DIPH_DEVICE;
    dipdw.dwData            = 16; // Arbitrary buffer size

    if(FAILED(hr = pMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)))
        return hr;
}

pMouse->Acquire();

그런 다음, DirectInput 마우스 디바이스를 각 프레임을 읽을 수 있습니다.

DIMOUSESTATE2 dims2; 
ZeroMemory(&dims2, sizeof(dims2));

hr = pMouse->GetDeviceState(sizeof(DIMOUSESTATE2), &dims2);
if(FAILED(hr)) 
{
    hr = pMouse->Acquire();
    while(hr == DIERR_INPUTLOST) 
        hr = pMouse->Acquire();

    return S_OK; 
}

int xPosRelative = dims2.lX;
int yPosRelative = dims2.lY;

요약

전반적으로 고화질 마우스 이동 데이터를 수신하는 가장 좋은 방법은 WM_INPUT. 사용자가 마우스 포인터를 이동하는 경우 포인터 탄도를 수행할 필요가 없도록 WM_MOUSEMOVE 사용하는 것이 좋습니다. 이 두 창 메시지는 마우스가 고화질 마우스가 아니더라도 잘 작동합니다. Windows 게임은 고화질을 지원하여 사용자에게 보다 정확한 제어 기능을 제공할 수 있습니다.