Freigeben über


Verwendung von Rohdaten

Dieser Abschnitt enthält Beispielcode für die folgenden Zwecke:

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