Nutzen Sie die High-Definition-Mausbewegung
Eine Standardcomputermaus gibt Daten mit 400 Punkten pro Zoll (DPI) zurück, während eine High-Definition-Maus Daten mit 800 DPI oder höher generiert. Dadurch wird die Eingabe einer High-Definition-Maus viel präziser als bei einer Standardmaus. High-Definition-Daten können jedoch nicht über die standardmäßigen WM_MOUSEMOVE Nachrichten abgerufen werden. Im Allgemeinen profitieren Spiele von High-Definition-Mausgeräten, aber Spiele, die Mausdaten mit nur WM_MOUSEMOVE erhalten, können nicht auf die vollständige, ungefilterte Auflösung der Maus zugreifen.
Einige Unternehmen produzieren High-Definition-Mausgeräte wie Microsoft und Logitech. Mit zunehmender Beliebtheit von hochauflösenden Mausgeräten ist es wichtig, dass Entwickler verstehen, wie die von diesen Geräten generierten Informationen optimal verwendet werden. Dieser Artikel konzentriert sich auf die beste Möglichkeit, um die Leistung der High-Definition-Mauseingabe in einem Spiel wie einem First-Person-Shooter zu optimieren.
Abrufen von Mausbewegungsdaten
Hier sind die drei primären Methoden zum Abrufen von Mausdaten:
Es gibt Vor- und Nachteile für jede Methode, je nachdem, wie die Daten verwendet werden.
WM_MOUSEMOVE
Die einfachste Methode zum Lesen von Mausbewegungsdaten besteht aus WM_MOUSEMOVE Nachrichten. Im Folgenden finden Sie ein Beispiel zum Lesen von Mausbewegungsdaten aus der WM_MOUSEMOVE Nachricht:
case WM_MOUSEMOVE:
{
int xPosAbsolute = GET_X_PARAM(lParam);
int yPosAbsolute = GET_Y_PARAM(lParam);
// ...
break;
}
Der Hauptnachteil von Daten von WM_MOUSEMOVE ist, dass sie auf die Bildschirmauflösung beschränkt sind. Dies bedeutet, dass, wenn Sie die Maus etwas bewegen – aber nicht genug, um den Zeiger zum nächsten Pixel zu bewegen – dann wird keine WM_MOUSEMOVE Nachricht generiert. Wenn Sie also diese Methode verwenden, um Mausbewegungen zu lesen, werden die Vorteile von hochauflösenden Eingaben aufgehoben.
Der Vorteil von WM_MOUSEMOVE ist jedoch, dass Windows Zeigerbeschleunigung (auch als Ballistik bezeichnet) auf die rohen Mausdaten anwendet, wodurch sich der Mauszeiger wie erwartet verhält. WM_MOUSEMOVE wird als die bevorzugte Option für die Zeigersteuerung (gegenüber WM_INPUT oder DirectInput) verwendet, da es zu einem natürlicheren Verhalten für die Benutzer führt. Während WM_MOUSEMOVE ideal für bewegende Mauszeiger geeignet ist, ist es nicht so gut für das Verschieben einer Erstperson-Kamera, da die High-Definition-Genauigkeit verloren geht.
Weitere Informationen zu WM_MOUSEMOVE finden Sie unter WM_MOUSEMOVE.
WM_INPUT
Die zweite Methode zum Abrufen von Mausdaten besteht darin, WM_INPUT Nachrichten zu lesen. Die Verarbeitung von WM_INPUT-Nachrichten ist komplizierter als die von WM_MOUSEMOVE-Nachrichten, aber WM_INPUT-Nachrichten werden direkt aus dem HID-Stapel (Human Interface Device) gelesen und spiegeln hochauflösende Ergebnisse wider.
Um Mausbewegungsdaten aus der WM_INPUT Nachricht zu lesen, muss das Gerät zuerst registriert werden; Der folgende Code enthält ein Beispiel dafür:
// 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]));
Der folgende Code behandelt WM_INPUT Nachrichten im WinProc-Handler der Anwendung:
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;
}
Der Vorteil bei der Verwendung von WM_INPUT besteht darin, dass Ihr Spiel rohe Daten von der Maus auf möglichst niedriger Ebene empfängt.
Der Nachteil besteht darin, dass WM_INPUT keine Ballistiken auf ihre Daten angewendet hat. Wenn Sie also einen Cursor mit diesen Daten steuern möchten, ist zusätzlicher Aufwand erforderlich, damit sich der Cursor wie in Windows verhält. Weitere Informationen zum Anwenden von Zeigerballistiken finden Sie unter Zeigerballistiken für Windows XP.
Weitere Informationen zu WM_INPUT finden Sie unter Informationen zu Rohdaten.
DirectInput
DirectInput- ist eine Reihe von API-Aufrufen, die Eingabegeräte im System abstrahiert. Intern erstellt DirectInput einen zweiten Thread, um WM_INPUT Daten zu lesen, und die Verwendung der DirectInput-APIs fügt mehr Aufwand hinzu, als einfach WM_INPUT direkt zu lesen. DirectInput ist nur zum Lesen von Daten aus DirectInput-Joysticks nützlich; Wenn Sie jedoch nur Controller für Windows unterstützen müssen, verwenden Sie stattdessen XInput-. Insgesamt bietet die Verwendung von DirectInput keine Vorteile beim Lesen von Daten von Maus- oder Tastaturgeräten, und die Verwendung von DirectInput in diesen Szenarien wird abgeraten.
Vergleichen Sie die Komplexität der Verwendung von DirectInput-, wie im folgenden Code dargestellt, mit den zuvor beschriebenen Methoden. Zum Erstellen einer DirectInput-Maus sind die folgenden Aufrufe erforderlich:
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();
Und dann kann das DirectInput-Mausgerät jeden Frame lesen:
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;
Zusammenfassung
Insgesamt ist die beste Methode zum Empfangen von High-Definition-Mausbewegungsdaten WM_INPUT. Wenn Ihre Benutzer einfach einen Mauszeiger bewegen, sollten Sie WM_MOUSEMOVE verwenden, um zu vermeiden, dass Zeigerballistiken ausgeführt werden müssen. Beide Fenstermeldungen funktionieren gut, auch wenn die Maus keine High-Definition-Maus ist. Durch die Unterstützung von High Definition können Windows-Spiele Benutzern eine präzisere Steuerung bieten.