Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Dieser Abschnitt enthält Beispielcode für die folgenden Zwecke:
- Registrieren für unformatierte Eingaben
- Ausführen eines Standardlesevorgangs für unformatierte Eingaben
- Ausführen eines gepufferten Lesevorgangs für unformatierte Eingaben
Registrierung für Rohdateneingaben
Beispiel 1
In diesem Beispiel gibt eine Anwendung die rohe Eingabe von Gamecontrollern (sowohl Gamepads als auch Joysticks) und alle Geräte außerhalb der Telefonienutzungsseite an, mit Ausnahme von Antwortcomputern.
RAWINPUTDEVICE Rid[4];
Rid[0].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
Rid[0].usUsage = 0x05; // HID_USAGE_GENERIC_GAMEPAD
Rid[0].dwFlags = 0; // adds game pad
Rid[0].hwndTarget = 0;
Rid[1].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
Rid[1].usUsage = 0x04; // HID_USAGE_GENERIC_JOYSTICK
Rid[1].dwFlags = 0; // adds joystick
Rid[1].hwndTarget = 0;
Rid[2].usUsagePage = 0x0B; // HID_USAGE_PAGE_TELEPHONY
Rid[2].usUsage = 0x00;
Rid[2].dwFlags = RIDEV_PAGEONLY; // adds all devices from telephony page
Rid[2].hwndTarget = 0;
Rid[3].usUsagePage = 0x0B; // HID_USAGE_PAGE_TELEPHONY
Rid[3].usUsage = 0x02; // HID_USAGE_TELEPHONY_ANSWERING_MACHINE
Rid[3].dwFlags = RIDEV_EXCLUDE; // excludes answering machines
Rid[3].hwndTarget = 0;
if (RegisterRawInputDevices(Rid, 4, sizeof(Rid[0])) == FALSE)
{
//registration failed. Call GetLastError for the cause of the error.
}
Beispiel 2
In diesem Beispiel möchte eine Anwendung unformatierte Eingaben von Tastatur und Maus, aber ältere Tastatur- und Mausfenstermeldungen ignorieren (die von derselben Tastatur und Maus stammen).
RAWINPUTDEVICE Rid[2];
Rid[0].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
Rid[0].usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE
Rid[0].dwFlags = RIDEV_NOLEGACY; // adds mouse and also ignores legacy mouse messages
Rid[0].hwndTarget = 0;
Rid[1].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
Rid[1].usUsage = 0x06; // HID_USAGE_GENERIC_KEYBOARD
Rid[1].dwFlags = RIDEV_NOLEGACY; // adds keyboard and also ignores legacy keyboard messages
Rid[1].hwndTarget = 0;
if (RegisterRawInputDevices(Rid, 2, sizeof(Rid[0])) == FALSE)
{
//registration failed. Call GetLastError for the cause of the error
}
Ausführen eines Standardlesevorgangs für unformatierte Eingaben
Dieses Beispiel zeigt das minimale Muster für standardmäßiges Lesen von roheingaben über einen WM_INPUT-Nachrichtenhandler. Jede WM_INPUT Nachricht enthält ein HRAWINPUT-Handle in lParam , das auf das aktuelle Eingabeereignis verweist– es muss über GetRawInputData gelesen werden, bevor DefWindowProc aufgerufen wird.
Bei Hochfrequenzgeräten wie Mäusen mit 1000Hz können sich mehrere Ereignisse zwischen Nachrichtenschleifen-Iterationen ansammeln. Folgen Sie in diesem Fall dem Aufruf von GetRawInputBuffer, um die verbleibende Warteschlange abzuarbeiten – siehe die optionale Phase 2 unten.
/* Initialized once at startup */
UINT g_bufferSize = 64 * sizeof(RAWINPUT);
void* g_pBuffer = NULL;
/* Call once before entering the message loop: */
/* g_pBuffer = malloc(g_bufferSize); */
void ProcessInput(const RAWINPUT* input)
{
if (input->header.dwType == RIM_TYPEKEYBOARD)
{
const RAWKEYBOARD* kb = &input->data.keyboard;
const char* transition = (kb->Flags & RI_KEY_BREAK) ? "up" : "down";
const char* extended = (kb->Flags & RI_KEY_E0) ? " e0" :
(kb->Flags & RI_KEY_E1) ? " e1" : "";
printf("keyboard: vk=0x%02x scan=0x%02x %s%s msg=0x%04x extra=0x%08x\n",
kb->VKey, kb->MakeCode, transition, extended,
kb->Message, kb->ExtraInformation);
}
else if (input->header.dwType == RIM_TYPEMOUSE)
{
const RAWMOUSE* mouse = &input->data.mouse;
const char* moveMode = (mouse->usFlags & MOUSE_MOVE_ABSOLUTE) ? "abs" : "rel";
printf("mouse: move %s dx=%d dy=%d\n", moveMode, mouse->lLastX, mouse->lLastY);
if (mouse->usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) printf(" left down\n");
if (mouse->usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) printf(" left up\n");
if (mouse->usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) printf(" right down\n");
if (mouse->usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) printf(" right up\n");
if (mouse->usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) printf(" middle down\n");
if (mouse->usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) printf(" middle up\n");
if (mouse->usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) printf(" x1 down\n");
if (mouse->usButtonFlags & RI_MOUSE_BUTTON_4_UP) printf(" x1 up\n");
if (mouse->usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) printf(" x2 down\n");
if (mouse->usButtonFlags & RI_MOUSE_BUTTON_5_UP) printf(" x2 up\n");
if (mouse->usButtonFlags & RI_MOUSE_WHEEL)
printf(" wheel delta=%d\n", (int)(short)mouse->usButtonData);
if (mouse->usButtonFlags & RI_MOUSE_HWHEEL)
printf(" hwheel delta=%d\n", (int)(short)mouse->usButtonData);
}
else if (input->header.dwType == RIM_TYPEHID)
{
const RAWHID* hid = &input->data.hid;
printf("hid: count=%u size=%u\n", hid->dwCount, hid->dwSizeHid);
}
}
void DrainRawInputQueue(void)
{
for (;;)
{
UINT bufferSize = g_bufferSize;
UINT count = GetRawInputBuffer((RAWINPUT*)g_pBuffer, &bufferSize, sizeof(RAWINPUTHEADER));
if (count == 0)
break;
if (count == (UINT)-1)
{
/* Buffer too small — grow and retry. */
g_bufferSize = max(bufferSize, g_bufferSize * 2);
g_pBuffer = realloc(g_pBuffer, g_bufferSize);
if (g_pBuffer == NULL)
break;
continue;
}
{
RAWINPUT* ri = (RAWINPUT*)g_pBuffer;
UINT i;
for (i = 0; i < count; ++i, ri = NEXTRAWINPUTBLOCK(ri))
ProcessInput(ri);
}
/* Do not break — there may be more events in the queue. */
}
}
/* ... */
case WM_INPUT:
{
/* Phase 1: read the event carried by this WM_INPUT message. */
UINT bufferSize = g_bufferSize;
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, g_pBuffer, &bufferSize, sizeof(RAWINPUTHEADER)) != (UINT)-1)
{
ProcessInput((RAWINPUT*)g_pBuffer);
}
/* Phase 2 (optional): drain any additional events that accumulated in the queue since this message was posted.
* Recommended for high-frequency devices such as mice at 1000Hz. */
DrainRawInputQueue();
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Ausführen eines gepufferten Lesevorgangs von Rohdaten
In diesem Beispiel wird gezeigt, wie Roheingaben in Batches mit fester Rate mithilfe eines regelmäßigen Timers gelesen werden. WM_INPUT-Nachrichten werden absichtlich niemals über DispatchMessage gesendet. Da GetMessage die Nachrichten aus der Rohdateneingangs-Warteschlange entfernt, bevor es zurückkehrt, wird nur PeekMessage mit expliziten Nachrichtenbereichsfiltern verwendet, wobei WM_INPUT vollständig übersprungen wird. Alle anderen Nachrichten werden normal über DispatchMessage verteilt. Dadurch werden alle Roh-Eingabeereignisse in der Warteschlange beibehalten, in der GetRawInputBuffer sie alle auf einmal bei jedem Timer-Tick abholen kann. Dieser Ansatz eignet sich gut für Spielschleifen und andere Anwendungen, die Eingaben mit fester Rate verarbeiten, anstatt einzeln auf jedes Ereignis zu reagieren.
Hinweis
Verwenden Sie RIDEV_DEVNOTIFY nicht mit diesem Muster.
Da WM_INPUT_DEVICE_CHANGE über die unformatierte Eingabewarteschlange übermittelt wird, können die hier verwendeten Range-gefilterten PeekMessage-Aufrufe nicht abgerufen werden, was dazu führt, dass der Thread gedreht wird. Verwenden Sie zum Empfangen von Geräteänderungsbenachrichtigungen stattdessen das Standardlesemuster .
MSG msg;
BOOL running = TRUE;
HWND hWnd = CreateWindowExW(0, L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
RAWINPUTDEVICE rid[2] = {
{ 0x01, 0x02, RIDEV_INPUTSINK, hWnd }, /* mouse */
{ 0x01, 0x06, RIDEV_INPUTSINK, hWnd }, /* keyboard */
};
RegisterRawInputDevices(rid, 2, sizeof(RAWINPUTDEVICE));
/* Drain raw input queue every 16ms (~60Hz) */
SetTimer(hWnd, 1, 16, NULL);
/* Message loop — WM_INPUT is skipped via range filters so it
* accumulates in the raw input queue for DrainRawInputQueue to drain. */
while (running)
{
while (PeekMessageW(&msg, NULL, 0, WM_INPUT - 1, PM_REMOVE) ||
PeekMessageW(&msg, NULL, WM_INPUT + 1, 0xFFFF, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
running = FALSE;
break;
}
if (msg.message == WM_TIMER)
{
DrainRawInputQueue();
}
DispatchMessageW(&msg);
}
if (running)
WaitMessage();
}