ucrtbase: Add support for r-value demangling in unDName.
[wine.git] / dlls / user32 / rawinput.c
bloba774f12231b6bb0a85e67f89340006b59c3f2337
1 /*
2 * Raw Input
4 * Copyright 2012 Henri Verbeet
5 * Copyright 2018 Zebediah Figura for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winnls.h"
30 #include "winreg.h"
31 #include "winuser.h"
32 #include "setupapi.h"
33 #include "ddk/hidsdi.h"
34 #include "wine/debug.h"
35 #include "wine/server.h"
36 #include "wine/hid.h"
38 #include "user_private.h"
40 #include "initguid.h"
41 #include "devpkey.h"
42 #include "ntddmou.h"
43 #include "ntddkbd.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(rawinput);
47 DEFINE_DEVPROPKEY(DEVPROPKEY_HID_HANDLE, 0xbc62e415, 0xf4fe, 0x405c, 0x8e, 0xda, 0x63, 0x6f, 0xb5, 0x9f, 0x08, 0x98, 2);
49 struct device
51 SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail;
52 HANDLE file;
53 HANDLE handle;
54 RID_DEVICE_INFO info;
55 PHIDP_PREPARSED_DATA data;
58 static struct device *rawinput_devices;
59 static unsigned int rawinput_devices_count, rawinput_devices_max;
61 static CRITICAL_SECTION rawinput_devices_cs;
62 static CRITICAL_SECTION_DEBUG rawinput_devices_cs_debug =
64 0, 0, &rawinput_devices_cs,
65 { &rawinput_devices_cs_debug.ProcessLocksList, &rawinput_devices_cs_debug.ProcessLocksList },
66 0, 0, { (DWORD_PTR)(__FILE__ ": rawinput_devices_cs") }
68 static CRITICAL_SECTION rawinput_devices_cs = { &rawinput_devices_cs_debug, -1, 0, 0, 0, 0 };
70 static BOOL array_reserve(void **elements, unsigned int *capacity, unsigned int count, unsigned int size)
72 unsigned int new_capacity, max_capacity;
73 void *new_elements;
75 if (count <= *capacity)
76 return TRUE;
78 max_capacity = ~(SIZE_T)0 / size;
79 if (count > max_capacity)
80 return FALSE;
82 new_capacity = max(4, *capacity);
83 while (new_capacity < count && new_capacity <= max_capacity / 2)
84 new_capacity *= 2;
85 if (new_capacity < count)
86 new_capacity = max_capacity;
88 if (!(new_elements = realloc(*elements, new_capacity * size)))
89 return FALSE;
91 *elements = new_elements;
92 *capacity = new_capacity;
94 return TRUE;
97 static struct device *add_device(HDEVINFO set, SP_DEVICE_INTERFACE_DATA *iface)
99 SP_DEVINFO_DATA device_data = {sizeof(device_data)};
100 SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail;
101 struct device *device = NULL;
102 UINT32 handle;
103 HANDLE file;
104 WCHAR *pos;
105 DWORD i, size, type;
107 SetupDiGetDeviceInterfaceDetailW(set, iface, NULL, 0, &size, &device_data);
108 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
110 ERR("Failed to get device path, error %#x.\n", GetLastError());
111 return FALSE;
114 if (!SetupDiGetDevicePropertyW(set, &device_data, &DEVPROPKEY_HID_HANDLE, &type, (BYTE *)&handle, sizeof(handle), NULL, 0) ||
115 type != DEVPROP_TYPE_UINT32)
117 ERR("Failed to get device handle, error %#x.\n", GetLastError());
118 return NULL;
121 if (!(detail = malloc(size)))
123 ERR("Failed to allocate memory.\n");
124 return FALSE;
126 detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
127 SetupDiGetDeviceInterfaceDetailW(set, iface, detail, size, NULL, NULL);
129 /* upper case everything but the GUID */
130 for (pos = detail->DevicePath; *pos && *pos != '{'; pos++) *pos = towupper(*pos);
132 file = CreateFileW(detail->DevicePath, GENERIC_READ | GENERIC_WRITE,
133 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
134 if (file == INVALID_HANDLE_VALUE)
136 ERR("Failed to open device file %s, error %u.\n", debugstr_w(detail->DevicePath), GetLastError());
137 free(detail);
138 return NULL;
141 for (i = 0; i < rawinput_devices_count && !device; ++i)
142 if (rawinput_devices[i].handle == UlongToHandle(handle))
143 device = rawinput_devices + i;
145 if (device)
147 TRACE("Updating device %x / %s.\n", handle, debugstr_w(detail->DevicePath));
148 HidD_FreePreparsedData(device->data);
149 CloseHandle(device->file);
150 free(device->detail);
152 else if (array_reserve((void **)&rawinput_devices, &rawinput_devices_max,
153 rawinput_devices_count + 1, sizeof(*rawinput_devices)))
155 device = &rawinput_devices[rawinput_devices_count++];
156 TRACE("Adding device %x / %s.\n", handle, debugstr_w(detail->DevicePath));
158 else
160 ERR("Failed to allocate memory.\n");
161 CloseHandle(file);
162 free(detail);
163 return NULL;
166 device->detail = detail;
167 device->file = file;
168 device->handle = ULongToHandle(handle);
169 device->info.cbSize = sizeof(RID_DEVICE_INFO);
170 device->data = NULL;
172 return device;
175 void rawinput_update_device_list(void)
177 SP_DEVICE_INTERFACE_DATA iface = { sizeof(iface) };
178 struct device *device;
179 HIDD_ATTRIBUTES attr;
180 HIDP_CAPS caps;
181 GUID hid_guid;
182 HDEVINFO set;
183 DWORD idx;
185 TRACE("\n");
187 HidD_GetHidGuid(&hid_guid);
189 EnterCriticalSection(&rawinput_devices_cs);
191 /* destroy previous list */
192 for (idx = 0; idx < rawinput_devices_count; ++idx)
194 HidD_FreePreparsedData(rawinput_devices[idx].data);
195 CloseHandle(rawinput_devices[idx].file);
196 free(rawinput_devices[idx].detail);
198 rawinput_devices_count = 0;
200 set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
202 for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &hid_guid, idx, &iface); ++idx)
204 if (!(device = add_device(set, &iface)))
205 continue;
207 attr.Size = sizeof(HIDD_ATTRIBUTES);
208 if (!HidD_GetAttributes(device->file, &attr))
209 WARN("Failed to get attributes.\n");
211 device->info.dwType = RIM_TYPEHID;
212 device->info.hid.dwVendorId = attr.VendorID;
213 device->info.hid.dwProductId = attr.ProductID;
214 device->info.hid.dwVersionNumber = attr.VersionNumber;
216 if (!HidD_GetPreparsedData(device->file, &device->data))
217 WARN("Failed to get preparsed data.\n");
219 if (!HidP_GetCaps(device->data, &caps))
220 WARN("Failed to get caps.\n");
222 device->info.hid.usUsagePage = caps.UsagePage;
223 device->info.hid.usUsage = caps.Usage;
226 SetupDiDestroyDeviceInfoList(set);
228 set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_MOUSE, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
230 for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_MOUSE, idx, &iface); ++idx)
232 static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE};
234 if (!(device = add_device(set, &iface)))
235 continue;
237 device->info.dwType = RIM_TYPEMOUSE;
238 device->info.mouse = mouse_info;
241 SetupDiDestroyDeviceInfoList(set);
243 set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_KEYBOARD, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
245 for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_KEYBOARD, idx, &iface); ++idx)
247 static const RID_DEVICE_INFO_KEYBOARD keyboard_info = {0, 0, 1, 12, 3, 101};
249 if (!(device = add_device(set, &iface)))
250 continue;
252 device->info.dwType = RIM_TYPEKEYBOARD;
253 device->info.keyboard = keyboard_info;
256 SetupDiDestroyDeviceInfoList(set);
258 LeaveCriticalSection(&rawinput_devices_cs);
262 static struct device *find_device_from_handle(HANDLE handle)
264 UINT i;
265 for (i = 0; i < rawinput_devices_count; ++i)
266 if (rawinput_devices[i].handle == handle)
267 return rawinput_devices + i;
268 rawinput_update_device_list();
269 for (i = 0; i < rawinput_devices_count; ++i)
270 if (rawinput_devices[i].handle == handle)
271 return rawinput_devices + i;
272 return NULL;
276 BOOL rawinput_device_get_usages(HANDLE handle, USAGE *usage_page, USAGE *usage)
278 struct device *device;
280 *usage_page = *usage = 0;
282 if (!(device = find_device_from_handle(handle))) return FALSE;
283 if (device->info.dwType != RIM_TYPEHID) return FALSE;
285 *usage_page = device->info.hid.usUsagePage;
286 *usage = device->info.hid.usUsage;
287 return TRUE;
291 struct rawinput_thread_data *rawinput_thread_data(void)
293 struct user_thread_info *thread_info = get_user_thread_info();
294 struct rawinput_thread_data *data = thread_info->rawinput;
295 if (data) return data;
296 data = thread_info->rawinput = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
297 RAWINPUT_BUFFER_SIZE + sizeof(struct user_thread_info) );
298 return data;
302 BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hardware_msg_data *msg_data)
304 SIZE_T size;
306 rawinput->header.dwType = msg_data->rawinput.type;
307 if (msg_data->rawinput.type == RIM_TYPEMOUSE)
309 static const unsigned int button_flags[] =
311 0, /* MOUSEEVENTF_MOVE */
312 RI_MOUSE_LEFT_BUTTON_DOWN, /* MOUSEEVENTF_LEFTDOWN */
313 RI_MOUSE_LEFT_BUTTON_UP, /* MOUSEEVENTF_LEFTUP */
314 RI_MOUSE_RIGHT_BUTTON_DOWN, /* MOUSEEVENTF_RIGHTDOWN */
315 RI_MOUSE_RIGHT_BUTTON_UP, /* MOUSEEVENTF_RIGHTUP */
316 RI_MOUSE_MIDDLE_BUTTON_DOWN, /* MOUSEEVENTF_MIDDLEDOWN */
317 RI_MOUSE_MIDDLE_BUTTON_UP, /* MOUSEEVENTF_MIDDLEUP */
319 unsigned int i;
321 rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWMOUSE);
322 rawinput->header.hDevice = WINE_MOUSE_HANDLE;
323 rawinput->header.wParam = 0;
325 rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE;
326 rawinput->data.mouse.usButtonFlags = 0;
327 rawinput->data.mouse.usButtonData = 0;
328 for (i = 1; i < ARRAY_SIZE(button_flags); ++i)
330 if (msg_data->flags & (1 << i))
331 rawinput->data.mouse.usButtonFlags |= button_flags[i];
333 if (msg_data->flags & MOUSEEVENTF_WHEEL)
335 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_WHEEL;
336 rawinput->data.mouse.usButtonData = msg_data->rawinput.mouse.data;
338 if (msg_data->flags & MOUSEEVENTF_HWHEEL)
340 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_HORIZONTAL_WHEEL;
341 rawinput->data.mouse.usButtonData = msg_data->rawinput.mouse.data;
343 if (msg_data->flags & MOUSEEVENTF_XDOWN)
345 if (msg_data->rawinput.mouse.data == XBUTTON1)
346 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN;
347 else if (msg_data->rawinput.mouse.data == XBUTTON2)
348 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN;
350 if (msg_data->flags & MOUSEEVENTF_XUP)
352 if (msg_data->rawinput.mouse.data == XBUTTON1)
353 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_UP;
354 else if (msg_data->rawinput.mouse.data == XBUTTON2)
355 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_UP;
358 rawinput->data.mouse.ulRawButtons = 0;
359 rawinput->data.mouse.lLastX = msg_data->rawinput.mouse.x;
360 rawinput->data.mouse.lLastY = msg_data->rawinput.mouse.y;
361 rawinput->data.mouse.ulExtraInformation = msg_data->info;
363 else if (msg_data->rawinput.type == RIM_TYPEKEYBOARD)
365 rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWKEYBOARD);
366 rawinput->header.hDevice = WINE_KEYBOARD_HANDLE;
367 rawinput->header.wParam = 0;
369 rawinput->data.keyboard.MakeCode = msg_data->rawinput.kbd.scan;
370 rawinput->data.keyboard.Flags = msg_data->flags & KEYEVENTF_KEYUP ? RI_KEY_BREAK : RI_KEY_MAKE;
371 if (msg_data->flags & KEYEVENTF_EXTENDEDKEY) rawinput->data.keyboard.Flags |= RI_KEY_E0;
372 rawinput->data.keyboard.Reserved = 0;
374 switch (msg_data->rawinput.kbd.vkey)
376 case VK_LSHIFT:
377 case VK_RSHIFT:
378 rawinput->data.keyboard.VKey = VK_SHIFT;
379 rawinput->data.keyboard.Flags &= ~RI_KEY_E0;
380 break;
381 case VK_LCONTROL:
382 case VK_RCONTROL:
383 rawinput->data.keyboard.VKey = VK_CONTROL;
384 break;
385 case VK_LMENU:
386 case VK_RMENU:
387 rawinput->data.keyboard.VKey = VK_MENU;
388 break;
389 default:
390 rawinput->data.keyboard.VKey = msg_data->rawinput.kbd.vkey;
391 break;
394 rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message;
395 rawinput->data.keyboard.ExtraInformation = msg_data->info;
397 else if (msg_data->rawinput.type == RIM_TYPEHID)
399 size = msg_data->size - sizeof(*msg_data);
400 if (size > rawinput->header.dwSize - sizeof(*rawinput)) return FALSE;
402 rawinput->header.dwSize = FIELD_OFFSET( RAWINPUT, data.hid.bRawData ) + size;
403 rawinput->header.hDevice = ULongToHandle( msg_data->rawinput.hid.device );
404 rawinput->header.wParam = 0;
406 rawinput->data.hid.dwCount = msg_data->rawinput.hid.count;
407 rawinput->data.hid.dwSizeHid = msg_data->rawinput.hid.length;
408 memcpy( rawinput->data.hid.bRawData, msg_data + 1, size );
410 else
412 FIXME("Unhandled rawinput type %#x.\n", msg_data->rawinput.type);
413 return FALSE;
416 return TRUE;
420 /***********************************************************************
421 * GetRawInputDeviceList (USER32.@)
423 UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_count, UINT size)
425 static UINT last_check;
426 UINT i, ticks = GetTickCount();
428 TRACE("devices %p, device_count %p, size %u.\n", devices, device_count, size);
430 if (size != sizeof(*devices))
432 SetLastError(ERROR_INVALID_PARAMETER);
433 return ~0U;
436 if (!device_count)
438 SetLastError(ERROR_NOACCESS);
439 return ~0U;
442 if (ticks - last_check > 2000)
444 last_check = ticks;
445 rawinput_update_device_list();
448 if (!devices)
450 *device_count = rawinput_devices_count;
451 return 0;
454 if (*device_count < rawinput_devices_count)
456 SetLastError(ERROR_INSUFFICIENT_BUFFER);
457 *device_count = rawinput_devices_count;
458 return ~0U;
461 for (i = 0; i < rawinput_devices_count; ++i)
463 devices[i].hDevice = rawinput_devices[i].handle;
464 devices[i].dwType = rawinput_devices[i].info.dwType;
467 return rawinput_devices_count;
470 /***********************************************************************
471 * RegisterRawInputDevices (USER32.@)
473 BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, UINT device_count, UINT size)
475 struct rawinput_device *d;
476 BOOL ret;
477 UINT i;
479 TRACE("devices %p, device_count %u, size %u.\n", devices, device_count, size);
481 if (size != sizeof(*devices))
483 WARN("Invalid structure size %u.\n", size);
484 SetLastError(ERROR_INVALID_PARAMETER);
485 return FALSE;
488 for (i = 0; i < device_count; ++i)
490 if ((devices[i].dwFlags & RIDEV_INPUTSINK) &&
491 (devices[i].hwndTarget == NULL))
493 SetLastError(ERROR_INVALID_PARAMETER);
494 return FALSE;
497 if ((devices[i].dwFlags & RIDEV_REMOVE) &&
498 (devices[i].hwndTarget != NULL))
500 SetLastError(ERROR_INVALID_PARAMETER);
501 return FALSE;
505 if (!(d = HeapAlloc( GetProcessHeap(), 0, device_count * sizeof(*d) ))) return FALSE;
507 for (i = 0; i < device_count; ++i)
509 TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n",
510 i, devices[i].usUsagePage, devices[i].usUsage,
511 devices[i].dwFlags, devices[i].hwndTarget);
512 if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK|RIDEV_DEVNOTIFY))
513 FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
515 d[i].usage_page = devices[i].usUsagePage;
516 d[i].usage = devices[i].usUsage;
517 d[i].flags = devices[i].dwFlags;
518 d[i].target = wine_server_user_handle( devices[i].hwndTarget );
521 SERVER_START_REQ( update_rawinput_devices )
523 wine_server_add_data( req, d, device_count * sizeof(*d) );
524 ret = !wine_server_call( req );
526 SERVER_END_REQ;
528 HeapFree( GetProcessHeap(), 0, d );
530 return ret;
533 /***********************************************************************
534 * GetRawInputData (USER32.@)
536 UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size)
538 struct rawinput_thread_data *thread_data = rawinput_thread_data();
539 UINT size;
541 TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
542 rawinput, command, data, data_size, header_size);
544 if (!rawinput || thread_data->hw_id != (UINT_PTR)rawinput)
546 SetLastError(ERROR_INVALID_HANDLE);
547 return ~0U;
550 if (header_size != sizeof(RAWINPUTHEADER))
552 WARN("Invalid structure size %u.\n", header_size);
553 SetLastError(ERROR_INVALID_PARAMETER);
554 return ~0U;
557 switch (command)
559 case RID_INPUT:
560 size = thread_data->buffer->header.dwSize;
561 break;
562 case RID_HEADER:
563 size = sizeof(RAWINPUTHEADER);
564 break;
565 default:
566 SetLastError(ERROR_INVALID_PARAMETER);
567 return ~0U;
570 if (!data)
572 *data_size = size;
573 return 0;
576 if (*data_size < size)
578 SetLastError(ERROR_INSUFFICIENT_BUFFER);
579 return ~0U;
581 memcpy(data, thread_data->buffer, size);
582 return size;
585 #ifdef _WIN64
586 typedef RAWINPUT RAWINPUT64;
587 #else
588 typedef struct
590 RAWINPUTHEADER header;
591 char pad[8];
592 union {
593 RAWMOUSE mouse;
594 RAWKEYBOARD keyboard;
595 RAWHID hid;
596 } data;
597 } RAWINPUT64;
598 #endif
600 /***********************************************************************
601 * GetRawInputBuffer (USER32.@)
603 UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size, UINT header_size)
605 struct hardware_msg_data *msg_data;
606 struct rawinput_thread_data *thread_data;
607 RAWINPUT *rawinput;
608 UINT count = 0, remaining, rawinput_size, next_size, overhead;
609 BOOL is_wow64;
610 int i;
612 if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64)
613 rawinput_size = sizeof(RAWINPUT64);
614 else
615 rawinput_size = sizeof(RAWINPUT);
616 overhead = rawinput_size - sizeof(RAWINPUT);
618 if (header_size != sizeof(RAWINPUTHEADER))
620 WARN("Invalid structure size %u.\n", header_size);
621 SetLastError(ERROR_INVALID_PARAMETER);
622 return ~0U;
625 if (!data_size)
627 SetLastError(ERROR_INVALID_PARAMETER);
628 return ~0U;
631 if (!data)
633 TRACE("data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size);
634 SERVER_START_REQ( get_rawinput_buffer )
636 req->rawinput_size = rawinput_size;
637 req->buffer_size = 0;
638 if (wine_server_call( req )) return ~0U;
639 *data_size = reply->next_size;
641 SERVER_END_REQ;
642 return 0;
645 if (!(thread_data = rawinput_thread_data())) return ~0U;
646 rawinput = thread_data->buffer;
648 /* first RAWINPUT block in the buffer is used for WM_INPUT message data */
649 msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput);
650 SERVER_START_REQ( get_rawinput_buffer )
652 req->rawinput_size = rawinput_size;
653 req->buffer_size = *data_size;
654 wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize );
655 if (wine_server_call( req )) return ~0U;
656 next_size = reply->next_size;
657 count = reply->count;
659 SERVER_END_REQ;
661 remaining = *data_size;
662 for (i = 0; i < count; ++i)
664 data->header.dwSize = remaining;
665 if (!rawinput_from_hardware_message(data, msg_data)) break;
666 if (overhead) memmove((char *)&data->data + overhead, &data->data,
667 data->header.dwSize - sizeof(RAWINPUTHEADER));
668 data->header.dwSize += overhead;
669 remaining -= data->header.dwSize;
670 data = NEXTRAWINPUTBLOCK(data);
671 msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_data->size);
674 if (count == 0 && next_size == 0) *data_size = 0;
675 else if (next_size == 0) next_size = rawinput_size;
677 if (next_size && *data_size <= next_size)
679 SetLastError(ERROR_INSUFFICIENT_BUFFER);
680 *data_size = next_size;
681 count = ~0U;
684 if (count) TRACE("data %p, data_size %p (%u), header_size %u, count %u\n", data, data_size, *data_size, header_size, count);
685 return count;
688 /***********************************************************************
689 * GetRawInputDeviceInfoA (USER32.@)
691 UINT WINAPI GetRawInputDeviceInfoA(HANDLE device, UINT command, void *data, UINT *data_size)
693 TRACE("device %p, command %#x, data %p, data_size %p.\n",
694 device, command, data, data_size);
696 /* RIDI_DEVICENAME data_size is in chars, not bytes */
697 if (command == RIDI_DEVICENAME)
699 WCHAR *nameW;
700 UINT ret, nameW_sz;
702 if (!data_size) return ~0U;
704 nameW_sz = *data_size;
706 if (data && nameW_sz > 0)
707 nameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nameW_sz);
708 else
709 nameW = NULL;
711 ret = GetRawInputDeviceInfoW(device, command, nameW, &nameW_sz);
713 if (ret && ret != ~0U)
714 WideCharToMultiByte(CP_ACP, 0, nameW, -1, data, *data_size, NULL, NULL);
716 *data_size = nameW_sz;
718 HeapFree(GetProcessHeap(), 0, nameW);
720 return ret;
723 return GetRawInputDeviceInfoW(device, command, data, data_size);
726 /***********************************************************************
727 * GetRawInputDeviceInfoW (USER32.@)
729 UINT WINAPI GetRawInputDeviceInfoW(HANDLE handle, UINT command, void *data, UINT *data_size)
731 struct hid_preparsed_data *preparsed;
732 RID_DEVICE_INFO info;
733 struct device *device;
734 DWORD len, data_len;
736 TRACE("handle %p, command %#x, data %p, data_size %p.\n",
737 handle, command, data, data_size);
739 if (!data_size)
741 SetLastError(ERROR_NOACCESS);
742 return ~0U;
744 if (!(device = find_device_from_handle(handle)))
746 SetLastError(ERROR_INVALID_HANDLE);
747 return ~0U;
750 data_len = *data_size;
751 switch (command)
753 case RIDI_DEVICENAME:
754 if ((len = wcslen(device->detail->DevicePath) + 1) <= data_len && data)
755 memcpy(data, device->detail->DevicePath, len * sizeof(WCHAR));
756 *data_size = len;
757 break;
759 case RIDI_DEVICEINFO:
760 if ((len = sizeof(info)) <= data_len && data)
761 memcpy(data, &device->info, len);
762 *data_size = len;
763 break;
765 case RIDI_PREPARSEDDATA:
766 if (!(preparsed = (struct hid_preparsed_data *)device->data)) len = 0;
767 else len = preparsed->caps_size + FIELD_OFFSET(struct hid_preparsed_data, value_caps[0]) +
768 preparsed->number_link_collection_nodes * sizeof(struct hid_collection_node);
770 if (device->data && len <= data_len && data)
771 memcpy(data, device->data, len);
772 *data_size = len;
773 break;
775 default:
776 FIXME("command %#x not supported\n", command);
777 SetLastError(ERROR_INVALID_PARAMETER);
778 return ~0U;
781 if (!data)
782 return 0;
784 if (data_len < len)
786 SetLastError(ERROR_INSUFFICIENT_BUFFER);
787 return ~0U;
790 return *data_size;
793 static int __cdecl compare_raw_input_devices(const void *ap, const void *bp)
795 const RAWINPUTDEVICE a = *(const RAWINPUTDEVICE *)ap;
796 const RAWINPUTDEVICE b = *(const RAWINPUTDEVICE *)bp;
798 if (a.usUsagePage != b.usUsagePage) return a.usUsagePage - b.usUsagePage;
799 if (a.usUsage != b.usUsage) return a.usUsage - b.usUsage;
800 return 0;
803 /***********************************************************************
804 * GetRegisteredRawInputDevices (USER32.@)
806 UINT WINAPI DECLSPEC_HOTPATCH GetRegisteredRawInputDevices(RAWINPUTDEVICE *devices, UINT *device_count, UINT size)
808 struct rawinput_device *buffer = NULL;
809 unsigned int i, status, count = ~0U, buffer_size;
811 TRACE("devices %p, device_count %p, size %u\n", devices, device_count, size);
813 if (size != sizeof(RAWINPUTDEVICE) || !device_count || (devices && !*device_count))
815 SetLastError(ERROR_INVALID_PARAMETER);
816 return ~0U;
819 buffer_size = *device_count * sizeof(*buffer);
820 if (devices && !(buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size)))
821 return ~0U;
823 SERVER_START_REQ(get_rawinput_devices)
825 if (buffer) wine_server_set_reply(req, buffer, buffer_size);
826 status = wine_server_call_err(req);
827 *device_count = reply->device_count;
829 SERVER_END_REQ;
831 if (buffer && !status)
833 for (i = 0, count = *device_count; i < count; ++i)
835 devices[i].usUsagePage = buffer[i].usage_page;
836 devices[i].usUsage = buffer[i].usage;
837 devices[i].dwFlags = buffer[i].flags;
838 devices[i].hwndTarget = wine_server_ptr_handle(buffer[i].target);
841 qsort(devices, count, sizeof(*devices), compare_raw_input_devices);
844 if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
845 else count = 0;
846 return count;
850 /***********************************************************************
851 * DefRawInputProc (USER32.@)
853 LRESULT WINAPI DefRawInputProc(RAWINPUT **data, INT data_count, UINT header_size)
855 FIXME("data %p, data_count %d, header_size %u stub!\n", data, data_count, header_size);
857 return 0;