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
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
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
;
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());
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());
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");
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());
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");
157 device
= &rawinput_devices
[rawinput_devices_count
++];
158 device
->detail
= detail
;
160 device
->handle
= ULongToHandle(handle
);
161 device
->info
.cbSize
= sizeof(RID_DEVICE_INFO
);
167 static void find_devices(void)
169 SP_DEVICE_INTERFACE_DATA iface
= { sizeof(iface
) };
170 struct device
*device
;
171 HIDD_ATTRIBUTES attr
;
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
)))
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
)))
227 device
->info
.dwType
= RIM_TYPEMOUSE
;
228 device
->info
.u
.mouse
= mouse_info
;
229 HidD_FreePreparsedData(device
->data
);
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
)))
244 device
->info
.dwType
= RIM_TYPEKEYBOARD
;
245 device
->info
.u
.keyboard
= keyboard_info
;
246 HidD_FreePreparsedData(device
->data
);
250 SetupDiDestroyDeviceInfoList(set
);
252 LeaveCriticalSection(&rawinput_devices_cs
);
256 static struct device
*find_device_from_handle(HANDLE handle
)
259 for (i
= 0; i
< rawinput_devices_count
; ++i
)
260 if (rawinput_devices
[i
].handle
== handle
)
261 return rawinput_devices
+ i
;
263 for (i
= 0; i
< rawinput_devices_count
; ++i
)
264 if (rawinput_devices
[i
].handle
== handle
)
265 return rawinput_devices
+ i
;
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
) );
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 */
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
)
355 rawinput
->data
.keyboard
.VKey
= VK_SHIFT
;
356 rawinput
->data
.keyboard
.Flags
&= ~RI_KEY_E0
;
360 rawinput
->data
.keyboard
.VKey
= VK_CONTROL
;
364 rawinput
->data
.keyboard
.VKey
= VK_MENU
;
367 rawinput
->data
.keyboard
.VKey
= msg_data
->rawinput
.kbd
.vkey
;
371 rawinput
->data
.keyboard
.Message
= msg_data
->rawinput
.kbd
.message
;
372 rawinput
->data
.keyboard
.ExtraInformation
= msg_data
->info
;
376 FIXME("Unhandled rawinput type %#x.\n", msg_data
->rawinput
.type
);
384 /***********************************************************************
385 * GetRawInputDeviceList (USER32.@)
387 UINT WINAPI
GetRawInputDeviceList(RAWINPUTDEVICELIST
*devices
, UINT
*device_count
, UINT size
)
391 TRACE("devices %p, device_count %p, size %u.\n", devices
, device_count
, size
);
393 if (size
!= sizeof(*devices
))
395 SetLastError(ERROR_INVALID_PARAMETER
);
401 SetLastError(ERROR_NOACCESS
);
409 *device_count
= rawinput_devices_count
;
413 if (*device_count
< rawinput_devices_count
)
415 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
416 *device_count
= rawinput_devices_count
;
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
;
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
);
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
);
456 if ((devices
[i
].dwFlags
& RIDEV_REMOVE
) &&
457 (devices
[i
].hwndTarget
!= NULL
))
459 SetLastError(ERROR_INVALID_PARAMETER
);
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
);
487 HeapFree( GetProcessHeap(), 0, d
);
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();
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
);
509 if (header_size
!= sizeof(RAWINPUTHEADER
))
511 WARN("Invalid structure size %u.\n", header_size
);
512 SetLastError(ERROR_INVALID_PARAMETER
);
519 size
= thread_data
->buffer
->header
.dwSize
;
522 size
= sizeof(RAWINPUTHEADER
);
525 SetLastError(ERROR_INVALID_PARAMETER
);
535 if (*data_size
< size
)
537 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
540 memcpy(data
, thread_data
->buffer
, size
);
545 typedef RAWINPUT RAWINPUT64
;
549 RAWINPUTHEADER header
;
553 RAWKEYBOARD keyboard
;
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
;
567 UINT count
= 0, rawinput_size
, next_size
, overhead
;
571 if (IsWow64Process( GetCurrentProcess(), &is_wow64
) && is_wow64
)
572 rawinput_size
= sizeof(RAWINPUT64
);
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
);
586 SetLastError(ERROR_INVALID_PARAMETER
);
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
;
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
;
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
);
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
;
640 if (count
) TRACE("data %p, data_size %p (%u), header_size %u, count %u\n", data
, data_size
, *data_size
, header_size
, 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
)
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
);
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
);
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
;
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
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";
725 *data_size
= wcslen(device
->detail
->DevicePath
) + 1;
726 to_copy
= device
->detail
->DevicePath
;
728 to_copy_bytes
= *data_size
* sizeof(WCHAR
);
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
;
748 to_copy_bytes
= sizeof(info
);
749 *data_size
= to_copy_bytes
;
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
)
764 to_copy_bytes
= ((WINE_HIDP_PREPARSED_DATA
*)device
->data
)->dwSize
;
765 *data_size
= to_copy_bytes
;
766 to_copy
= device
->data
;
771 FIXME("command %#x not supported\n", command
);
778 if (avail_bytes
< to_copy_bytes
)
781 memcpy(data
, to_copy
, to_copy_bytes
);
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
;
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
);
812 buffer_size
= *device_count
* sizeof(*buffer
);
813 if (devices
&& !(buffer
= HeapAlloc(GetProcessHeap(), 0, buffer_size
)))
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
;
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
);
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
);