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 NONAMELESSUNION
33 #include "ddk/hidsdi.h"
34 #include "wine/debug.h"
35 #include "wine/server.h"
38 #include "user_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(rawinput
);
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
;
70 if (count
<= *capacity
)
73 max_capacity
= ~(SIZE_T
)0 / size
;
74 if (count
> max_capacity
)
77 new_capacity
= max(4, *capacity
);
78 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
80 if (new_capacity
< count
)
81 new_capacity
= max_capacity
;
83 if (!(new_elements
= heap_realloc(*elements
, new_capacity
* size
)))
86 *elements
= new_elements
;
87 *capacity
= new_capacity
;
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
;
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());
106 if (!(detail
= heap_alloc(size
)))
108 ERR("Failed to allocate memory.\n");
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");
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());
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");
142 device
= &rawinput_devices
[rawinput_devices_count
++];
145 device
->info
.cbSize
= sizeof(RID_DEVICE_INFO
);
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
;
162 if (GetTickCount64() - last_check
< 2000)
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
)))
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
)))
215 device
->info
.dwType
= RIM_TYPEMOUSE
;
216 device
->info
.u
.mouse
= mouse_info
;
219 SetupDiDestroyDeviceInfoList(set
);
221 LeaveCriticalSection(&rawinput_devices_cs
);
224 /***********************************************************************
225 * GetRawInputDeviceList (USER32.@)
227 UINT WINAPI
GetRawInputDeviceList(RAWINPUTDEVICELIST
*devices
, UINT
*device_count
, UINT size
)
231 TRACE("devices %p, device_count %p, size %u.\n", devices
, device_count
, size
);
233 if (size
!= sizeof(*devices
))
235 SetLastError(ERROR_INVALID_PARAMETER
);
241 SetLastError(ERROR_NOACCESS
);
249 *device_count
= 2 + rawinput_devices_count
;
253 if (*device_count
< 2 + rawinput_devices_count
)
255 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
256 *device_count
= 2 + rawinput_devices_count
;
260 devices
[0].hDevice
= WINE_MOUSE_HANDLE
;
261 devices
[0].dwType
= RIM_TYPEMOUSE
;
262 devices
[1].hDevice
= WINE_KEYBOARD_HANDLE
;
263 devices
[1].dwType
= RIM_TYPEKEYBOARD
;
265 for (i
= 0; i
< rawinput_devices_count
; ++i
)
267 devices
[2 + i
].hDevice
= &rawinput_devices
[i
];
268 devices
[2 + i
].dwType
= rawinput_devices
[i
].info
.dwType
;
271 return 2 + rawinput_devices_count
;
274 /***********************************************************************
275 * RegisterRawInputDevices (USER32.@)
277 BOOL WINAPI DECLSPEC_HOTPATCH
RegisterRawInputDevices(RAWINPUTDEVICE
*devices
, UINT device_count
, UINT size
)
279 struct rawinput_device
*d
;
283 TRACE("devices %p, device_count %u, size %u.\n", devices
, device_count
, size
);
285 if (size
!= sizeof(*devices
))
287 WARN("Invalid structure size %u.\n", size
);
288 SetLastError(ERROR_INVALID_PARAMETER
);
292 for (i
= 0; i
< device_count
; ++i
)
294 if ((devices
[i
].dwFlags
& RIDEV_REMOVE
) &&
295 (devices
[i
].hwndTarget
!= NULL
))
297 SetLastError(ERROR_INVALID_PARAMETER
);
302 if (!(d
= HeapAlloc( GetProcessHeap(), 0, device_count
* sizeof(*d
) ))) return FALSE
;
304 for (i
= 0; i
< device_count
; ++i
)
306 TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n",
307 i
, devices
[i
].usUsagePage
, devices
[i
].usUsage
,
308 devices
[i
].dwFlags
, devices
[i
].hwndTarget
);
309 if (devices
[i
].dwFlags
& ~RIDEV_REMOVE
)
310 FIXME("Unhandled flags %#x for device %u.\n", devices
[i
].dwFlags
, i
);
312 d
[i
].usage_page
= devices
[i
].usUsagePage
;
313 d
[i
].usage
= devices
[i
].usUsage
;
314 d
[i
].flags
= devices
[i
].dwFlags
;
315 d
[i
].target
= wine_server_user_handle( devices
[i
].hwndTarget
);
318 SERVER_START_REQ( update_rawinput_devices
)
320 wine_server_add_data( req
, d
, device_count
* sizeof(*d
) );
321 ret
= !wine_server_call( req
);
325 HeapFree( GetProcessHeap(), 0, d
);
330 /***********************************************************************
331 * GetRawInputData (USER32.@)
333 UINT WINAPI
GetRawInputData(HRAWINPUT rawinput
, UINT command
, void *data
, UINT
*data_size
, UINT header_size
)
335 RAWINPUT
*ri
= (RAWINPUT
*)rawinput
;
338 TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
339 rawinput
, command
, data
, data_size
, header_size
);
344 if (header_size
!= sizeof(RAWINPUTHEADER
))
346 WARN("Invalid structure size %u.\n", header_size
);
353 s
= ri
->header
.dwSize
;
356 s
= sizeof(RAWINPUTHEADER
);
368 if (*data_size
< s
) return ~0U;
373 /***********************************************************************
374 * GetRawInputBuffer (USER32.@)
376 UINT WINAPI DECLSPEC_HOTPATCH
GetRawInputBuffer(RAWINPUT
*data
, UINT
*data_size
, UINT header_size
)
378 FIXME("data %p, data_size %p, header_size %u stub!\n", data
, data_size
, header_size
);
383 /***********************************************************************
384 * GetRawInputDeviceInfoA (USER32.@)
386 UINT WINAPI
GetRawInputDeviceInfoA(HANDLE device
, UINT command
, void *data
, UINT
*data_size
)
388 TRACE("device %p, command %#x, data %p, data_size %p.\n",
389 device
, command
, data
, data_size
);
391 /* RIDI_DEVICENAME data_size is in chars, not bytes */
392 if (command
== RIDI_DEVICENAME
)
397 if (!data_size
) return ~0U;
399 nameW_sz
= *data_size
;
401 if (data
&& nameW_sz
> 0)
402 nameW
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
) * nameW_sz
);
406 ret
= GetRawInputDeviceInfoW(device
, command
, nameW
, &nameW_sz
);
408 if (ret
&& ret
!= ~0U)
409 WideCharToMultiByte(CP_ACP
, 0, nameW
, -1, data
, *data_size
, NULL
, NULL
);
411 *data_size
= nameW_sz
;
413 HeapFree(GetProcessHeap(), 0, nameW
);
418 return GetRawInputDeviceInfoW(device
, command
, data
, data_size
);
421 /***********************************************************************
422 * GetRawInputDeviceInfoW (USER32.@)
424 UINT WINAPI
GetRawInputDeviceInfoW(HANDLE handle
, UINT command
, void *data
, UINT
*data_size
)
426 /* FIXME: Most of this is made up. */
427 static const WCHAR keyboard_name
[] = {'\\','\\','?','\\','W','I','N','E','_','K','E','Y','B','O','A','R','D',0};
428 static const WCHAR mouse_name
[] = {'\\','\\','?','\\','W','I','N','E','_','M','O','U','S','E',0};
429 static const RID_DEVICE_INFO_KEYBOARD keyboard_info
= {0, 0, 1, 12, 3, 101};
430 static const RID_DEVICE_INFO_MOUSE mouse_info
= {1, 5, 0, FALSE
};
432 RID_DEVICE_INFO info
;
433 struct device
*device
= handle
;
435 UINT to_copy_bytes
, avail_bytes
;
437 TRACE("handle %p, command %#x, data %p, data_size %p.\n",
438 handle
, command
, data
, data_size
);
440 if (!data_size
) return ~0U;
442 /* each case below must set:
443 * *data_size: length (meaning defined by command) of data we want to copy
444 * avail_bytes: number of bytes available in user buffer
445 * to_copy_bytes: number of bytes we want to copy into user buffer
446 * to_copy: pointer to data we want to copy into user buffer
450 case RIDI_DEVICENAME
:
451 /* for RIDI_DEVICENAME, data_size is in characters, not bytes */
452 avail_bytes
= *data_size
* sizeof(WCHAR
);
453 if (handle
== WINE_MOUSE_HANDLE
)
455 *data_size
= ARRAY_SIZE(mouse_name
);
456 to_copy
= mouse_name
;
458 else if (handle
== WINE_KEYBOARD_HANDLE
)
460 *data_size
= ARRAY_SIZE(keyboard_name
);
461 to_copy
= keyboard_name
;
465 *data_size
= strlenW(device
->path
) + 1;
466 to_copy
= device
->path
;
468 to_copy_bytes
= *data_size
* sizeof(WCHAR
);
471 case RIDI_DEVICEINFO
:
472 avail_bytes
= *data_size
;
473 info
.cbSize
= sizeof(info
);
474 if (handle
== WINE_MOUSE_HANDLE
)
476 info
.dwType
= RIM_TYPEMOUSE
;
477 info
.u
.mouse
= mouse_info
;
479 else if (handle
== WINE_KEYBOARD_HANDLE
)
481 info
.dwType
= RIM_TYPEKEYBOARD
;
482 info
.u
.keyboard
= keyboard_info
;
488 to_copy_bytes
= sizeof(info
);
489 *data_size
= to_copy_bytes
;
493 case RIDI_PREPARSEDDATA
:
494 avail_bytes
= *data_size
;
495 if (handle
== WINE_MOUSE_HANDLE
|| handle
== WINE_KEYBOARD_HANDLE
||
496 device
->info
.dwType
!= RIM_TYPEHID
)
504 to_copy_bytes
= ((WINE_HIDP_PREPARSED_DATA
*)device
->data
)->dwSize
;
505 *data_size
= to_copy_bytes
;
506 to_copy
= device
->data
;
511 FIXME("command %#x not supported\n", command
);
518 if (avail_bytes
< to_copy_bytes
)
521 memcpy(data
, to_copy
, to_copy_bytes
);
526 /***********************************************************************
527 * GetRegisteredRawInputDevices (USER32.@)
529 UINT WINAPI DECLSPEC_HOTPATCH
GetRegisteredRawInputDevices(RAWINPUTDEVICE
*devices
, UINT
*device_count
, UINT size
)
531 FIXME("devices %p, device_count %p, size %u stub!\n", devices
, device_count
, size
);
537 /***********************************************************************
538 * DefRawInputProc (USER32.@)
540 LRESULT WINAPI
DefRawInputProc(RAWINPUT
**data
, INT data_count
, UINT header_size
)
542 FIXME("data %p, data_count %d, header_size %u stub!\n", data
, data_count
, header_size
);