Condividi tramite


Sfruttare i vantaggi dello spostamento del mouse ad alta definizione

Un mouse del computer standard restituisce dati a 400 punti per pollice (DPI), mentre un mouse ad alta definizione genera dati a 800 DPI o superiore. Questo rende l'input da un mouse ad alta definizione molto più preciso di quello da un mouse standard. Tuttavia, i dati ad alta definizione non possono essere ottenuti tramite i messaggi standard WM_MOUedizione Standard MOVE. In generale, i giochi trarranno vantaggio dai dispositivi mouse ad alta definizione, ma i giochi che ottengono i dati del mouse usando solo WM_MOUedizione Standard MOVE non saranno in grado di accedere alla risoluzione completa e non filtrata del mouse.

Alcune aziende stanno fabbricando dispositivi mouse ad alta definizione, come Microsoft e Logitech. Con la crescente popolarità dei dispositivi mouse ad alta risoluzione, è importante che gli sviluppatori comprendano come usare le informazioni generate da questi dispositivi in modo ottimale. Questo articolo è incentrato sul modo migliore per ottimizzare le prestazioni dell'input del mouse ad alta definizione in un gioco come uno sparatutto in prima persona.

Recupero dei dati di spostamento del mouse

Ecco i tre metodi principali per recuperare i dati del mouse:

Esistono vantaggi e svantaggi per ogni metodo, a seconda della modalità di utilizzo dei dati.

WM_MOUedizione Standard MOVE

Il metodo più semplice per leggere i dati di spostamento del mouse consiste nell'usare i messaggi WM_MOUedizione Standard MOVE. Di seguito è riportato un esempio di come leggere i dati sullo spostamento del mouse dal messaggio WM_MOUedizione Standard MOVE:

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

Lo svantaggio principale dei dati di WM_MOUedizione Standard MOVE è che è limitato alla risoluzione dello schermo. Ciò significa che se si sposta leggermente il mouse, ma non abbastanza per fare in modo che il puntatore passi al pixel successivo, non viene generato alcun messaggio WM_MOUedizione Standard MOVE. Quindi, l'uso di questo metodo per leggere lo spostamento del mouse nega i vantaggi dell'input ad alta definizione.

Il vantaggio di WM_MOUedizione Standard MOVE, tuttavia, è che Windows applica l'accelerazione del puntatore (nota anche come ballistica) ai dati del mouse non elaborati, che rende il puntatore del mouse si comporta come previsto dai clienti. Ciò rende WM_MOUedizione Standard MOVE l'opzione preferita per il controllo del puntatore (su WM_INPUT o DirectInput), poiché comporta un comportamento più naturale per gli utenti. Mentre WM_MOUedizione Standard MOVE è ideale per spostare i puntatori del mouse, non è così buono per spostare una fotocamera di prima persona, poiché la precisione ad alta definizione andrà persa.

Per altre info su WM_MOUedizione Standard MOVE, vedi WM_MOUedizione Standard MOVE.

WM_INPUT

Il secondo metodo per ottenere i dati del mouse consiste nel leggere WM_INPUT messaggi. L'elaborazione dei messaggi WM_INPUT è più complessa dell'elaborazione dei messaggi WM_MOUedizione Standard MOVE, ma WM_INPUT messaggi vengono letti direttamente dallo stack HID (Human Interface Device) e riflettono i risultati ad alta definizione.

Per leggere i dati di spostamento del mouse dal messaggio di WM_INPUT, il dispositivo deve prima essere registrato; Il codice seguente fornisce un esempio di questo:

// 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]));

Il codice seguente gestisce WM_INPUT messaggi nel gestore WinProc dell'applicazione:

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;
}

Il vantaggio di usare WM_INPUT è che il gioco riceve dati non elaborati dal mouse al livello più basso possibile.

Lo svantaggio è che WM_INPUT non ha alcuna ballistica applicata ai dati, quindi se si desidera guidare un cursore con questi dati, sarà necessario sforzo aggiuntivo per fare in modo che il cursore si comporti come in Windows. Per altre informazioni sull'applicazione della ballistica del puntatore, vedere Ballistics puntatore per Windows XP.

Per altre informazioni sulle WM_INPUT, vedi Informazioni sull'input non elaborato.

DirectInput

DirectInput è un set di chiamate API che astraggono i dispositivi di input nel sistema. Internamente, DirectInput crea un secondo thread per leggere i dati WM_INPUT e l'uso delle API DirectInput comporta un sovraccarico maggiore rispetto alla semplice lettura diretta di WM_INPUT. DirectInput è utile solo per la lettura dei dati dai joystick DirectInput; Tuttavia, se è necessario supportare solo i controller per Windows, usare invece XInput . In generale, l'uso di DirectInput non offre alcun vantaggio durante la lettura dei dati dai dispositivi mouse o tastiera e l'uso di DirectInput in questi scenari è sconsigliato.

Confrontare la complessità dell'uso di DirectInput, illustrato nel codice seguente, con i metodi descritti in precedenza. Per creare un mouse DirectInput sono necessari il set di chiamate seguente:

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();

E quindi il dispositivo mouse DirectInput può essere letto ogni fotogramma:

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;

Riepilogo

In generale, il metodo migliore per ricevere dati di spostamento del mouse ad alta definizione è WM_INPUT. Se gli utenti stanno semplicemente spostando un puntatore del mouse, prendere in considerazione l'uso di WM_MOUedizione Standard MOVE per evitare di dover eseguire la ballistica del puntatore. Entrambi questi messaggi di finestra funzioneranno bene anche se il mouse non è un mouse ad alta definizione. Supportando l'alta definizione, i giochi di Windows possono offrire un controllo più preciso agli utenti.