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"
37 #include "user_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(rawinput
);
45 RID_DEVICE_INFO_HID info
;
46 PHIDP_PREPARSED_DATA data
;
49 static struct hid_device
*hid_devices
;
50 static unsigned int hid_devices_count
, hid_devices_max
;
52 static CRITICAL_SECTION hid_devices_cs
;
53 static CRITICAL_SECTION_DEBUG hid_devices_cs_debug
=
55 0, 0, &hid_devices_cs
,
56 { &hid_devices_cs_debug
.ProcessLocksList
, &hid_devices_cs_debug
.ProcessLocksList
},
57 0, 0, { (DWORD_PTR
)(__FILE__
": hid_devices_cs") }
59 static CRITICAL_SECTION hid_devices_cs
= { &hid_devices_cs_debug
, -1, 0, 0, 0, 0 };
61 static void find_hid_devices(void)
63 static ULONGLONG last_check
;
65 SP_DEVICE_INTERFACE_DATA iface
= { sizeof(iface
) };
66 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*detail
;
67 DWORD detail_size
, needed
;
76 if (GetTickCount64() - last_check
< 2000)
78 last_check
= GetTickCount64();
80 HidD_GetHidGuid(&hid_guid
);
82 set
= SetupDiGetClassDevsW(&hid_guid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
| DIGCF_PRESENT
);
84 detail_size
= sizeof(*detail
) + (MAX_PATH
* sizeof(WCHAR
));
85 if (!(detail
= heap_alloc(detail_size
)))
87 detail
->cbSize
= sizeof(*detail
);
89 EnterCriticalSection(&hid_devices_cs
);
91 /* destroy previous list */
92 for (didx
= 0; didx
< hid_devices_count
; ++didx
)
94 CloseHandle(hid_devices
[didx
].file
);
95 heap_free(hid_devices
[didx
].path
);
99 for (idx
= 0; SetupDiEnumDeviceInterfaces(set
, NULL
, &hid_guid
, idx
, &iface
); ++idx
)
101 if (!SetupDiGetDeviceInterfaceDetailW(set
, &iface
, detail
, detail_size
, &needed
, NULL
))
103 if (!(detail
= heap_realloc(detail
, needed
)))
105 ERR("Failed to allocate memory.\n");
108 detail_size
= needed
;
110 SetupDiGetDeviceInterfaceDetailW(set
, &iface
, detail
, detail_size
, NULL
, NULL
);
113 if (!(path
= heap_strdupW(detail
->DevicePath
)))
115 ERR("Failed to allocate memory.\n");
119 file
= CreateFileW(path
, GENERIC_READ
| GENERIC_WRITE
,
120 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, 0);
121 if (file
== INVALID_HANDLE_VALUE
)
123 ERR("Failed to open device file %s, error %u.\n", debugstr_w(path
), GetLastError());
128 if (didx
>= hid_devices_max
)
132 hid_devices_max
*= 2;
133 hid_devices
= heap_realloc(hid_devices
,
134 hid_devices_max
* sizeof(hid_devices
[0]));
139 hid_devices
= heap_alloc(hid_devices_max
* sizeof(hid_devices
[0]));
143 ERR("Failed to allocate memory.\n");
148 TRACE("Found HID device %s.\n", debugstr_w(path
));
150 hid_devices
[didx
].path
= path
;
151 hid_devices
[didx
].file
= file
;
153 attr
.Size
= sizeof(HIDD_ATTRIBUTES
);
154 if (!HidD_GetAttributes(file
, &attr
))
155 WARN_(rawinput
)("Failed to get attributes.\n");
156 hid_devices
[didx
].info
.dwVendorId
= attr
.VendorID
;
157 hid_devices
[didx
].info
.dwProductId
= attr
.ProductID
;
158 hid_devices
[didx
].info
.dwVersionNumber
= attr
.VersionNumber
;
160 if (!HidD_GetPreparsedData(file
, &hid_devices
[didx
].data
))
161 WARN_(rawinput
)("Failed to get preparsed data.\n");
163 if (!HidP_GetCaps(hid_devices
[didx
].data
, &caps
))
164 WARN_(rawinput
)("Failed to get caps.\n");
166 hid_devices
[didx
].info
.usUsagePage
= caps
.UsagePage
;
167 hid_devices
[didx
].info
.usUsage
= caps
.Usage
;
171 hid_devices_count
= didx
;
174 LeaveCriticalSection(&hid_devices_cs
);
178 /***********************************************************************
179 * GetRawInputDeviceList (USER32.@)
181 UINT WINAPI
GetRawInputDeviceList(RAWINPUTDEVICELIST
*devices
, UINT
*device_count
, UINT size
)
185 TRACE("devices %p, device_count %p, size %u.\n", devices
, device_count
, size
);
187 if (size
!= sizeof(*devices
))
189 SetLastError(ERROR_INVALID_PARAMETER
);
195 SetLastError(ERROR_NOACCESS
);
203 *device_count
= 2 + hid_devices_count
;
207 if (*device_count
< 2 + hid_devices_count
)
209 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
210 *device_count
= 2 + hid_devices_count
;
214 devices
[0].hDevice
= WINE_MOUSE_HANDLE
;
215 devices
[0].dwType
= RIM_TYPEMOUSE
;
216 devices
[1].hDevice
= WINE_KEYBOARD_HANDLE
;
217 devices
[1].dwType
= RIM_TYPEKEYBOARD
;
219 for (i
= 0; i
< hid_devices_count
; ++i
)
221 devices
[2 + i
].hDevice
= &hid_devices
[i
];
222 devices
[2 + i
].dwType
= RIM_TYPEHID
;
225 return 2 + hid_devices_count
;
228 /***********************************************************************
229 * RegisterRawInputDevices (USER32.@)
231 BOOL WINAPI DECLSPEC_HOTPATCH
RegisterRawInputDevices(RAWINPUTDEVICE
*devices
, UINT device_count
, UINT size
)
233 struct rawinput_device
*d
;
237 TRACE("devices %p, device_count %u, size %u.\n", devices
, device_count
, size
);
239 if (size
!= sizeof(*devices
))
241 WARN("Invalid structure size %u.\n", size
);
245 if (!(d
= HeapAlloc( GetProcessHeap(), 0, device_count
* sizeof(*d
) ))) return FALSE
;
247 for (i
= 0; i
< device_count
; ++i
)
249 TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n",
250 i
, devices
[i
].usUsagePage
, devices
[i
].usUsage
,
251 devices
[i
].dwFlags
, devices
[i
].hwndTarget
);
252 if (devices
[i
].dwFlags
& ~RIDEV_REMOVE
)
253 FIXME("Unhandled flags %#x for device %u.\n", devices
[i
].dwFlags
, i
);
255 d
[i
].usage_page
= devices
[i
].usUsagePage
;
256 d
[i
].usage
= devices
[i
].usUsage
;
257 d
[i
].flags
= devices
[i
].dwFlags
;
258 d
[i
].target
= wine_server_user_handle( devices
[i
].hwndTarget
);
261 SERVER_START_REQ( update_rawinput_devices
)
263 wine_server_add_data( req
, d
, device_count
* sizeof(*d
) );
264 ret
= !wine_server_call( req
);
268 HeapFree( GetProcessHeap(), 0, d
);
273 /***********************************************************************
274 * GetRawInputData (USER32.@)
276 UINT WINAPI
GetRawInputData(HRAWINPUT rawinput
, UINT command
, void *data
, UINT
*data_size
, UINT header_size
)
278 RAWINPUT
*ri
= (RAWINPUT
*)rawinput
;
281 TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
282 rawinput
, command
, data
, data_size
, header_size
);
284 if (header_size
!= sizeof(RAWINPUTHEADER
))
286 WARN("Invalid structure size %u.\n", header_size
);
293 s
= ri
->header
.dwSize
;
296 s
= sizeof(RAWINPUTHEADER
);
308 if (*data_size
< s
) return ~0U;
313 /***********************************************************************
314 * GetRawInputBuffer (USER32.@)
316 UINT WINAPI DECLSPEC_HOTPATCH
GetRawInputBuffer(RAWINPUT
*data
, UINT
*data_size
, UINT header_size
)
318 FIXME("data %p, data_size %p, header_size %u stub!\n", data
, data_size
, header_size
);
323 /***********************************************************************
324 * GetRawInputDeviceInfoA (USER32.@)
326 UINT WINAPI
GetRawInputDeviceInfoA(HANDLE device
, UINT command
, void *data
, UINT
*data_size
)
330 TRACE("device %p, command %#x, data %p, data_size %p.\n",
331 device
, command
, data
, data_size
);
333 ret
= GetRawInputDeviceInfoW(device
, command
, data
, data_size
);
334 if (command
== RIDI_DEVICENAME
&& ret
&& ret
!= ~0U)
335 ret
= WideCharToMultiByte(CP_ACP
, 0, data
, -1, data
, *data_size
, NULL
, NULL
);
340 /***********************************************************************
341 * GetRawInputDeviceInfoW (USER32.@)
343 UINT WINAPI
GetRawInputDeviceInfoW(HANDLE device
, UINT command
, void *data
, UINT
*data_size
)
345 /* FIXME: Most of this is made up. */
346 static const WCHAR keyboard_name
[] = {'\\','\\','?','\\','W','I','N','E','_','K','E','Y','B','O','A','R','D',0};
347 static const WCHAR mouse_name
[] = {'\\','\\','?','\\','W','I','N','E','_','M','O','U','S','E',0};
348 static const RID_DEVICE_INFO_KEYBOARD keyboard_info
= {0, 0, 1, 12, 3, 101};
349 static const RID_DEVICE_INFO_MOUSE mouse_info
= {1, 5, 0, FALSE
};
350 struct hid_device
*hid_device
;
351 const WCHAR
*name
= NULL
;
352 RID_DEVICE_INFO
*info
;
355 TRACE("device %p, command %#x, data %p, data_size %p.\n",
356 device
, command
, data
, data_size
);
358 if (!data_size
) return ~0U;
362 case RIDI_DEVICENAME
:
363 if (device
== WINE_MOUSE_HANDLE
)
365 s
= sizeof(mouse_name
);
368 else if (device
== WINE_KEYBOARD_HANDLE
)
370 s
= sizeof(keyboard_name
);
371 name
= keyboard_name
;
376 s
= (strlenW(hid_device
->path
) + 1) * sizeof(WCHAR
);
377 name
= hid_device
->path
;
380 case RIDI_DEVICEINFO
:
399 if (command
== RIDI_DEVICENAME
)
401 memcpy(data
, name
, s
);
406 info
->cbSize
= sizeof(*info
);
407 if (device
== WINE_MOUSE_HANDLE
)
409 info
->dwType
= RIM_TYPEMOUSE
;
410 info
->u
.mouse
= mouse_info
;
412 else if (device
== WINE_KEYBOARD_HANDLE
)
414 info
->dwType
= RIM_TYPEKEYBOARD
;
415 info
->u
.keyboard
= keyboard_info
;
420 info
->dwType
= RIM_TYPEHID
;
421 info
->u
.hid
= hid_device
->info
;
426 /***********************************************************************
427 * GetRegisteredRawInputDevices (USER32.@)
429 UINT WINAPI DECLSPEC_HOTPATCH
GetRegisteredRawInputDevices(RAWINPUTDEVICE
*devices
, UINT
*device_count
, UINT size
)
431 FIXME("devices %p, device_count %p, size %u stub!\n", devices
, device_count
, size
);
437 /***********************************************************************
438 * DefRawInputProc (USER32.@)
440 LRESULT WINAPI
DefRawInputProc(RAWINPUT
**data
, INT data_count
, UINT header_size
)
442 FIXME("data %p, data_count %d, header_size %u stub!\n", data
, data_count
, header_size
);