cmd: DIR command outputs free space for the path.
[wine.git] / dlls / win32u / rawinput.c
blobbd2e00a31c4440495fb9da1554d0056aafc47452
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 #if 0
23 #pragma makedep unix
24 #endif
26 #include <stdbool.h>
27 #include <pthread.h>
29 #include "win32u_private.h"
30 #include "ntuser_private.h"
31 #define WIN32_NO_STATUS
32 #include "winioctl.h"
33 #include "ddk/hidclass.h"
34 #include "wine/hid.h"
35 #include "wine/server.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(rawinput);
40 #define WINE_MOUSE_HANDLE ((HANDLE)1)
41 #define WINE_KEYBOARD_HANDLE ((HANDLE)2)
43 #ifdef _WIN64
44 typedef RAWINPUTHEADER RAWINPUTHEADER64;
45 typedef RAWINPUT RAWINPUT64;
46 #else
47 typedef struct
49 DWORD dwType;
50 DWORD dwSize;
51 ULONGLONG hDevice;
52 ULONGLONG wParam;
53 } RAWINPUTHEADER64;
55 typedef struct
57 RAWINPUTHEADER64 header;
58 union
60 RAWMOUSE mouse;
61 RAWKEYBOARD keyboard;
62 RAWHID hid;
63 } data;
64 } RAWINPUT64;
65 #endif
67 static struct rawinput_thread_data *get_rawinput_thread_data(void)
69 struct user_thread_info *thread_info = get_user_thread_info();
70 struct rawinput_thread_data *data = thread_info->rawinput;
71 if (data) return data;
72 data = thread_info->rawinput = calloc( 1, RAWINPUT_BUFFER_SIZE + sizeof(struct user_thread_info) );
73 return data;
76 static bool rawinput_from_hardware_message( RAWINPUT *rawinput, const struct hardware_msg_data *msg_data )
78 SIZE_T size;
80 rawinput->header.dwType = msg_data->rawinput.type;
81 if (msg_data->rawinput.type == RIM_TYPEMOUSE)
83 static const unsigned int button_flags[] =
85 0, /* MOUSEEVENTF_MOVE */
86 RI_MOUSE_LEFT_BUTTON_DOWN, /* MOUSEEVENTF_LEFTDOWN */
87 RI_MOUSE_LEFT_BUTTON_UP, /* MOUSEEVENTF_LEFTUP */
88 RI_MOUSE_RIGHT_BUTTON_DOWN, /* MOUSEEVENTF_RIGHTDOWN */
89 RI_MOUSE_RIGHT_BUTTON_UP, /* MOUSEEVENTF_RIGHTUP */
90 RI_MOUSE_MIDDLE_BUTTON_DOWN, /* MOUSEEVENTF_MIDDLEDOWN */
91 RI_MOUSE_MIDDLE_BUTTON_UP, /* MOUSEEVENTF_MIDDLEUP */
93 unsigned int i;
95 rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWMOUSE);
96 rawinput->header.hDevice = WINE_MOUSE_HANDLE;
97 rawinput->header.wParam = 0;
99 rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE;
100 rawinput->data.mouse.usButtonFlags = 0;
101 rawinput->data.mouse.usButtonData = 0;
102 for (i = 1; i < ARRAY_SIZE(button_flags); ++i)
104 if (msg_data->flags & (1 << i))
105 rawinput->data.mouse.usButtonFlags |= button_flags[i];
107 if (msg_data->flags & MOUSEEVENTF_WHEEL)
109 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_WHEEL;
110 rawinput->data.mouse.usButtonData = msg_data->rawinput.mouse.data;
112 if (msg_data->flags & MOUSEEVENTF_HWHEEL)
114 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_HORIZONTAL_WHEEL;
115 rawinput->data.mouse.usButtonData = msg_data->rawinput.mouse.data;
117 if (msg_data->flags & MOUSEEVENTF_XDOWN)
119 if (msg_data->rawinput.mouse.data == XBUTTON1)
120 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN;
121 else if (msg_data->rawinput.mouse.data == XBUTTON2)
122 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN;
124 if (msg_data->flags & MOUSEEVENTF_XUP)
126 if (msg_data->rawinput.mouse.data == XBUTTON1)
127 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_UP;
128 else if (msg_data->rawinput.mouse.data == XBUTTON2)
129 rawinput->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_UP;
132 rawinput->data.mouse.ulRawButtons = 0;
133 rawinput->data.mouse.lLastX = msg_data->rawinput.mouse.x;
134 rawinput->data.mouse.lLastY = msg_data->rawinput.mouse.y;
135 rawinput->data.mouse.ulExtraInformation = msg_data->info;
137 else if (msg_data->rawinput.type == RIM_TYPEKEYBOARD)
139 rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data) + sizeof(RAWKEYBOARD);
140 rawinput->header.hDevice = WINE_KEYBOARD_HANDLE;
141 rawinput->header.wParam = 0;
143 rawinput->data.keyboard.MakeCode = msg_data->rawinput.kbd.scan;
144 rawinput->data.keyboard.Flags = (msg_data->flags & KEYEVENTF_KEYUP) ? RI_KEY_BREAK : RI_KEY_MAKE;
145 if (msg_data->flags & KEYEVENTF_EXTENDEDKEY)
146 rawinput->data.keyboard.Flags |= RI_KEY_E0;
147 rawinput->data.keyboard.Reserved = 0;
149 switch (msg_data->rawinput.kbd.vkey)
151 case VK_LSHIFT:
152 case VK_RSHIFT:
153 rawinput->data.keyboard.VKey = VK_SHIFT;
154 rawinput->data.keyboard.Flags &= ~RI_KEY_E0;
155 break;
157 case VK_LCONTROL:
158 case VK_RCONTROL:
159 rawinput->data.keyboard.VKey = VK_CONTROL;
160 break;
162 case VK_LMENU:
163 case VK_RMENU:
164 rawinput->data.keyboard.VKey = VK_MENU;
165 break;
167 default:
168 rawinput->data.keyboard.VKey = msg_data->rawinput.kbd.vkey;
169 break;
172 rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message;
173 rawinput->data.keyboard.ExtraInformation = msg_data->info;
175 else if (msg_data->rawinput.type == RIM_TYPEHID)
177 size = msg_data->size - sizeof(*msg_data);
178 if (size > rawinput->header.dwSize - sizeof(*rawinput)) return false;
180 rawinput->header.dwSize = FIELD_OFFSET( RAWINPUT, data.hid.bRawData ) + size;
181 rawinput->header.hDevice = ULongToHandle( msg_data->rawinput.hid.device );
182 rawinput->header.wParam = 0;
184 rawinput->data.hid.dwCount = msg_data->rawinput.hid.count;
185 rawinput->data.hid.dwSizeHid = msg_data->rawinput.hid.length;
186 memcpy( rawinput->data.hid.bRawData, msg_data + 1, size );
188 else
190 FIXME( "Unhandled rawinput type %#x.\n", msg_data->rawinput.type );
191 return false;
194 return true;
197 struct device
199 HANDLE file;
200 HANDLE handle;
201 struct list entry;
202 WCHAR path[MAX_PATH];
203 RID_DEVICE_INFO info;
204 struct hid_preparsed_data *data;
207 static RAWINPUTDEVICE *registered_devices;
208 static unsigned int registered_device_count;
209 static struct list devices = LIST_INIT( devices );
210 static pthread_mutex_t rawinput_mutex = PTHREAD_MUTEX_INITIALIZER;
212 static struct device *add_device( HKEY key, DWORD type )
214 static const WCHAR symbolic_linkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
215 char value_buffer[offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data[MAX_PATH * sizeof(WCHAR)])];
216 KEY_VALUE_PARTIAL_INFORMATION *value = (KEY_VALUE_PARTIAL_INFORMATION *)value_buffer;
217 static const RID_DEVICE_INFO_KEYBOARD keyboard_info = {0, 0, 1, 12, 3, 101};
218 static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE};
219 struct hid_preparsed_data *preparsed = NULL;
220 HID_COLLECTION_INFORMATION hid_info;
221 IO_STATUS_BLOCK io = {{0}};
222 OBJECT_ATTRIBUTES attr;
223 UNICODE_STRING string;
224 struct device *device;
225 RID_DEVICE_INFO info;
226 unsigned int status;
227 UINT32 handle;
228 void *buffer;
229 SIZE_T size;
230 HANDLE file;
231 WCHAR *path;
233 if (!query_reg_value( key, symbolic_linkW, value, sizeof(value_buffer) - sizeof(WCHAR) ))
235 ERR( "failed to get symbolic link value\n" );
236 return NULL;
238 memset( value->Data + value->DataLength, 0, sizeof(WCHAR) );
240 /* upper case everything but the GUID */
241 for (path = (WCHAR *)value->Data; *path && *path != '{'; path++) *path = towupper( *path );
242 path = (WCHAR *)value->Data;
244 /* path is in DOS format and begins with \\?\ prefix */
245 path[1] = '?';
247 RtlInitUnicodeString( &string, path );
248 InitializeObjectAttributes( &attr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL );
249 if ((status = NtOpenFile( &file, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &attr, &io,
250 FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT )))
252 WARN( "Failed to open device file %s, status %#x.\n", debugstr_w(path), status );
253 return NULL;
256 path[1] = '\\';
258 status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, IOCTL_HID_GET_WINE_RAWINPUT_HANDLE,
259 NULL, 0, &handle, sizeof(handle) );
260 if (status)
262 ERR( "Failed to get raw input handle, status %#x.\n", status );
263 goto fail;
266 LIST_FOR_EACH_ENTRY( device, &devices, struct device, entry )
268 if (device->handle == UlongToHandle( handle ))
270 TRACE( "Ignoring already added device %#x / %s.\n", handle, debugstr_w(path) );
271 goto fail;
275 memset( &info, 0, sizeof(info) );
276 info.cbSize = sizeof(info);
277 info.dwType = type;
279 switch (type)
281 case RIM_TYPEHID:
282 status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io,
283 IOCTL_HID_GET_COLLECTION_INFORMATION,
284 NULL, 0, &hid_info, sizeof(hid_info) );
285 if (status)
287 ERR( "Failed to get collection information, status %#x.\n", status );
288 goto fail;
291 info.hid.dwVendorId = hid_info.VendorID;
292 info.hid.dwProductId = hid_info.ProductID;
293 info.hid.dwVersionNumber = hid_info.VersionNumber;
295 if (!(preparsed = malloc( hid_info.DescriptorSize )))
297 ERR( "Failed to allocate memory.\n" );
298 goto fail;
301 /* NtDeviceIoControlFile checks that the output buffer is writable using ntdll virtual
302 * memory protection information, we need an NtAllocateVirtualMemory allocated buffer.
304 buffer = NULL;
305 size = hid_info.DescriptorSize;
306 if (!(status = NtAllocateVirtualMemory( GetCurrentProcess(), &buffer, 0, &size,
307 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE )))
309 size = 0;
310 status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io,
311 IOCTL_HID_GET_COLLECTION_DESCRIPTOR,
312 NULL, 0, buffer, hid_info.DescriptorSize );
313 if (!status) memcpy( preparsed, buffer, hid_info.DescriptorSize );
314 NtFreeVirtualMemory( GetCurrentProcess(), &buffer, &size, MEM_RELEASE );
317 if (status)
319 ERR( "Failed to get collection descriptor, status %#x.\n", status );
320 goto fail;
323 info.hid.usUsagePage = preparsed->usage_page;
324 info.hid.usUsage = preparsed->usage;
325 break;
327 case RIM_TYPEMOUSE:
328 info.mouse = mouse_info;
329 break;
331 case RIM_TYPEKEYBOARD:
332 info.keyboard = keyboard_info;
333 break;
336 if (!(device = calloc( 1, sizeof(*device) )))
338 ERR( "Failed to allocate memory.\n" );
339 goto fail;
342 TRACE( "Adding device %#x / %s.\n", handle, debugstr_w(path) );
343 wcscpy( device->path, path );
344 device->file = file;
345 device->handle = ULongToHandle(handle);
346 device->info = info;
347 device->data = preparsed;
348 list_add_tail( &devices, &device->entry );
350 return device;
352 fail:
353 free( preparsed );
354 NtClose( file );
355 return NULL;
358 static const WCHAR device_classesW[] =
360 '\\','R','e','g','i','s','t','r','y',
361 '\\','M','a','c','h','i','n','e',
362 '\\','S','y','s','t','e','m',
363 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
364 '\\','C','o','n','t','r','o','l',
365 '\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',0
367 static const WCHAR guid_devinterface_hidW[] =
369 '{','4','d','1','e','5','5','b','2','-','f','1','6','f','-','1','1','c','f',
370 '-','8','8','c','b','-','0','0','1','1','1','1','0','0','0','0','3','0','}',0
372 static const WCHAR guid_devinterface_keyboardW[] =
374 '{','8','8','4','b','9','6','c','3','-','5','6','e','f','-','1','1','d','1',
375 '-','b','c','8','c','-','0','0','a','0','c','9','1','4','0','5','d','d','}',0
377 static const WCHAR guid_devinterface_mouseW[] =
379 '{','3','7','8','d','e','4','4','c','-','5','6','e','f','-','1','1','d','1',
380 '-','b','c','8','c','-','0','0','a','0','c','9','1','4','0','5','d','d','}',0
383 static void enumerate_devices( DWORD type, const WCHAR *class )
385 WCHAR buffer[1024];
386 KEY_NODE_INFORMATION *subkey_info = (void *)buffer;
387 HKEY class_key, device_key, iface_key;
388 unsigned int i, j;
389 DWORD size;
391 wcscpy( buffer, device_classesW );
392 wcscat( buffer, class );
393 if (!(class_key = reg_open_key( NULL, buffer, wcslen( buffer ) * sizeof(WCHAR) )))
394 return;
396 for (i = 0; !NtEnumerateKey( class_key, i, KeyNodeInformation, buffer, sizeof(buffer), &size ); ++i)
398 if (!(device_key = reg_open_key( class_key, subkey_info->Name, subkey_info->NameLength )))
400 ERR( "failed to open %s\n", debugstr_wn(subkey_info->Name, subkey_info->NameLength / sizeof(WCHAR)) );
401 continue;
404 for (j = 0; !NtEnumerateKey( device_key, j, KeyNodeInformation, buffer, sizeof(buffer), &size ); ++j)
406 if (!(iface_key = reg_open_key( device_key, subkey_info->Name, subkey_info->NameLength )))
408 ERR( "failed to open %s\n", debugstr_wn(subkey_info->Name, subkey_info->NameLength / sizeof(WCHAR)) );
409 continue;
412 add_device( iface_key, type );
413 NtClose( iface_key );
416 NtClose( device_key );
419 NtClose( class_key );
422 static void rawinput_update_device_list(void)
424 struct device *device, *next;
426 TRACE( "\n" );
428 LIST_FOR_EACH_ENTRY_SAFE( device, next, &devices, struct device, entry )
430 list_remove( &device->entry );
431 NtClose( device->file );
432 free( device->data );
433 free( device );
436 enumerate_devices( RIM_TYPEMOUSE, guid_devinterface_mouseW );
437 enumerate_devices( RIM_TYPEKEYBOARD, guid_devinterface_keyboardW );
438 enumerate_devices( RIM_TYPEHID, guid_devinterface_hidW );
441 static struct device *find_device_from_handle( HANDLE handle )
443 struct device *device;
445 LIST_FOR_EACH_ENTRY( device, &devices, struct device, entry )
446 if (device->handle == handle) return device;
448 rawinput_update_device_list();
450 LIST_FOR_EACH_ENTRY( device, &devices, struct device, entry )
451 if (device->handle == handle) return device;
453 return NULL;
456 BOOL rawinput_device_get_usages( HANDLE handle, USAGE *usage_page, USAGE *usage )
458 struct device *device;
460 pthread_mutex_lock( &rawinput_mutex );
462 if (!(device = find_device_from_handle( handle )) || device->info.dwType != RIM_TYPEHID)
463 *usage_page = *usage = 0;
464 else
466 *usage_page = device->info.hid.usUsagePage;
467 *usage = device->info.hid.usUsage;
470 pthread_mutex_unlock( &rawinput_mutex );
472 return *usage_page || *usage;
475 /**********************************************************************
476 * NtUserGetRawInputDeviceList (win32u.@)
478 UINT WINAPI NtUserGetRawInputDeviceList( RAWINPUTDEVICELIST *device_list, UINT *device_count, UINT size )
480 unsigned int count = 0, ticks = NtGetTickCount();
481 static unsigned int last_check;
482 struct device *device;
484 TRACE( "device_list %p, device_count %p, size %u.\n", device_list, device_count, size );
486 if (size != sizeof(*device_list))
488 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
489 return ~0u;
492 if (!device_count)
494 RtlSetLastWin32Error( ERROR_NOACCESS );
495 return ~0u;
498 pthread_mutex_lock( &rawinput_mutex );
500 if (ticks - last_check > 2000)
502 last_check = ticks;
503 rawinput_update_device_list();
506 LIST_FOR_EACH_ENTRY( device, &devices, struct device, entry )
508 if (*device_count < ++count || !device_list) continue;
509 device_list->hDevice = device->handle;
510 device_list->dwType = device->info.dwType;
511 device_list++;
514 pthread_mutex_unlock( &rawinput_mutex );
516 if (!device_list)
518 *device_count = count;
519 return 0;
522 if (*device_count < count)
524 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
525 *device_count = count;
526 return ~0u;
529 return count;
532 /**********************************************************************
533 * NtUserGetRawInputDeviceInfo (win32u.@)
535 UINT WINAPI NtUserGetRawInputDeviceInfo( HANDLE handle, UINT command, void *data, UINT *data_size )
537 const struct hid_preparsed_data *preparsed;
538 struct device *device;
539 RID_DEVICE_INFO info;
540 DWORD len, data_len;
542 TRACE( "handle %p, command %#x, data %p, data_size %p.\n", handle, command, data, data_size );
544 if (!data_size)
546 RtlSetLastWin32Error( ERROR_NOACCESS );
547 return ~0u;
549 if (command != RIDI_DEVICENAME && command != RIDI_DEVICEINFO && command != RIDI_PREPARSEDDATA)
551 FIXME( "Command %#x not implemented!\n", command );
552 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
553 return ~0u;
556 pthread_mutex_lock( &rawinput_mutex );
558 if (!(device = find_device_from_handle( handle )))
560 pthread_mutex_unlock( &rawinput_mutex );
561 RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
562 return ~0u;
565 len = data_len = *data_size;
566 switch (command)
568 case RIDI_DEVICENAME:
569 if ((len = wcslen( device->path ) + 1) <= data_len && data)
570 memcpy( data, device->path, len * sizeof(WCHAR) );
571 *data_size = len;
572 break;
574 case RIDI_DEVICEINFO:
575 if ((len = sizeof(info)) <= data_len && data)
576 memcpy( data, &device->info, len );
577 *data_size = len;
578 break;
580 case RIDI_PREPARSEDDATA:
581 if (!(preparsed = device->data))
582 len = 0;
583 else
584 len = preparsed->caps_size + FIELD_OFFSET(struct hid_preparsed_data, value_caps[0]) +
585 preparsed->number_link_collection_nodes * sizeof(struct hid_collection_node);
587 if (preparsed && len <= data_len && data)
588 memcpy( data, preparsed, len );
589 *data_size = len;
590 break;
593 pthread_mutex_unlock( &rawinput_mutex );
595 if (!data)
596 return 0;
598 if (data_len < len)
600 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
601 return ~0u;
604 return *data_size;
607 /**********************************************************************
608 * NtUserGetRawInputBuffer (win32u.@)
610 UINT WINAPI NtUserGetRawInputBuffer( RAWINPUT *data, UINT *data_size, UINT header_size )
612 unsigned int count = 0, remaining, rawinput_size, next_size, overhead;
613 struct rawinput_thread_data *thread_data;
614 struct hardware_msg_data *msg_data;
615 RAWINPUT *rawinput;
616 int i;
618 if (NtCurrentTeb()->WowTebOffset)
619 rawinput_size = sizeof(RAWINPUT64);
620 else
621 rawinput_size = sizeof(RAWINPUT);
622 overhead = rawinput_size - sizeof(RAWINPUT);
624 if (header_size != sizeof(RAWINPUTHEADER))
626 WARN( "Invalid structure size %u.\n", header_size );
627 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
628 return ~0u;
631 if (!data_size)
633 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
634 return ~0u;
637 if (!data)
639 TRACE( "data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size );
640 SERVER_START_REQ( get_rawinput_buffer )
642 req->rawinput_size = rawinput_size;
643 req->buffer_size = 0;
644 if (wine_server_call( req )) return ~0u;
645 *data_size = reply->next_size;
647 SERVER_END_REQ;
648 return 0;
651 if (!(thread_data = get_rawinput_thread_data())) return ~0u;
652 rawinput = thread_data->buffer;
654 /* first RAWINPUT block in the buffer is used for WM_INPUT message data */
655 msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput);
656 SERVER_START_REQ( get_rawinput_buffer )
658 req->rawinput_size = rawinput_size;
659 req->buffer_size = *data_size;
660 wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize );
661 if (wine_server_call( req )) return ~0u;
662 next_size = reply->next_size;
663 count = reply->count;
665 SERVER_END_REQ;
667 remaining = *data_size;
668 for (i = 0; i < count; ++i)
670 data->header.dwSize = remaining;
671 if (!rawinput_from_hardware_message( data, msg_data )) break;
672 if (overhead)
674 /* Under WoW64, GetRawInputBuffer always gives 64-bit RAWINPUT structs. */
675 RAWINPUT64 *ri64 = (RAWINPUT64 *)data;
676 memmove( (char *)&data->data + overhead, &data->data,
677 data->header.dwSize - sizeof(RAWINPUTHEADER) );
678 ri64->header.dwSize += overhead;
680 /* Need to copy wParam before hDevice so it's not overwritten. */
681 ri64->header.wParam = data->header.wParam;
682 #ifdef _WIN64
683 ri64->header.hDevice = data->header.hDevice;
684 #else
685 ri64->header.hDevice = HandleToULong(data->header.hDevice);
686 #endif
688 remaining -= data->header.dwSize;
689 data = NEXTRAWINPUTBLOCK(data);
690 msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_data->size);
693 if (!next_size)
695 if (!count)
696 *data_size = 0;
697 else
698 next_size = rawinput_size;
701 if (next_size && *data_size <= next_size)
703 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
704 *data_size = next_size;
705 count = ~0u;
708 TRACE( "data %p, data_size %p (%u), header_size %u, count %u\n",
709 data, data_size, *data_size, header_size, count );
710 return count;
713 /**********************************************************************
714 * NtUserGetRawInputData (win32u.@)
716 UINT WINAPI NtUserGetRawInputData( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size )
718 struct rawinput_thread_data *thread_data;
719 UINT size;
721 TRACE( "rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
722 rawinput, command, data, data_size, header_size );
724 if (!(thread_data = get_rawinput_thread_data()))
726 RtlSetLastWin32Error( ERROR_OUTOFMEMORY );
727 return ~0u;
730 if (!rawinput || thread_data->hw_id != (UINT_PTR)rawinput)
732 RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
733 return ~0u;
736 if (header_size != sizeof(RAWINPUTHEADER))
738 WARN( "Invalid structure size %u.\n", header_size );
739 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
740 return ~0u;
743 switch (command)
745 case RID_INPUT:
746 size = thread_data->buffer->header.dwSize;
747 break;
749 case RID_HEADER:
750 size = sizeof(RAWINPUTHEADER);
751 break;
753 default:
754 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
755 return ~0u;
758 if (!data)
760 *data_size = size;
761 return 0;
764 if (*data_size < size)
766 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
767 return ~0u;
769 memcpy( data, thread_data->buffer, size );
770 return size;
773 BOOL process_rawinput_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data )
775 struct rawinput_thread_data *thread_data;
777 if (!(thread_data = get_rawinput_thread_data()))
778 return FALSE;
780 if (msg->message == WM_INPUT_DEVICE_CHANGE)
782 pthread_mutex_lock( &rawinput_mutex );
783 rawinput_update_device_list();
784 pthread_mutex_unlock( &rawinput_mutex );
786 else
788 thread_data->buffer->header.dwSize = RAWINPUT_BUFFER_SIZE;
789 if (!rawinput_from_hardware_message( thread_data->buffer, msg_data )) return FALSE;
790 thread_data->hw_id = hw_id;
791 msg->lParam = (LPARAM)hw_id;
794 msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt );
795 return TRUE;
798 static void register_rawinput_device( const RAWINPUTDEVICE *device )
800 RAWINPUTDEVICE *pos, *end;
802 for (pos = registered_devices, end = pos + registered_device_count; pos != end; pos++)
804 if (pos->usUsagePage < device->usUsagePage) continue;
805 if (pos->usUsagePage > device->usUsagePage) break;
806 if (pos->usUsage >= device->usUsage) break;
809 if (device->dwFlags & RIDEV_REMOVE)
811 if (pos != end && pos->usUsagePage == device->usUsagePage && pos->usUsage == device->usUsage)
813 memmove( pos, pos + 1, (char *)end - (char *)(pos + 1) );
814 registered_device_count--;
817 else
819 if (pos == end || pos->usUsagePage != device->usUsagePage || pos->usUsage != device->usUsage)
821 memmove( pos + 1, pos, (char *)end - (char *)pos );
822 registered_device_count++;
824 *pos = *device;
828 /**********************************************************************
829 * NtUserRegisterRawInputDevices (win32u.@)
831 BOOL WINAPI NtUserRegisterRawInputDevices( const RAWINPUTDEVICE *devices, UINT device_count, UINT device_size )
833 struct rawinput_device *server_devices;
834 RAWINPUTDEVICE *new_registered_devices;
835 SIZE_T size;
836 BOOL ret;
837 UINT i;
839 TRACE( "devices %p, device_count %u, device_size %u.\n", devices, device_count, device_size );
841 if (device_size != sizeof(RAWINPUTDEVICE))
843 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
844 return FALSE;
847 for (i = 0; i < device_count; ++i)
849 TRACE( "device %u: page %#x, usage %#x, flags %#x, target %p.\n", i, devices[i].usUsagePage,
850 devices[i].usUsage, (int)devices[i].dwFlags, devices[i].hwndTarget );
852 if ((devices[i].dwFlags & RIDEV_INPUTSINK) && !devices[i].hwndTarget)
854 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
855 return FALSE;
858 if ((devices[i].dwFlags & RIDEV_REMOVE) && devices[i].hwndTarget)
860 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
861 return FALSE;
864 if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK|RIDEV_DEVNOTIFY))
865 FIXME( "Unhandled flags %#x for device %u.\n", (int)devices[i].dwFlags, i );
868 pthread_mutex_lock( &rawinput_mutex );
870 if (!registered_device_count && !device_count)
872 pthread_mutex_unlock( &rawinput_mutex );
873 return TRUE;
876 size = (SIZE_T)device_size * (registered_device_count + device_count);
877 if (!(new_registered_devices = realloc( registered_devices, size )))
879 pthread_mutex_unlock( &rawinput_mutex );
880 RtlSetLastWin32Error( ERROR_OUTOFMEMORY );
881 return FALSE;
884 registered_devices = new_registered_devices;
885 for (i = 0; i < device_count; ++i) register_rawinput_device( devices + i );
887 if (!(device_count = registered_device_count)) server_devices = NULL;
888 else if (!(server_devices = malloc( device_count * sizeof(*server_devices) )))
890 pthread_mutex_unlock( &rawinput_mutex );
891 RtlSetLastWin32Error( ERROR_OUTOFMEMORY );
892 return FALSE;
895 for (i = 0; i < device_count; ++i)
897 server_devices[i].usage_page = registered_devices[i].usUsagePage;
898 server_devices[i].usage = registered_devices[i].usUsage;
899 server_devices[i].flags = registered_devices[i].dwFlags;
900 server_devices[i].target = wine_server_user_handle( registered_devices[i].hwndTarget );
903 SERVER_START_REQ( update_rawinput_devices )
905 wine_server_add_data( req, server_devices, device_count * sizeof(*server_devices) );
906 ret = !wine_server_call_err( req );
908 SERVER_END_REQ;
910 free( server_devices );
912 pthread_mutex_unlock( &rawinput_mutex );
914 return ret;
917 /**********************************************************************
918 * NtUserGetRegisteredRawInputDevices (win32u.@)
920 UINT WINAPI NtUserGetRegisteredRawInputDevices( RAWINPUTDEVICE *devices, UINT *device_count, UINT device_size )
922 SIZE_T size, capacity;
924 TRACE( "devices %p, device_count %p, device_size %u\n", devices, device_count, device_size );
926 if (device_size != sizeof(RAWINPUTDEVICE) || !device_count || (devices && !*device_count))
928 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
929 return ~0u;
932 pthread_mutex_lock( &rawinput_mutex );
934 capacity = *device_count * device_size;
935 *device_count = registered_device_count;
936 size = (SIZE_T)device_size * *device_count;
937 if (devices && capacity >= size) memcpy( devices, registered_devices, size );
939 pthread_mutex_unlock( &rawinput_mutex );
941 if (!devices) return 0;
943 if (capacity < size)
945 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
946 return ~0u;
949 return *device_count;