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
25 #define WIN32_NO_STATUS
33 #include "ddk/hidsdi.h"
34 #include "wine/debug.h"
35 #include "wine/server.h"
38 #include "user_private.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);
51 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*detail
;
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
;
75 if (count
<= *capacity
)
78 max_capacity
= ~(SIZE_T
)0 / size
;
79 if (count
> max_capacity
)
82 new_capacity
= max(4, *capacity
);
83 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
85 if (new_capacity
< count
)
86 new_capacity
= max_capacity
;
88 if (!(new_elements
= realloc(*elements
, new_capacity
* size
)))
91 *elements
= new_elements
;
92 *capacity
= new_capacity
;
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
;
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());
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());
121 if (!(detail
= malloc(size
)))
123 ERR("Failed to allocate memory.\n");
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());
141 for (i
= 0; i
< rawinput_devices_count
&& !device
; ++i
)
142 if (rawinput_devices
[i
].handle
== UlongToHandle(handle
))
143 device
= rawinput_devices
+ i
;
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
));
160 ERR("Failed to allocate memory.\n");
166 device
->detail
= detail
;
168 device
->handle
= ULongToHandle(handle
);
169 device
->info
.cbSize
= sizeof(RID_DEVICE_INFO
);
175 void rawinput_update_device_list(void)
177 SP_DEVICE_INTERFACE_DATA iface
= { sizeof(iface
) };
178 struct device
*device
;
179 HIDD_ATTRIBUTES attr
;
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
)))
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
)))
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
)))
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
)
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
;
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
;
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
) );
302 BOOL
rawinput_from_hardware_message(RAWINPUT
*rawinput
, const struct hardware_msg_data
*msg_data
)
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 */
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
)
378 rawinput
->data
.keyboard
.VKey
= VK_SHIFT
;
379 rawinput
->data
.keyboard
.Flags
&= ~RI_KEY_E0
;
383 rawinput
->data
.keyboard
.VKey
= VK_CONTROL
;
387 rawinput
->data
.keyboard
.VKey
= VK_MENU
;
390 rawinput
->data
.keyboard
.VKey
= msg_data
->rawinput
.kbd
.vkey
;
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
);
412 FIXME("Unhandled rawinput type %#x.\n", msg_data
->rawinput
.type
);
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
);
438 SetLastError(ERROR_NOACCESS
);
442 if (ticks
- last_check
> 2000)
445 rawinput_update_device_list();
450 *device_count
= rawinput_devices_count
;
454 if (*device_count
< rawinput_devices_count
)
456 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
457 *device_count
= rawinput_devices_count
;
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
;
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
);
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
);
497 if ((devices
[i
].dwFlags
& RIDEV_REMOVE
) &&
498 (devices
[i
].hwndTarget
!= NULL
))
500 SetLastError(ERROR_INVALID_PARAMETER
);
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
);
528 HeapFree( GetProcessHeap(), 0, d
);
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();
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
);
550 if (header_size
!= sizeof(RAWINPUTHEADER
))
552 WARN("Invalid structure size %u.\n", header_size
);
553 SetLastError(ERROR_INVALID_PARAMETER
);
560 size
= thread_data
->buffer
->header
.dwSize
;
563 size
= sizeof(RAWINPUTHEADER
);
566 SetLastError(ERROR_INVALID_PARAMETER
);
576 if (*data_size
< size
)
578 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
581 memcpy(data
, thread_data
->buffer
, size
);
586 typedef RAWINPUT RAWINPUT64
;
590 RAWINPUTHEADER header
;
594 RAWKEYBOARD keyboard
;
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
;
608 UINT count
= 0, remaining
, rawinput_size
, next_size
, overhead
;
612 if (IsWow64Process( GetCurrentProcess(), &is_wow64
) && is_wow64
)
613 rawinput_size
= sizeof(RAWINPUT64
);
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
);
627 SetLastError(ERROR_INVALID_PARAMETER
);
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
;
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
;
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
;
684 if (count
) TRACE("data %p, data_size %p (%u), header_size %u, count %u\n", data
, data_size
, *data_size
, header_size
, 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
)
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
);
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
);
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
;
736 TRACE("handle %p, command %#x, data %p, data_size %p.\n",
737 handle
, command
, data
, data_size
);
741 SetLastError(ERROR_NOACCESS
);
744 if (!(device
= find_device_from_handle(handle
)))
746 SetLastError(ERROR_INVALID_HANDLE
);
750 data_len
= *data_size
;
753 case RIDI_DEVICENAME
:
754 if ((len
= wcslen(device
->detail
->DevicePath
) + 1) <= data_len
&& data
)
755 memcpy(data
, device
->detail
->DevicePath
, len
* sizeof(WCHAR
));
759 case RIDI_DEVICEINFO
:
760 if ((len
= sizeof(info
)) <= data_len
&& data
)
761 memcpy(data
, &device
->info
, len
);
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
);
776 FIXME("command %#x not supported\n", command
);
777 SetLastError(ERROR_INVALID_PARAMETER
);
786 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
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
;
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
);
819 buffer_size
= *device_count
* sizeof(*buffer
);
820 if (devices
&& !(buffer
= HeapAlloc(GetProcessHeap(), 0, buffer_size
)))
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
;
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
);
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
);