libport: Remove support for PPC32.
[wine.git] / dlls / user32 / rawinput.c
blobdd2ac2e208b2e7451e37c48f0e8ed974913f692b
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 "config.h"
23 #include <stdarg.h>
25 #define NONAMELESSUNION
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 "ntddmou.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(rawinput);
45 struct device
47 WCHAR *path;
48 HANDLE file;
49 RID_DEVICE_INFO info;
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;
68 void *new_elements;
70 if (count <= *capacity)
71 return TRUE;
73 max_capacity = ~(SIZE_T)0 / size;
74 if (count > max_capacity)
75 return FALSE;
77 new_capacity = max(4, *capacity);
78 while (new_capacity < count && new_capacity <= max_capacity / 2)
79 new_capacity *= 2;
80 if (new_capacity < count)
81 new_capacity = max_capacity;
83 if (!(new_elements = heap_realloc(*elements, new_capacity * size)))
84 return FALSE;
86 *elements = new_elements;
87 *capacity = new_capacity;
89 return TRUE;
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;
96 HANDLE file;
97 WCHAR *path;
98 DWORD size;
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());
104 return FALSE;
106 if (!(detail = heap_alloc(size)))
108 ERR("Failed to allocate memory.\n");
109 return FALSE;
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");
119 heap_free(detail);
120 return NULL;
122 heap_free(detail);
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());
129 heap_free(path);
130 return NULL;
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");
137 CloseHandle(file);
138 heap_free(path);
139 return NULL;
142 device = &rawinput_devices[rawinput_devices_count++];
143 device->path = path;
144 device->file = file;
145 device->info.cbSize = sizeof(RID_DEVICE_INFO);
147 return device;
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;
157 HIDP_CAPS caps;
158 GUID hid_guid;
159 HDEVINFO set;
160 DWORD idx;
162 if (GetTickCount64() - last_check < 2000)
163 return;
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)))
183 continue;
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)))
213 continue;
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)
229 UINT i;
231 TRACE("devices %p, device_count %p, size %u.\n", devices, device_count, size);
233 if (size != sizeof(*devices))
235 SetLastError(ERROR_INVALID_PARAMETER);
236 return ~0U;
239 if (!device_count)
241 SetLastError(ERROR_NOACCESS);
242 return ~0U;
245 find_devices();
247 if (!devices)
249 *device_count = 2 + rawinput_devices_count;
250 return 0;
253 if (*device_count < 2 + rawinput_devices_count)
255 SetLastError(ERROR_INSUFFICIENT_BUFFER);
256 *device_count = 2 + rawinput_devices_count;
257 return ~0U;
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;
280 BOOL ret;
281 UINT i;
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);
289 return FALSE;
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);
298 return FALSE;
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 );
323 SERVER_END_REQ;
325 HeapFree( GetProcessHeap(), 0, d );
327 return ret;
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;
336 UINT s;
338 TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
339 rawinput, command, data, data_size, header_size);
341 if (!ri)
342 return ~0U;
344 if (header_size != sizeof(RAWINPUTHEADER))
346 WARN("Invalid structure size %u.\n", header_size);
347 return ~0U;
350 switch (command)
352 case RID_INPUT:
353 s = ri->header.dwSize;
354 break;
355 case RID_HEADER:
356 s = sizeof(RAWINPUTHEADER);
357 break;
358 default:
359 return ~0U;
362 if (!data)
364 *data_size = s;
365 return 0;
368 if (*data_size < s) return ~0U;
369 memcpy(data, ri, s);
370 return s;
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);
380 return 0;
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)
394 WCHAR *nameW;
395 UINT ret, nameW_sz;
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);
403 else
404 nameW = NULL;
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);
415 return ret;
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;
434 const void *to_copy;
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
448 switch (command)
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;
463 else
465 *data_size = strlenW(device->path) + 1;
466 to_copy = device->path;
468 to_copy_bytes = *data_size * sizeof(WCHAR);
469 break;
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;
484 else
486 info = device->info;
488 to_copy_bytes = sizeof(info);
489 *data_size = to_copy_bytes;
490 to_copy = &info;
491 break;
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)
498 to_copy_bytes = 0;
499 *data_size = 0;
500 to_copy = NULL;
502 else
504 to_copy_bytes = ((WINE_HIDP_PREPARSED_DATA*)device->data)->dwSize;
505 *data_size = to_copy_bytes;
506 to_copy = device->data;
508 break;
510 default:
511 FIXME("command %#x not supported\n", command);
512 return ~0U;
515 if (!data)
516 return 0;
518 if (avail_bytes < to_copy_bytes)
519 return ~0U;
521 memcpy(data, to_copy, to_copy_bytes);
523 return *data_size;
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);
533 return 0;
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);
544 return 0;