Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questa sezione include il codice di esempio per gli scopi seguenti:
- Registrazione per l'input non elaborato
- Esecuzione di una lettura standard di dati grezzi
- esecuzione di una lettura memorizzata nel buffer di input non elaborato
Registrazione per l'input non elaborato
Esempio 1
In questo esempio, un'applicazione specifica l'input non elaborato dei controller di gioco (sia i game pad che i joystick) e tutti i dispositivi fuori dalla pagina di utilizzo della telefonia, ad eccezione dei computer di risposta.
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.
}
Esempio 2
In questo esempio, un'applicazione vuole l'input non elaborato dalla tastiera e dal mouse, ma vuole ignorare tastiera legacy e messaggi della finestra del mouse (che verrebbero dalla stessa tastiera e mouse).
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
}
Esecuzione di una lettura standard di input non elaborato
Questo esempio illustra il modello minimo per la lettura standard dell'input non elaborato da un gestore di messaggi WM_INPUT . Ogni WM_INPUT messaggio contiene un handle HRAWINPUT in lParam che fa riferimento all'evento di input corrente, che deve essere letto tramite GetRawInputData prima di chiamare DefWindowProc.
Per dispositivi ad alta frequenza, ad esempio mouse a 1000Hz, più eventi possono accumularsi tra iterazioni del ciclo di messaggi. In tal caso, procedere con GetRawInputBuffer per svuotare la coda rimanente — vedere la fase 2 facoltativa di seguito.
/* 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);
}
Esecuzione di una lettura bufferizzata dell'input non elaborato
Questo esempio illustra come leggere l'input non elaborato in batch a frequenza fissa usando un timer periodico. WM_INPUT messaggi non vengono inviati intenzionalmente tramite DispatchMessage , perché GetMessage rimuove i messaggi dalla coda di input non elaborata prima della restituzione, viene usato solo PeekMessage con filtri espliciti per l'intervallo di messaggi, ignorando completamente WM_INPUT . Tutti gli altri messaggi vengono inviati normalmente tramite DispatchMessage. In questo modo vengono mantenuti tutti gli eventi di input grezzi nella coda, in cui GetRawInputBuffer può svuotarli tutti contemporaneamente ad ogni intervallo del timer. Questo approccio è particolarmente adatto per i cicli di gioco e altre applicazioni che elaborano l'input a una velocità fissa anziché reagire singolarmente a ogni evento.
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();
}