user32: Free rawinput device preparsed data for mouse and keyboard.
[wine.git] / dlls / user32 / rawinput.c
blob1e66b394cb5d971d51565d49b7b4fa3b45c6781a
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 "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;
102 UINT32 handle;
103 HANDLE file;
104 DWORD i, size, type;
106 SetupDiGetDeviceInterfaceDetailW(set, iface, NULL, 0, &size, &device_data);
107 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
109 ERR("Failed to get device path, error %#x.\n", GetLastError());
110 return FALSE;
113 if (!SetupDiGetDevicePropertyW(set, &device_data, &DEVPROPKEY_HID_HANDLE, &type, (BYTE *)&handle, sizeof(handle), NULL, 0) ||
114 type != DEVPROP_TYPE_UINT32)
116 ERR("Failed to get device handle, error %#x.\n", GetLastError());
117 return NULL;
120 for (i = 0; i < rawinput_devices_count; ++i)
122 if (rawinput_devices[i].handle == UlongToHandle(handle))
124 TRACE("Updating device %x / %s\n", handle, debugstr_w(rawinput_devices[i].detail->DevicePath));
125 return rawinput_devices + i;
129 if (!(detail = malloc(size)))
131 ERR("Failed to allocate memory.\n");
132 return FALSE;
134 detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
135 SetupDiGetDeviceInterfaceDetailW(set, iface, detail, size, NULL, NULL);
137 TRACE("Found device %x / %s.\n", handle, debugstr_w(detail->DevicePath));
139 file = CreateFileW(detail->DevicePath, GENERIC_READ | GENERIC_WRITE,
140 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
141 if (file == INVALID_HANDLE_VALUE)
143 ERR("Failed to open device file %s, error %u.\n", debugstr_w(detail->DevicePath), GetLastError());
144 free(detail);
145 return NULL;
148 if (!array_reserve((void **)&rawinput_devices, &rawinput_devices_max,
149 rawinput_devices_count + 1, sizeof(*rawinput_devices)))
151 ERR("Failed to allocate memory.\n");
152 CloseHandle(file);
153 free(detail);
154 return NULL;
157 device = &rawinput_devices[rawinput_devices_count++];
158 device->detail = detail;
159 device->file = file;
160 device->handle = ULongToHandle(handle);
161 device->info.cbSize = sizeof(RID_DEVICE_INFO);
162 device->data = NULL;
164 return device;
167 static void find_devices(void)
169 SP_DEVICE_INTERFACE_DATA iface = { sizeof(iface) };
170 struct device *device;
171 HIDD_ATTRIBUTES attr;
172 HIDP_CAPS caps;
173 GUID hid_guid;
174 HDEVINFO set;
175 DWORD idx;
177 HidD_GetHidGuid(&hid_guid);
179 EnterCriticalSection(&rawinput_devices_cs);
181 /* destroy previous list */
182 for (idx = 0; idx < rawinput_devices_count; ++idx)
184 HidD_FreePreparsedData(rawinput_devices[idx].data);
185 CloseHandle(rawinput_devices[idx].file);
186 free(rawinput_devices[idx].detail);
188 rawinput_devices_count = 0;
190 set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
192 for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &hid_guid, idx, &iface); ++idx)
194 if (!(device = add_device(set, &iface)))
195 continue;
197 attr.Size = sizeof(HIDD_ATTRIBUTES);
198 if (!HidD_GetAttributes(device->file, &attr))
199 WARN("Failed to get attributes.\n");
201 device->info.dwType = RIM_TYPEHID;
202 device->info.u.hid.dwVendorId = attr.VendorID;
203 device->info.u.hid.dwProductId = attr.ProductID;
204 device->info.u.hid.dwVersionNumber = attr.VersionNumber;
206 if (!HidD_GetPreparsedData(device->file, &device->data))
207 WARN("Failed to get preparsed data.\n");
209 if (!HidP_GetCaps(device->data, &caps))
210 WARN("Failed to get caps.\n");
212 device->info.u.hid.usUsagePage = caps.UsagePage;
213 device->info.u.hid.usUsage = caps.Usage;
216 SetupDiDestroyDeviceInfoList(set);
218 set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_MOUSE, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
220 for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_MOUSE, idx, &iface); ++idx)
222 static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE};
224 if (!(device = add_device(set, &iface)))
225 continue;
227 device->info.dwType = RIM_TYPEMOUSE;
228 device->info.u.mouse = mouse_info;
229 HidD_FreePreparsedData(device->data);
230 device->data = NULL;
233 SetupDiDestroyDeviceInfoList(set);
235 set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_KEYBOARD, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
237 for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_KEYBOARD, idx, &iface); ++idx)
239 static const RID_DEVICE_INFO_KEYBOARD keyboard_info = {0, 0, 1, 12, 3, 101};
241 if (!(device = add_device(set, &iface)))
242 continue;
244 device->info.dwType = RIM_TYPEKEYBOARD;
245 device->info.u.keyboard = keyboard_info;
246 HidD_FreePreparsedData(device->data);
247 device->data = NULL;
250 SetupDiDestroyDeviceInfoList(set);
252 LeaveCriticalSection(&rawinput_devices_cs);
256 static struct device *find_device_from_handle(HANDLE handle)
258 UINT i;
259 for (i = 0; i < rawinput_devices_count; ++i)
260 if (rawinput_devices[i].handle == handle)
261 return rawinput_devices + i;
262 find_devices();
263 for (i = 0; i < rawinput_devices_count; ++i)
264 if (rawinput_devices[i].handle == handle)
265 return rawinput_devices + i;
266 return NULL;
270 struct rawinput_thread_data *rawinput_thread_data(void)
272 struct user_thread_info *thread_info = get_user_thread_info();
273 struct rawinput_thread_data *data = thread_info->rawinput;
274 if (data) return data;
275 data = thread_info->rawinput = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
276 RAWINPUT_BUFFER_SIZE + sizeof(struct user_thread_info) );
277 return data;
281 BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hardware_msg_data *msg_data)
283 rawinput->header.dwType = msg_data->rawinput.type;
284 if (msg_data->rawinput.type == RIM_TYPEMOUSE)
286 static const unsigned int button_flags[] =
288 0, /* MOUSEEVENTF_MOVE */
289 RI_MOUSE_LEFT_BUTTON_DOWN, /* MOUSEEVENTF_LEFTDOWN */
290 RI_MOUSE_LEFT_BUTTON_UP, /* MOUSEEVENTF_LEFTUP */
291 RI_MOUSE_RIGHT_BUTTON_DOWN, /* MOUSEEVENTF_RIGHTDOWN */
292 RI_MOUSE_RIGHT_BUTTON_UP, /* MOUSEEVENTF_RIGHTUP */
293 RI_MOUSE_MIDDLE_BUTTON_DOWN, /* MOUSEEVENTF_MIDDLEDOWN */
294 RI_MOUSE_MIDDLE_BUTTON_UP, /* MOUSEEVENTF_MIDDLEUP */
296 unsigned int i;
298 rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWMOUSE);
299 rawinput->header.hDevice = WINE_MOUSE_HANDLE;
300 rawinput->header.wParam = 0;
302 rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE;
303 rawinput->data.mouse.u.s.usButtonFlags = 0;
304 rawinput->data.mouse.u.s.usButtonData = 0;
305 for (i = 1; i < ARRAY_SIZE(button_flags); ++i)
307 if (msg_data->flags & (1 << i))
308 rawinput->data.mouse.u.s.usButtonFlags |= button_flags[i];
310 if (msg_data->flags & MOUSEEVENTF_WHEEL)
312 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_WHEEL;
313 rawinput->data.mouse.u.s.usButtonData = msg_data->rawinput.mouse.data;
315 if (msg_data->flags & MOUSEEVENTF_HWHEEL)
317 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_HORIZONTAL_WHEEL;
318 rawinput->data.mouse.u.s.usButtonData = msg_data->rawinput.mouse.data;
320 if (msg_data->flags & MOUSEEVENTF_XDOWN)
322 if (msg_data->rawinput.mouse.data == XBUTTON1)
323 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN;
324 else if (msg_data->rawinput.mouse.data == XBUTTON2)
325 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN;
327 if (msg_data->flags & MOUSEEVENTF_XUP)
329 if (msg_data->rawinput.mouse.data == XBUTTON1)
330 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_4_UP;
331 else if (msg_data->rawinput.mouse.data == XBUTTON2)
332 rawinput->data.mouse.u.s.usButtonFlags |= RI_MOUSE_BUTTON_5_UP;
335 rawinput->data.mouse.ulRawButtons = 0;
336 rawinput->data.mouse.lLastX = msg_data->rawinput.mouse.x;
337 rawinput->data.mouse.lLastY = msg_data->rawinput.mouse.y;
338 rawinput->data.mouse.ulExtraInformation = msg_data->info;
340 else if (msg_data->rawinput.type == RIM_TYPEKEYBOARD)
342 rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWKEYBOARD);
343 rawinput->header.hDevice = WINE_KEYBOARD_HANDLE;
344 rawinput->header.wParam = 0;
346 rawinput->data.keyboard.MakeCode = msg_data->rawinput.kbd.scan;
347 rawinput->data.keyboard.Flags = msg_data->flags & KEYEVENTF_KEYUP ? RI_KEY_BREAK : RI_KEY_MAKE;
348 if (msg_data->flags & KEYEVENTF_EXTENDEDKEY) rawinput->data.keyboard.Flags |= RI_KEY_E0;
349 rawinput->data.keyboard.Reserved = 0;
351 switch (msg_data->rawinput.kbd.vkey)
353 case VK_LSHIFT:
354 case VK_RSHIFT:
355 rawinput->data.keyboard.VKey = VK_SHIFT;
356 rawinput->data.keyboard.Flags &= ~RI_KEY_E0;
357 break;
358 case VK_LCONTROL:
359 case VK_RCONTROL:
360 rawinput->data.keyboard.VKey = VK_CONTROL;
361 break;
362 case VK_LMENU:
363 case VK_RMENU:
364 rawinput->data.keyboard.VKey = VK_MENU;
365 break;
366 default:
367 rawinput->data.keyboard.VKey = msg_data->rawinput.kbd.vkey;
368 break;
371 rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message;
372 rawinput->data.keyboard.ExtraInformation = msg_data->info;
374 else
376 FIXME("Unhandled rawinput type %#x.\n", msg_data->rawinput.type);
377 return FALSE;
380 return TRUE;
384 /***********************************************************************
385 * GetRawInputDeviceList (USER32.@)
387 UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_count, UINT size)
389 UINT i;
391 TRACE("devices %p, device_count %p, size %u.\n", devices, device_count, size);
393 if (size != sizeof(*devices))
395 SetLastError(ERROR_INVALID_PARAMETER);
396 return ~0U;
399 if (!device_count)
401 SetLastError(ERROR_NOACCESS);
402 return ~0U;
405 find_devices();
407 if (!devices)
409 *device_count = rawinput_devices_count;
410 return 0;
413 if (*device_count < rawinput_devices_count)
415 SetLastError(ERROR_INSUFFICIENT_BUFFER);
416 *device_count = rawinput_devices_count;
417 return ~0U;
420 for (i = 0; i < rawinput_devices_count; ++i)
422 devices[i].hDevice = rawinput_devices[i].handle;
423 devices[i].dwType = rawinput_devices[i].info.dwType;
426 return rawinput_devices_count;
429 /***********************************************************************
430 * RegisterRawInputDevices (USER32.@)
432 BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, UINT device_count, UINT size)
434 struct rawinput_device *d;
435 BOOL ret;
436 UINT i;
438 TRACE("devices %p, device_count %u, size %u.\n", devices, device_count, size);
440 if (size != sizeof(*devices))
442 WARN("Invalid structure size %u.\n", size);
443 SetLastError(ERROR_INVALID_PARAMETER);
444 return FALSE;
447 for (i = 0; i < device_count; ++i)
449 if ((devices[i].dwFlags & RIDEV_INPUTSINK) &&
450 (devices[i].hwndTarget == NULL))
452 SetLastError(ERROR_INVALID_PARAMETER);
453 return FALSE;
456 if ((devices[i].dwFlags & RIDEV_REMOVE) &&
457 (devices[i].hwndTarget != NULL))
459 SetLastError(ERROR_INVALID_PARAMETER);
460 return FALSE;
464 if (!(d = HeapAlloc( GetProcessHeap(), 0, device_count * sizeof(*d) ))) return FALSE;
466 for (i = 0; i < device_count; ++i)
468 TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n",
469 i, devices[i].usUsagePage, devices[i].usUsage,
470 devices[i].dwFlags, devices[i].hwndTarget);
471 if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK))
472 FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
474 d[i].usage_page = devices[i].usUsagePage;
475 d[i].usage = devices[i].usUsage;
476 d[i].flags = devices[i].dwFlags;
477 d[i].target = wine_server_user_handle( devices[i].hwndTarget );
480 SERVER_START_REQ( update_rawinput_devices )
482 wine_server_add_data( req, d, device_count * sizeof(*d) );
483 ret = !wine_server_call( req );
485 SERVER_END_REQ;
487 HeapFree( GetProcessHeap(), 0, d );
489 return ret;
492 /***********************************************************************
493 * GetRawInputData (USER32.@)
495 UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size)
497 struct rawinput_thread_data *thread_data = rawinput_thread_data();
498 UINT size;
500 TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
501 rawinput, command, data, data_size, header_size);
503 if (!rawinput || thread_data->hw_id != (UINT_PTR)rawinput)
505 SetLastError(ERROR_INVALID_HANDLE);
506 return ~0U;
509 if (header_size != sizeof(RAWINPUTHEADER))
511 WARN("Invalid structure size %u.\n", header_size);
512 SetLastError(ERROR_INVALID_PARAMETER);
513 return ~0U;
516 switch (command)
518 case RID_INPUT:
519 size = thread_data->buffer->header.dwSize;
520 break;
521 case RID_HEADER:
522 size = sizeof(RAWINPUTHEADER);
523 break;
524 default:
525 SetLastError(ERROR_INVALID_PARAMETER);
526 return ~0U;
529 if (!data)
531 *data_size = size;
532 return 0;
535 if (*data_size < size)
537 SetLastError(ERROR_INSUFFICIENT_BUFFER);
538 return ~0U;
540 memcpy(data, thread_data->buffer, size);
541 return size;
544 #ifdef _WIN64
545 typedef RAWINPUT RAWINPUT64;
546 #else
547 typedef struct
549 RAWINPUTHEADER header;
550 char pad[8];
551 union {
552 RAWMOUSE mouse;
553 RAWKEYBOARD keyboard;
554 RAWHID hid;
555 } data;
556 } RAWINPUT64;
557 #endif
559 /***********************************************************************
560 * GetRawInputBuffer (USER32.@)
562 UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size, UINT header_size)
564 struct hardware_msg_data *msg_data;
565 struct rawinput_thread_data *thread_data;
566 RAWINPUT *rawinput;
567 UINT count = 0, rawinput_size, next_size, overhead;
568 BOOL is_wow64;
569 int i;
571 if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64)
572 rawinput_size = sizeof(RAWINPUT64);
573 else
574 rawinput_size = sizeof(RAWINPUT);
575 overhead = rawinput_size - sizeof(RAWINPUT);
577 if (header_size != sizeof(RAWINPUTHEADER))
579 WARN("Invalid structure size %u.\n", header_size);
580 SetLastError(ERROR_INVALID_PARAMETER);
581 return ~0U;
584 if (!data_size)
586 SetLastError(ERROR_INVALID_PARAMETER);
587 return ~0U;
590 if (!data)
592 TRACE("data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size);
593 SERVER_START_REQ( get_rawinput_buffer )
595 req->rawinput_size = rawinput_size;
596 req->buffer_size = 0;
597 if (wine_server_call( req )) return ~0U;
598 *data_size = reply->next_size;
600 SERVER_END_REQ;
601 return 0;
604 if (!(thread_data = rawinput_thread_data())) return ~0U;
605 rawinput = thread_data->buffer;
607 /* first RAWINPUT block in the buffer is used for WM_INPUT message data */
608 msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput);
609 SERVER_START_REQ( get_rawinput_buffer )
611 req->rawinput_size = rawinput_size;
612 req->buffer_size = *data_size;
613 wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize );
614 if (wine_server_call( req )) return ~0U;
615 next_size = reply->next_size;
616 count = reply->count;
618 SERVER_END_REQ;
620 for (i = 0; i < count; ++i)
622 rawinput_from_hardware_message(data, msg_data);
623 if (overhead) memmove((char *)&data->data + overhead, &data->data,
624 data->header.dwSize - sizeof(RAWINPUTHEADER));
625 data->header.dwSize += overhead;
626 data = NEXTRAWINPUTBLOCK(data);
627 msg_data++;
630 if (count == 0 && next_size == 0) *data_size = 0;
631 else if (next_size == 0) next_size = rawinput_size;
633 if (next_size && *data_size <= next_size)
635 SetLastError(ERROR_INSUFFICIENT_BUFFER);
636 *data_size = next_size;
637 count = ~0U;
640 if (count) TRACE("data %p, data_size %p (%u), header_size %u, count %u\n", data, data_size, *data_size, header_size, count);
641 return count;
644 /***********************************************************************
645 * GetRawInputDeviceInfoA (USER32.@)
647 UINT WINAPI GetRawInputDeviceInfoA(HANDLE device, UINT command, void *data, UINT *data_size)
649 TRACE("device %p, command %#x, data %p, data_size %p.\n",
650 device, command, data, data_size);
652 /* RIDI_DEVICENAME data_size is in chars, not bytes */
653 if (command == RIDI_DEVICENAME)
655 WCHAR *nameW;
656 UINT ret, nameW_sz;
658 if (!data_size) return ~0U;
660 nameW_sz = *data_size;
662 if (data && nameW_sz > 0)
663 nameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nameW_sz);
664 else
665 nameW = NULL;
667 ret = GetRawInputDeviceInfoW(device, command, nameW, &nameW_sz);
669 if (ret && ret != ~0U)
670 WideCharToMultiByte(CP_ACP, 0, nameW, -1, data, *data_size, NULL, NULL);
672 *data_size = nameW_sz;
674 HeapFree(GetProcessHeap(), 0, nameW);
676 return ret;
679 return GetRawInputDeviceInfoW(device, command, data, data_size);
682 /***********************************************************************
683 * GetRawInputDeviceInfoW (USER32.@)
685 UINT WINAPI GetRawInputDeviceInfoW(HANDLE handle, UINT command, void *data, UINT *data_size)
687 /* FIXME: Most of this is made up. */
688 static const RID_DEVICE_INFO_KEYBOARD keyboard_info = {0, 0, 1, 12, 3, 101};
689 static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE};
691 RID_DEVICE_INFO info;
692 struct device *device;
693 const void *to_copy;
694 UINT to_copy_bytes, avail_bytes;
696 TRACE("handle %p, command %#x, data %p, data_size %p.\n",
697 handle, command, data, data_size);
699 if (!data_size) return ~0U;
700 if (!(device = find_device_from_handle(handle))) return ~0U;
702 /* each case below must set:
703 * *data_size: length (meaning defined by command) of data we want to copy
704 * avail_bytes: number of bytes available in user buffer
705 * to_copy_bytes: number of bytes we want to copy into user buffer
706 * to_copy: pointer to data we want to copy into user buffer
708 switch (command)
710 case RIDI_DEVICENAME:
711 /* for RIDI_DEVICENAME, data_size is in characters, not bytes */
712 avail_bytes = *data_size * sizeof(WCHAR);
713 if (handle == WINE_MOUSE_HANDLE)
715 *data_size = ARRAY_SIZE(L"\\\\?\\WINE_MOUSE");
716 to_copy = L"\\\\?\\WINE_MOUSE";
718 else if (handle == WINE_KEYBOARD_HANDLE)
720 *data_size = ARRAY_SIZE(L"\\\\?\\WINE_KEYBOARD");
721 to_copy = L"\\\\?\\WINE_KEYBOARD";
723 else
725 *data_size = wcslen(device->detail->DevicePath) + 1;
726 to_copy = device->detail->DevicePath;
728 to_copy_bytes = *data_size * sizeof(WCHAR);
729 break;
731 case RIDI_DEVICEINFO:
732 avail_bytes = *data_size;
733 info.cbSize = sizeof(info);
734 if (handle == WINE_MOUSE_HANDLE)
736 info.dwType = RIM_TYPEMOUSE;
737 info.u.mouse = mouse_info;
739 else if (handle == WINE_KEYBOARD_HANDLE)
741 info.dwType = RIM_TYPEKEYBOARD;
742 info.u.keyboard = keyboard_info;
744 else
746 info = device->info;
748 to_copy_bytes = sizeof(info);
749 *data_size = to_copy_bytes;
750 to_copy = &info;
751 break;
753 case RIDI_PREPARSEDDATA:
754 avail_bytes = *data_size;
755 if (handle == WINE_MOUSE_HANDLE || handle == WINE_KEYBOARD_HANDLE ||
756 device->info.dwType != RIM_TYPEHID)
758 to_copy_bytes = 0;
759 *data_size = 0;
760 to_copy = NULL;
762 else
764 to_copy_bytes = ((WINE_HIDP_PREPARSED_DATA*)device->data)->dwSize;
765 *data_size = to_copy_bytes;
766 to_copy = device->data;
768 break;
770 default:
771 FIXME("command %#x not supported\n", command);
772 return ~0U;
775 if (!data)
776 return 0;
778 if (avail_bytes < to_copy_bytes)
779 return ~0U;
781 memcpy(data, to_copy, to_copy_bytes);
783 return *data_size;
786 static int __cdecl compare_raw_input_devices(const void *ap, const void *bp)
788 const RAWINPUTDEVICE a = *(const RAWINPUTDEVICE *)ap;
789 const RAWINPUTDEVICE b = *(const RAWINPUTDEVICE *)bp;
791 if (a.usUsagePage != b.usUsagePage) return a.usUsagePage - b.usUsagePage;
792 if (a.usUsage != b.usUsage) return a.usUsage - b.usUsage;
793 return 0;
796 /***********************************************************************
797 * GetRegisteredRawInputDevices (USER32.@)
799 UINT WINAPI DECLSPEC_HOTPATCH GetRegisteredRawInputDevices(RAWINPUTDEVICE *devices, UINT *device_count, UINT size)
801 struct rawinput_device *buffer = NULL;
802 unsigned int i, status, count = ~0U, buffer_size;
804 TRACE("devices %p, device_count %p, size %u\n", devices, device_count, size);
806 if (size != sizeof(RAWINPUTDEVICE) || !device_count || (devices && !*device_count))
808 SetLastError(ERROR_INVALID_PARAMETER);
809 return ~0U;
812 buffer_size = *device_count * sizeof(*buffer);
813 if (devices && !(buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size)))
814 return ~0U;
816 SERVER_START_REQ(get_rawinput_devices)
818 if (buffer) wine_server_set_reply(req, buffer, buffer_size);
819 status = wine_server_call_err(req);
820 *device_count = reply->device_count;
822 SERVER_END_REQ;
824 if (buffer && !status)
826 for (i = 0, count = *device_count; i < count; ++i)
828 devices[i].usUsagePage = buffer[i].usage_page;
829 devices[i].usUsage = buffer[i].usage;
830 devices[i].dwFlags = buffer[i].flags;
831 devices[i].hwndTarget = wine_server_ptr_handle(buffer[i].target);
834 qsort(devices, count, sizeof(*devices), compare_raw_input_devices);
837 if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
838 else count = 0;
839 return count;
843 /***********************************************************************
844 * DefRawInputProc (USER32.@)
846 LRESULT WINAPI DefRawInputProc(RAWINPUT **data, INT data_count, UINT header_size)
848 FIXME("data %p, data_count %d, header_size %u stub!\n", data, data_count, header_size);
850 return 0;