Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cette section inclut des exemples de code à des fins suivantes :
- Enregistrement pour Raw Input
- Exécution d’une lecture standard d’entrée brute
- Exécution d’une lecture tampon d’entrée brute
Enregistrement d'une saisie brute
Exemple 1 :
Dans cet exemple, une application spécifie l’entrée brute des contrôleurs de jeu (à la fois les pavés de jeu et les joysticks) et tous les appareils hors de la page d’utilisation de la téléphonie, à l’exception des machines de réponse.
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.
}
Exemple 2
Dans cet exemple, une application souhaite une entrée brute à partir du clavier et de la souris, mais souhaite ignorer les messages de fenêtre de clavier et de sourishérités (qui proviennent du même clavier et de la même souris).
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
}
Exécution d’une lecture standard d’entrée brute
Cet exemple montre le modèle minimal pour la lecture standard des entrées brutes à partir d’un gestionnaire de messages WM_INPUT. Chaque message WM_INPUT porte un handle HRAWINPUT dans lParam référençant l’événement d’entrée actuel. Il doit être lu via GetRawInputData avant d’appeler DefWindowProc.
Pour les appareils à haute fréquence tels que les souris à 1000Hz, plusieurs événements peuvent s’accumuler entre les itérations de boucle de message. Dans ce cas, suivez GetRawInputBuffer pour vider la file d’attente restante , consultez la phase 2 facultative ci-dessous.
/* 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);
}
Exécution d'une lecture en mode tampon d'un input brut
Cet exemple montre comment lire des entrées brutes par lots de cadence fixe à l'aide d'un minuteur récurrent. WM_INPUT messages ne sont jamais distribués intentionnellement via DispatchMessage — car GetMessage supprime les messages de la file d’attente d’entrée brute avant de renvoyer. Seul PeekMessage avec des filtres de plage de messages explicites est utilisé, en ignorant entièrement WM_INPUT. Tous les autres messages sont distribués normalement via DispatchMessage. Cela permet de conserver tous les événements d’entrée bruts dans la file d’attente où GetRawInputBuffer peut les vider en une seule fois à chaque tique du minuteur. Cette approche est bien adaptée aux boucles de jeu et à d’autres applications qui traitent les entrées à un débit fixe plutôt que de réagir individuellement à chaque événement.
Note
N’utilisez pas RIDEV_DEVNOTIFY avec ce modèle.
Étant donné que WM_INPUT_DEVICE_CHANGE est remis via la file d’attente d’entrée brute, les appels PeekMessage filtrés par plage utilisés ici ne peuvent pas le récupérer, ce qui entraîne la rotation du thread. Pour recevoir des notifications de modification d’appareil, utilisez plutôt le modèle de lecture standard .
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();
}