Okay, this is my first time writing a multi-threaded app, so let's see if I've done this correctly.
This is a simple app that spawns a thread to monitor WM_INPUT messages to an invisible window. It caches each message so that the main thread can periodically check to see how much the mouse has moved since the last check.
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define _WIN32_WINNT 0x0501
#include <windows.h>
HANDLE RawInputMutex;
DWORD WINAPI RawInputThreadProc(void*);
LRESULT CALLBACK RawInputWindowProc(HWND, UINT, WPARAM, LPARAM);
class RawInput {
public:
HWND hwnd;
signed mouseMoveX;
signed mouseMoveY;
void init() {
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = RawInputWindowProc;
wc.lpszClassName = "rawinputclass";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
hwnd = CreateWindow("rawinputclass", "rawinput", WS_POPUP,
64, 64, 320, 240,
0, 0, GetModuleHandle(0), 0);
RAWINPUTDEVICELIST *list;
unsigned devices = 0;
GetRawInputDeviceList(NULL, &devices, sizeof(RAWINPUTDEVICELIST));
list = (RAWINPUTDEVICELIST*)malloc(sizeof(RAWINPUTDEVICELIST) * devices);
int n = GetRawInputDeviceList(list, &devices, sizeof(RAWINPUTDEVICELIST));
for(unsigned i = 0; i < devices; i++) {
unsigned size = 512;
char buffer[512];
GetRawInputDeviceInfo(list[i].hDevice, RIDI_DEVICENAME, buffer, &size);
printf("Device '%s':\n", buffer);
RID_DEVICE_INFO info;
info.cbSize = sizeof(RID_DEVICE_INFO);
size = info.cbSize;
GetRawInputDeviceInfo(list[i].hDevice, RIDI_DEVICEINFO, &info, &size);
if(info.dwType == RIM_TYPEMOUSE) {
printf("Mouse %p\n", list[i].hDevice);
printf("ID = %d\n", info.mouse.dwId);
printf("Buttons = %d\n", info.mouse.dwNumberOfButtons);
printf("DPI = %d\n", info.mouse.dwSampleRate);
} else if(info.dwType == RIM_TYPEKEYBOARD) {
printf("Keyboard\n");
printf("Type = %d\n", info.keyboard.dwType);
printf("Subtype = %d\n", info.keyboard.dwSubType);
printf("Mode = %d\n", info.keyboard.dwKeyboardMode);
printf("Function keys = %d\n", info.keyboard.dwNumberOfFunctionKeys);
printf("Indicators = %d\n", info.keyboard.dwNumberOfIndicators);
printf("Keys total = %d\n", info.keyboard.dwNumberOfKeysTotal);
}
printf("\n");
}
RAWINPUTDEVICE rid[2];
rid[0].usUsagePage = 1;
rid[0].usUsage = 2;
rid[0].dwFlags = RIDEV_INPUTSINK;
rid[0].hwndTarget = hwnd;
rid[1].usUsagePage = 1;
rid[1].usUsage = 6;
rid[1].dwFlags = RIDEV_INPUTSINK;
rid[1].hwndTarget = hwnd;
RegisterRawInputDevices(rid, 2, sizeof(RAWINPUTDEVICE));
}
LRESULT wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
if(msg == WM_INPUT) {
unsigned size = 0;
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
RAWINPUT *input = (RAWINPUT*)malloc(size);
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, input, &size, sizeof(RAWINPUTHEADER));
if(input->header.dwType == RIM_TYPEMOUSE) {
WaitForSingleObject(RawInputMutex, INFINITE);
mouseMoveX += input->data.mouse.lLastX;
mouseMoveY += input->data.mouse.lLastY;
ReleaseMutex(RawInputMutex);
//input->header.hDevice
//input->data.mouse.usButtonFlags
} else if(input->header.dwType == RIM_TYPEKEYBOARD) {
//input->data.keyboard.MakeCode
//input->data.keyboard.Flags
//input->data.keyboard.Message
}
free(input);
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
int main() {
init();
while(true) {
MSG msg;
GetMessage(&msg, hwnd, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
signed mouseX() {
WaitForSingleObject(RawInputMutex, INFINITE);
signed result = mouseMoveX;
mouseMoveX = 0;
ReleaseMutex(RawInputMutex);
return result;
}
signed mouseY() {
WaitForSingleObject(RawInputMutex, INFINITE);
signed result = mouseMoveY;
mouseMoveY = 0;
ReleaseMutex(RawInputMutex);
return result;
}
RawInput() : mouseMoveX(0), mouseMoveY(0) {
}
} rawinput;
DWORD WINAPI RawInputThreadProc(void *param) {
return rawinput.main();
}
LRESULT CALLBACK RawInputWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
return rawinput.wndproc(hwnd, msg, wparam, lparam);
}
int main() {
RawInputMutex = CreateMutex(NULL, FALSE, NULL);
CreateThread(NULL, 0, RawInputThreadProc, 0, 0, NULL);
while(true) {
signed x = rawinput.mouseX(), y = rawinput.mouseY();
if(x || y) printf("%5d, %5d\n", x, y);
Sleep(20);
}
return 0;
}
Mutexes seem fairly slow, but not horribly so. I can WaitForSingleObject + ReleaseMutex about ~1.1 million times a second, so ~0.9ns per. Should be more than enough for an input driver, at least.