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
29 #include "win32u_private.h"
30 #include "ntuser_private.h"
31 #define WIN32_NO_STATUS
33 #include "ddk/hidclass.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)
44 typedef RAWINPUTHEADER RAWINPUTHEADER64
;
45 typedef RAWINPUT RAWINPUT64
;
57 RAWINPUTHEADER64 header
;
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
) );
76 static bool rawinput_from_hardware_message( RAWINPUT
*rawinput
, const struct hardware_msg_data
*msg_data
)
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 */
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
)
153 rawinput
->data
.keyboard
.VKey
= VK_SHIFT
;
154 rawinput
->data
.keyboard
.Flags
&= ~RI_KEY_E0
;
159 rawinput
->data
.keyboard
.VKey
= VK_CONTROL
;
164 rawinput
->data
.keyboard
.VKey
= VK_MENU
;
168 rawinput
->data
.keyboard
.VKey
= msg_data
->rawinput
.kbd
.vkey
;
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
);
190 FIXME( "Unhandled rawinput type %#x.\n", msg_data
->rawinput
.type
);
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
;
233 if (!query_reg_value( key
, symbolic_linkW
, value
, sizeof(value_buffer
) - sizeof(WCHAR
) ))
235 ERR( "failed to get symbolic link value\n" );
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 */
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
);
258 status
= NtDeviceIoControlFile( file
, NULL
, NULL
, NULL
, &io
, IOCTL_HID_GET_WINE_RAWINPUT_HANDLE
,
259 NULL
, 0, &handle
, sizeof(handle
) );
262 ERR( "Failed to get raw input handle, status %#x.\n", status
);
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
) );
275 memset( &info
, 0, sizeof(info
) );
276 info
.cbSize
= sizeof(info
);
282 status
= NtDeviceIoControlFile( file
, NULL
, NULL
, NULL
, &io
,
283 IOCTL_HID_GET_COLLECTION_INFORMATION
,
284 NULL
, 0, &hid_info
, sizeof(hid_info
) );
287 ERR( "Failed to get collection information, status %#x.\n", status
);
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" );
301 /* NtDeviceIoControlFile checks that the output buffer is writable using ntdll virtual
302 * memory protection information, we need an NtAllocateVirtualMemory allocated buffer.
305 size
= hid_info
.DescriptorSize
;
306 if (!(status
= NtAllocateVirtualMemory( GetCurrentProcess(), &buffer
, 0, &size
,
307 MEM_RESERVE
|MEM_COMMIT
, PAGE_READWRITE
)))
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
);
319 ERR( "Failed to get collection descriptor, status %#x.\n", status
);
323 info
.hid
.usUsagePage
= preparsed
->usage_page
;
324 info
.hid
.usUsage
= preparsed
->usage
;
328 info
.mouse
= mouse_info
;
331 case RIM_TYPEKEYBOARD
:
332 info
.keyboard
= keyboard_info
;
336 if (!(device
= calloc( 1, sizeof(*device
) )))
338 ERR( "Failed to allocate memory.\n" );
342 TRACE( "Adding device %#x / %s.\n", handle
, debugstr_w(path
) );
343 wcscpy( device
->path
, path
);
345 device
->handle
= ULongToHandle(handle
);
347 device
->data
= preparsed
;
348 list_add_tail( &devices
, &device
->entry
);
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 )
386 KEY_NODE_INFORMATION
*subkey_info
= (void *)buffer
;
387 HKEY class_key
, device_key
, iface_key
;
391 wcscpy( buffer
, device_classesW
);
392 wcscat( buffer
, class );
393 if (!(class_key
= reg_open_key( NULL
, buffer
, wcslen( buffer
) * sizeof(WCHAR
) )))
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
)) );
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
)) );
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
;
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
);
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
;
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;
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
);
494 RtlSetLastWin32Error( ERROR_NOACCESS
);
498 pthread_mutex_lock( &rawinput_mutex
);
500 if (ticks
- last_check
> 2000)
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
;
514 pthread_mutex_unlock( &rawinput_mutex
);
518 *device_count
= count
;
522 if (*device_count
< count
)
524 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
525 *device_count
= 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
;
542 TRACE( "handle %p, command %#x, data %p, data_size %p.\n", handle
, command
, data
, data_size
);
546 RtlSetLastWin32Error( ERROR_NOACCESS
);
549 if (command
!= RIDI_DEVICENAME
&& command
!= RIDI_DEVICEINFO
&& command
!= RIDI_PREPARSEDDATA
)
551 FIXME( "Command %#x not implemented!\n", command
);
552 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
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
);
565 len
= data_len
= *data_size
;
568 case RIDI_DEVICENAME
:
569 if ((len
= wcslen( device
->path
) + 1) <= data_len
&& data
)
570 memcpy( data
, device
->path
, len
* sizeof(WCHAR
) );
574 case RIDI_DEVICEINFO
:
575 if ((len
= sizeof(info
)) <= data_len
&& data
)
576 memcpy( data
, &device
->info
, len
);
580 case RIDI_PREPARSEDDATA
:
581 if (!(preparsed
= device
->data
))
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
);
593 pthread_mutex_unlock( &rawinput_mutex
);
600 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
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
;
618 if (NtCurrentTeb()->WowTebOffset
)
619 rawinput_size
= sizeof(RAWINPUT64
);
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
);
633 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
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
;
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
;
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;
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
;
683 ri64
->header
.hDevice
= data
->header
.hDevice
;
685 ri64
->header
.hDevice
= HandleToULong(data
->header
.hDevice
);
688 remaining
-= data
->header
.dwSize
;
689 data
= NEXTRAWINPUTBLOCK(data
);
690 msg_data
= (struct hardware_msg_data
*)((char *)msg_data
+ msg_data
->size
);
698 next_size
= rawinput_size
;
701 if (next_size
&& *data_size
<= next_size
)
703 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
704 *data_size
= next_size
;
708 TRACE( "data %p, data_size %p (%u), header_size %u, count %u\n",
709 data
, data_size
, *data_size
, header_size
, 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
;
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
);
730 if (!rawinput
|| thread_data
->hw_id
!= (UINT_PTR
)rawinput
)
732 RtlSetLastWin32Error( ERROR_INVALID_HANDLE
);
736 if (header_size
!= sizeof(RAWINPUTHEADER
))
738 WARN( "Invalid structure size %u.\n", header_size
);
739 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
746 size
= thread_data
->buffer
->header
.dwSize
;
750 size
= sizeof(RAWINPUTHEADER
);
754 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
764 if (*data_size
< size
)
766 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
769 memcpy( data
, thread_data
->buffer
, 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()))
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
);
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
);
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
--;
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
++;
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
;
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
);
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
);
858 if ((devices
[i
].dwFlags
& RIDEV_REMOVE
) && devices
[i
].hwndTarget
)
860 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
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
);
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
);
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
);
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
);
910 free( server_devices
);
912 pthread_mutex_unlock( &rawinput_mutex
);
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
);
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;
945 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
949 return *device_count
;