crypt32: Make helper for copying CMSG_CMS_SIGNER_INFO attributes more generic.
[wine.git] / dlls / user32 / rawinput.c
blobba11a121bc538fa7243ba40ccacd282d46cb92bc
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 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
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 "ntddmou.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(rawinput);
45 struct device
47 WCHAR *path;
48 HANDLE file;
49 RID_DEVICE_INFO info;
50 PHIDP_PREPARSED_DATA data;
53 static struct device *rawinput_devices;
54 static unsigned int rawinput_devices_count, rawinput_devices_max;
56 static CRITICAL_SECTION rawinput_devices_cs;
57 static CRITICAL_SECTION_DEBUG rawinput_devices_cs_debug =
59 0, 0, &rawinput_devices_cs,
60 { &rawinput_devices_cs_debug.ProcessLocksList, &rawinput_devices_cs_debug.ProcessLocksList },
61 0, 0, { (DWORD_PTR)(__FILE__ ": rawinput_devices_cs") }
63 static CRITICAL_SECTION rawinput_devices_cs = { &rawinput_devices_cs_debug, -1, 0, 0, 0, 0 };
65 static BOOL array_reserve(void **elements, unsigned int *capacity, unsigned int count, unsigned int size)
67 unsigned int new_capacity, max_capacity;
68 void *new_elements;
70 if (count <= *capacity)
71 return TRUE;
73 max_capacity = ~(SIZE_T)0 / size;
74 if (count > max_capacity)
75 return FALSE;
77 new_capacity = max(4, *capacity);
78 while (new_capacity < count && new_capacity <= max_capacity / 2)
79 new_capacity *= 2;
80 if (new_capacity < count)
81 new_capacity = max_capacity;
83 if (!(new_elements = heap_realloc(*elements, new_capacity * size)))
84 return FALSE;
86 *elements = new_elements;
87 *capacity = new_capacity;
89 return TRUE;
92 static struct device *add_device(HDEVINFO set, SP_DEVICE_INTERFACE_DATA *iface)
94 SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail;
95 struct device *device;
96 HANDLE file;
97 WCHAR *path;
98 DWORD size;
100 SetupDiGetDeviceInterfaceDetailW(set, iface, NULL, 0, &size, NULL);
101 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
103 ERR("Failed to get device path, error %#x.\n", GetLastError());
104 return FALSE;
106 if (!(detail = heap_alloc(size)))
108 ERR("Failed to allocate memory.\n");
109 return FALSE;
111 detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
112 SetupDiGetDeviceInterfaceDetailW(set, iface, detail, size, NULL, NULL);
114 TRACE("Found HID device %s.\n", debugstr_w(detail->DevicePath));
116 if (!(path = heap_strdupW(detail->DevicePath)))
118 ERR("Failed to allocate memory.\n");
119 heap_free(detail);
120 return NULL;
122 heap_free(detail);
124 file = CreateFileW(path, GENERIC_READ | GENERIC_WRITE,
125 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
126 if (file == INVALID_HANDLE_VALUE)
128 ERR("Failed to open device file %s, error %u.\n", debugstr_w(path), GetLastError());
129 heap_free(path);
130 return NULL;
133 if (!array_reserve((void **)&rawinput_devices, &rawinput_devices_max,
134 rawinput_devices_count + 1, sizeof(*rawinput_devices)))
136 ERR("Failed to allocate memory.\n");
137 CloseHandle(file);
138 heap_free(path);
139 return NULL;
142 device = &rawinput_devices[rawinput_devices_count++];
143 device->path = path;
144 device->file = file;
145 device->info.cbSize = sizeof(RID_DEVICE_INFO);
147 return device;
150 static void find_devices(void)
152 static ULONGLONG last_check;
154 SP_DEVICE_INTERFACE_DATA iface = { sizeof(iface) };
155 struct device *device;
156 HIDD_ATTRIBUTES attr;
157 HIDP_CAPS caps;
158 GUID hid_guid;
159 HDEVINFO set;
160 DWORD idx;
162 if (GetTickCount64() - last_check < 2000)
163 return;
164 last_check = GetTickCount64();
166 HidD_GetHidGuid(&hid_guid);
168 EnterCriticalSection(&rawinput_devices_cs);
170 /* destroy previous list */
171 for (idx = 0; idx < rawinput_devices_count; ++idx)
173 CloseHandle(rawinput_devices[idx].file);
174 heap_free(rawinput_devices[idx].path);
176 rawinput_devices_count = 0;
178 set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
180 for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &hid_guid, idx, &iface); ++idx)
182 if (!(device = add_device(set, &iface)))
183 continue;
185 attr.Size = sizeof(HIDD_ATTRIBUTES);
186 if (!HidD_GetAttributes(device->file, &attr))
187 WARN("Failed to get attributes.\n");
189 device->info.dwType = RIM_TYPEHID;
190 device->info.u.hid.dwVendorId = attr.VendorID;
191 device->info.u.hid.dwProductId = attr.ProductID;
192 device->info.u.hid.dwVersionNumber = attr.VersionNumber;
194 if (!HidD_GetPreparsedData(device->file, &device->data))
195 WARN("Failed to get preparsed data.\n");
197 if (!HidP_GetCaps(device->data, &caps))
198 WARN("Failed to get caps.\n");
200 device->info.u.hid.usUsagePage = caps.UsagePage;
201 device->info.u.hid.usUsage = caps.Usage;
204 SetupDiDestroyDeviceInfoList(set);
206 set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_MOUSE, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
208 for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_MOUSE, idx, &iface); ++idx)
210 static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE};
212 if (!(device = add_device(set, &iface)))
213 continue;
215 device->info.dwType = RIM_TYPEMOUSE;
216 device->info.u.mouse = mouse_info;
219 SetupDiDestroyDeviceInfoList(set);
221 LeaveCriticalSection(&rawinput_devices_cs);
225 struct rawinput_thread_data *rawinput_thread_data(void)
227 struct user_thread_info *thread_info = get_user_thread_info();
228 struct rawinput_thread_data *data = thread_info->rawinput;
229 if (data) return data;
230 data = thread_info->rawinput = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
231 RAWINPUT_BUFFER_SIZE + sizeof(struct user_thread_info) );
232 return data;
236 BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hardware_msg_data *msg_data)
238 rawinput->header.dwType = msg_data->rawinput.type;
239 if (msg_data->rawinput.type == RIM_TYPEMOUSE)
241 static const unsigned int button_flags[] =
243 0, /* MOUSEEVENTF_MOVE */
244 RI_MOUSE_LEFT_BUTTON_DOWN, /* MOUSEEVENTF_LEFTDOWN */
245 RI_MOUSE_LEFT_BUTTON_UP, /* MOUSEEVENTF_LEFTUP */
246 RI_MOUSE_RIGHT_BUTTON_DOWN, /* MOUSEEVENTF_RIGHTDOWN */
247 RI_MOUSE_RIGHT_BUTTON_UP, /* MOUSEEVENTF_RIGHTUP */
248 RI_MOUSE_MIDDLE_BUTTON_DOWN, /* MOUSEEVENTF_MIDDLEDOWN */
249 RI_MOUSE_MIDDLE_BUTTON_UP, /* MOUSEEVENTF_MIDDLEUP */
251 unsigned int i;
253 rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWMOUSE);
254 rawinput->header.hDevice = WINE_MOUSE_HANDLE;
255 rawinput->header.wParam = 0;
257 rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE;
258 rawinput->data.mouse.u.s.usButtonFlags = 0;
259 rawinput->data.mouse.u.s.usButtonData = 0;
260 for (i = 1; i < ARRAY_SIZE(button_flags); ++i)
262 if (msg_data->flags & (1 << i))
263 rawinput->data.mouse.u.s.usButtonFlags |= button_flags[i];
265 if (msg_data->flags & MOUSEEVENTF_WHEEL)
267 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_WHEEL;
268 rawinput->data.mouse.u.s.usButtonData = msg_data->rawinput.mouse.data;
270 if (msg_data->flags & MOUSEEVENTF_HWHEEL)
272 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_HORIZONTAL_WHEEL;
273 rawinput->data.mouse.u.s.usButtonData = msg_data->rawinput.mouse.data;
275 if (msg_data->flags & MOUSEEVENTF_XDOWN)
277 if (msg_data->rawinput.mouse.data == XBUTTON1)
278 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN;
279 else if (msg_data->rawinput.mouse.data == XBUTTON2)
280 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN;
282 if (msg_data->flags & MOUSEEVENTF_XUP)
284 if (msg_data->rawinput.mouse.data == XBUTTON1)
285 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_4_UP;
286 else if (msg_data->rawinput.mouse.data == XBUTTON2)
287 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_5_UP;
290 rawinput->data.mouse.ulRawButtons = 0;
291 rawinput->data.mouse.lLastX = msg_data->rawinput.mouse.x;
292 rawinput->data.mouse.lLastY = msg_data->rawinput.mouse.y;
293 rawinput->data.mouse.ulExtraInformation = msg_data->info;
295 else if (msg_data->rawinput.type == RIM_TYPEKEYBOARD)
297 rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWKEYBOARD);
298 rawinput->header.hDevice = WINE_KEYBOARD_HANDLE;
299 rawinput->header.wParam = 0;
301 rawinput->data.keyboard.MakeCode = msg_data->rawinput.kbd.scan;
302 rawinput->data.keyboard.Flags = msg_data->flags & KEYEVENTF_KEYUP ? RI_KEY_BREAK : RI_KEY_MAKE;
303 if (msg_data->flags & KEYEVENTF_EXTENDEDKEY) rawinput->data.keyboard.Flags |= RI_KEY_E0;
304 rawinput->data.keyboard.Reserved = 0;
306 switch (msg_data->rawinput.kbd.vkey)
308 case VK_LSHIFT:
309 case VK_RSHIFT:
310 rawinput->data.keyboard.VKey = VK_SHIFT;
311 rawinput->data.keyboard.Flags &= ~RI_KEY_E0;
312 break;
313 case VK_LCONTROL:
314 case VK_RCONTROL:
315 rawinput->data.keyboard.VKey = VK_CONTROL;
316 break;
317 case VK_LMENU:
318 case VK_RMENU:
319 rawinput->data.keyboard.VKey = VK_MENU;
320 break;
321 default:
322 rawinput->data.keyboard.VKey = msg_data->rawinput.kbd.vkey;
323 break;
326 rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message;
327 rawinput->data.keyboard.ExtraInformation = msg_data->info;
329 else
331 FIXME("Unhandled rawinput type %#x.\n", msg_data->rawinput.type);
332 return FALSE;
335 return TRUE;
339 /***********************************************************************
340 * GetRawInputDeviceList (USER32.@)
342 UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_count, UINT size)
344 UINT i;
346 TRACE("devices %p, device_count %p, size %u.\n", devices, device_count, size);
348 if (size != sizeof(*devices))
350 SetLastError(ERROR_INVALID_PARAMETER);
351 return ~0U;
354 if (!device_count)
356 SetLastError(ERROR_NOACCESS);
357 return ~0U;
360 find_devices();
362 if (!devices)
364 *device_count = 2 + rawinput_devices_count;
365 return 0;
368 if (*device_count < 2 + rawinput_devices_count)
370 SetLastError(ERROR_INSUFFICIENT_BUFFER);
371 *device_count = 2 + rawinput_devices_count;
372 return ~0U;
375 devices[0].hDevice = WINE_MOUSE_HANDLE;
376 devices[0].dwType = RIM_TYPEMOUSE;
377 devices[1].hDevice = WINE_KEYBOARD_HANDLE;
378 devices[1].dwType = RIM_TYPEKEYBOARD;
380 for (i = 0; i < rawinput_devices_count; ++i)
382 devices[2 + i].hDevice = &rawinput_devices[i];
383 devices[2 + i].dwType = rawinput_devices[i].info.dwType;
386 return 2 + rawinput_devices_count;
389 /***********************************************************************
390 * RegisterRawInputDevices (USER32.@)
392 BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, UINT device_count, UINT size)
394 struct rawinput_device *d;
395 BOOL ret;
396 UINT i;
398 TRACE("devices %p, device_count %u, size %u.\n", devices, device_count, size);
400 if (size != sizeof(*devices))
402 WARN("Invalid structure size %u.\n", size);
403 SetLastError(ERROR_INVALID_PARAMETER);
404 return FALSE;
407 for (i = 0; i < device_count; ++i)
409 if ((devices[i].dwFlags & RIDEV_INPUTSINK) &&
410 (devices[i].hwndTarget == NULL))
412 SetLastError(ERROR_INVALID_PARAMETER);
413 return FALSE;
416 if ((devices[i].dwFlags & RIDEV_REMOVE) &&
417 (devices[i].hwndTarget != NULL))
419 SetLastError(ERROR_INVALID_PARAMETER);
420 return FALSE;
424 if (!(d = HeapAlloc( GetProcessHeap(), 0, device_count * sizeof(*d) ))) return FALSE;
426 for (i = 0; i < device_count; ++i)
428 TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n",
429 i, devices[i].usUsagePage, devices[i].usUsage,
430 devices[i].dwFlags, devices[i].hwndTarget);
431 if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK))
432 FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
434 d[i].usage_page = devices[i].usUsagePage;
435 d[i].usage = devices[i].usUsage;
436 d[i].flags = devices[i].dwFlags;
437 d[i].target = wine_server_user_handle( devices[i].hwndTarget );
440 SERVER_START_REQ( update_rawinput_devices )
442 wine_server_add_data( req, d, device_count * sizeof(*d) );
443 ret = !wine_server_call( req );
445 SERVER_END_REQ;
447 HeapFree( GetProcessHeap(), 0, d );
449 return ret;
452 /***********************************************************************
453 * GetRawInputData (USER32.@)
455 UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size)
457 struct rawinput_thread_data *thread_data = rawinput_thread_data();
458 UINT size;
460 TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
461 rawinput, command, data, data_size, header_size);
463 if (!rawinput || thread_data->hw_id != (UINT_PTR)rawinput)
465 SetLastError(ERROR_INVALID_HANDLE);
466 return ~0U;
469 if (header_size != sizeof(RAWINPUTHEADER))
471 WARN("Invalid structure size %u.\n", header_size);
472 SetLastError(ERROR_INVALID_PARAMETER);
473 return ~0U;
476 switch (command)
478 case RID_INPUT:
479 size = thread_data->buffer->header.dwSize;
480 break;
481 case RID_HEADER:
482 size = sizeof(RAWINPUTHEADER);
483 break;
484 default:
485 SetLastError(ERROR_INVALID_PARAMETER);
486 return ~0U;
489 if (!data)
491 *data_size = size;
492 return 0;
495 if (*data_size < size)
497 SetLastError(ERROR_INSUFFICIENT_BUFFER);
498 return ~0U;
500 memcpy(data, thread_data->buffer, size);
501 return size;
504 #ifdef _WIN64
505 typedef RAWINPUT RAWINPUT64;
506 #else
507 typedef struct
509 RAWINPUTHEADER header;
510 char pad[8];
511 union {
512 RAWMOUSE mouse;
513 RAWKEYBOARD keyboard;
514 RAWHID hid;
515 } data;
516 } RAWINPUT64;
517 #endif
519 /***********************************************************************
520 * GetRawInputBuffer (USER32.@)
522 UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size, UINT header_size)
524 struct hardware_msg_data *msg_data;
525 struct rawinput_thread_data *thread_data;
526 RAWINPUT *rawinput;
527 UINT count = 0, rawinput_size, next_size, overhead;
528 BOOL is_wow64;
529 int i;
531 if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64)
532 rawinput_size = sizeof(RAWINPUT64);
533 else
534 rawinput_size = sizeof(RAWINPUT);
535 overhead = rawinput_size - sizeof(RAWINPUT);
537 if (header_size != sizeof(RAWINPUTHEADER))
539 WARN("Invalid structure size %u.\n", header_size);
540 SetLastError(ERROR_INVALID_PARAMETER);
541 return ~0U;
544 if (!data_size)
546 SetLastError(ERROR_INVALID_PARAMETER);
547 return ~0U;
550 if (!data)
552 TRACE("data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size);
553 SERVER_START_REQ( get_rawinput_buffer )
555 req->rawinput_size = rawinput_size;
556 req->buffer_size = 0;
557 if (wine_server_call( req )) return ~0U;
558 *data_size = reply->next_size;
560 SERVER_END_REQ;
561 return 0;
564 if (!(thread_data = rawinput_thread_data())) return ~0U;
565 rawinput = thread_data->buffer;
567 /* first RAWINPUT block in the buffer is used for WM_INPUT message data */
568 msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput);
569 SERVER_START_REQ( get_rawinput_buffer )
571 req->rawinput_size = rawinput_size;
572 req->buffer_size = *data_size;
573 wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize );
574 if (wine_server_call( req )) return ~0U;
575 next_size = reply->next_size;
576 count = reply->count;
578 SERVER_END_REQ;
580 for (i = 0; i < count; ++i)
582 rawinput_from_hardware_message(data, msg_data);
583 if (overhead) memmove((char *)&data->data + overhead, &data->data,
584 data->header.dwSize - sizeof(RAWINPUTHEADER));
585 data->header.dwSize += overhead;
586 data = NEXTRAWINPUTBLOCK(data);
587 msg_data++;
590 if (count == 0 && next_size == 0) *data_size = 0;
591 else if (next_size == 0) next_size = rawinput_size;
593 if (next_size && *data_size <= next_size)
595 SetLastError(ERROR_INSUFFICIENT_BUFFER);
596 *data_size = next_size;
597 count = ~0U;
600 if (count) TRACE("data %p, data_size %p (%u), header_size %u, count %u\n", data, data_size, *data_size, header_size, count);
601 return count;
604 /***********************************************************************
605 * GetRawInputDeviceInfoA (USER32.@)
607 UINT WINAPI GetRawInputDeviceInfoA(HANDLE device, UINT command, void *data, UINT *data_size)
609 TRACE("device %p, command %#x, data %p, data_size %p.\n",
610 device, command, data, data_size);
612 /* RIDI_DEVICENAME data_size is in chars, not bytes */
613 if (command == RIDI_DEVICENAME)
615 WCHAR *nameW;
616 UINT ret, nameW_sz;
618 if (!data_size) return ~0U;
620 nameW_sz = *data_size;
622 if (data && nameW_sz > 0)
623 nameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nameW_sz);
624 else
625 nameW = NULL;
627 ret = GetRawInputDeviceInfoW(device, command, nameW, &nameW_sz);
629 if (ret && ret != ~0U)
630 WideCharToMultiByte(CP_ACP, 0, nameW, -1, data, *data_size, NULL, NULL);
632 *data_size = nameW_sz;
634 HeapFree(GetProcessHeap(), 0, nameW);
636 return ret;
639 return GetRawInputDeviceInfoW(device, command, data, data_size);
642 /***********************************************************************
643 * GetRawInputDeviceInfoW (USER32.@)
645 UINT WINAPI GetRawInputDeviceInfoW(HANDLE handle, UINT command, void *data, UINT *data_size)
647 /* FIXME: Most of this is made up. */
648 static const RID_DEVICE_INFO_KEYBOARD keyboard_info = {0, 0, 1, 12, 3, 101};
649 static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE};
651 RID_DEVICE_INFO info;
652 struct device *device = handle;
653 const void *to_copy;
654 UINT to_copy_bytes, avail_bytes;
656 TRACE("handle %p, command %#x, data %p, data_size %p.\n",
657 handle, command, data, data_size);
659 if (!data_size) return ~0U;
661 /* each case below must set:
662 * *data_size: length (meaning defined by command) of data we want to copy
663 * avail_bytes: number of bytes available in user buffer
664 * to_copy_bytes: number of bytes we want to copy into user buffer
665 * to_copy: pointer to data we want to copy into user buffer
667 switch (command)
669 case RIDI_DEVICENAME:
670 /* for RIDI_DEVICENAME, data_size is in characters, not bytes */
671 avail_bytes = *data_size * sizeof(WCHAR);
672 if (handle == WINE_MOUSE_HANDLE)
674 *data_size = ARRAY_SIZE(L"\\\\?\\WINE_MOUSE");
675 to_copy = L"\\\\?\\WINE_MOUSE";
677 else if (handle == WINE_KEYBOARD_HANDLE)
679 *data_size = ARRAY_SIZE(L"\\\\?\\WINE_KEYBOARD");
680 to_copy = L"\\\\?\\WINE_KEYBOARD";
682 else
684 *data_size = lstrlenW(device->path) + 1;
685 to_copy = device->path;
687 to_copy_bytes = *data_size * sizeof(WCHAR);
688 break;
690 case RIDI_DEVICEINFO:
691 avail_bytes = *data_size;
692 info.cbSize = sizeof(info);
693 if (handle == WINE_MOUSE_HANDLE)
695 info.dwType = RIM_TYPEMOUSE;
696 info.u.mouse = mouse_info;
698 else if (handle == WINE_KEYBOARD_HANDLE)
700 info.dwType = RIM_TYPEKEYBOARD;
701 info.u.keyboard = keyboard_info;
703 else
705 info = device->info;
707 to_copy_bytes = sizeof(info);
708 *data_size = to_copy_bytes;
709 to_copy = &info;
710 break;
712 case RIDI_PREPARSEDDATA:
713 avail_bytes = *data_size;
714 if (handle == WINE_MOUSE_HANDLE || handle == WINE_KEYBOARD_HANDLE ||
715 device->info.dwType != RIM_TYPEHID)
717 to_copy_bytes = 0;
718 *data_size = 0;
719 to_copy = NULL;
721 else
723 to_copy_bytes = ((WINE_HIDP_PREPARSED_DATA*)device->data)->dwSize;
724 *data_size = to_copy_bytes;
725 to_copy = device->data;
727 break;
729 default:
730 FIXME("command %#x not supported\n", command);
731 return ~0U;
734 if (!data)
735 return 0;
737 if (avail_bytes < to_copy_bytes)
738 return ~0U;
740 memcpy(data, to_copy, to_copy_bytes);
742 return *data_size;
745 static int __cdecl compare_raw_input_devices(const void *ap, const void *bp)
747 const RAWINPUTDEVICE a = *(const RAWINPUTDEVICE *)ap;
748 const RAWINPUTDEVICE b = *(const RAWINPUTDEVICE *)bp;
750 if (a.usUsagePage != b.usUsagePage) return a.usUsagePage - b.usUsagePage;
751 if (a.usUsage != b.usUsage) return a.usUsage - b.usUsage;
752 return 0;
755 /***********************************************************************
756 * GetRegisteredRawInputDevices (USER32.@)
758 UINT WINAPI DECLSPEC_HOTPATCH GetRegisteredRawInputDevices(RAWINPUTDEVICE *devices, UINT *device_count, UINT size)
760 struct rawinput_device *buffer = NULL;
761 unsigned int i, status, count = ~0U, buffer_size;
763 TRACE("devices %p, device_count %p, size %u\n", devices, device_count, size);
765 if (size != sizeof(RAWINPUTDEVICE) || !device_count || (devices && !*device_count))
767 SetLastError(ERROR_INVALID_PARAMETER);
768 return ~0U;
771 buffer_size = *device_count * sizeof(*buffer);
772 if (devices && !(buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size)))
773 return ~0U;
775 SERVER_START_REQ(get_rawinput_devices)
777 if (buffer) wine_server_set_reply(req, buffer, buffer_size);
778 status = wine_server_call_err(req);
779 *device_count = reply->device_count;
781 SERVER_END_REQ;
783 if (buffer && !status)
785 for (i = 0, count = *device_count; i < count; ++i)
787 devices[i].usUsagePage = buffer[i].usage_page;
788 devices[i].usUsage = buffer[i].usage;
789 devices[i].dwFlags = buffer[i].flags;
790 devices[i].hwndTarget = wine_server_ptr_handle(buffer[i].target);
793 qsort(devices, count, sizeof(*devices), compare_raw_input_devices);
796 if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
797 else count = 0;
798 return count;
802 /***********************************************************************
803 * DefRawInputProc (USER32.@)
805 LRESULT WINAPI DefRawInputProc(RAWINPUT **data, INT data_count, UINT header_size)
807 FIXME("data %p, data_count %d, header_size %u stub!\n", data, data_count, header_size);
809 return 0;