From: Zebediah Figura Subject: [PATCH v2 3/4] win32u: Move raw input device list management from user32. Message-Id: Date: Mon, 27 Jun 2022 22:20:54 +0000 In-Reply-To: References: From: Zebediah Figura --- dlls/user32/rawinput.c | 433 +--------------------------------- dlls/user32/user32.spec | 4 +- dlls/user32/user_main.c | 2 - dlls/user32/user_private.h | 6 - dlls/win32u/message.c | 5 +- dlls/win32u/ntuser_private.h | 2 - dlls/win32u/rawinput.c | 434 ++++++++++++++++++++++++++++++++++- dlls/win32u/syscall.c | 2 + dlls/win32u/win32u.spec | 4 +- dlls/win32u/win32u_private.h | 1 + dlls/wow64win/syscall.h | 2 + dlls/wow64win/user.c | 55 +++++ include/ntuser.h | 2 + 13 files changed, 503 insertions(+), 449 deletions(-) diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index 588d1685cc0..98854d75690 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -39,368 +39,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(rawinput); -struct device -{ - WCHAR *path; - HANDLE file; - HANDLE handle; - RID_DEVICE_INFO info; - struct hid_preparsed_data *data; -}; - -static struct device *rawinput_devices; -static unsigned int rawinput_devices_count, rawinput_devices_max; - -static CRITICAL_SECTION rawinput_devices_cs; -static CRITICAL_SECTION_DEBUG rawinput_devices_cs_debug = -{ - 0, 0, &rawinput_devices_cs, - { &rawinput_devices_cs_debug.ProcessLocksList, &rawinput_devices_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": rawinput_devices_cs") } -}; -static CRITICAL_SECTION rawinput_devices_cs = { &rawinput_devices_cs_debug, -1, 0, 0, 0, 0 }; - -static BOOL array_reserve(void **elements, unsigned int *capacity, unsigned int count, unsigned int size) -{ - unsigned int new_capacity, max_capacity; - void *new_elements; - - if (count <= *capacity) - return TRUE; - - max_capacity = ~(SIZE_T)0 / size; - if (count > max_capacity) - return FALSE; - - new_capacity = max(4, *capacity); - while (new_capacity < count && new_capacity <= max_capacity / 2) - new_capacity *= 2; - if (new_capacity < count) - new_capacity = max_capacity; - - if (!(new_elements = realloc(*elements, new_capacity * size))) - return FALSE; - - *elements = new_elements; - *capacity = new_capacity; - - return TRUE; -} - -static ULONG query_reg_value( HKEY hkey, const WCHAR *name, - KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size ) -{ - unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0; - UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name }; - - if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, - info, size, &size )) - return 0; - - return size - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); -} - -static struct device *add_device( HKEY key, DWORD type ) -{ - static const WCHAR symbolic_linkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0}; - char value_buffer[4096]; - KEY_VALUE_PARTIAL_INFORMATION *value = (KEY_VALUE_PARTIAL_INFORMATION *)value_buffer; - static const RID_DEVICE_INFO_KEYBOARD keyboard_info = {0, 0, 1, 12, 3, 101}; - static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE}; - struct hid_preparsed_data *preparsed = NULL; - HID_COLLECTION_INFORMATION hid_info; - struct device *device = NULL; - RID_DEVICE_INFO info; - IO_STATUS_BLOCK io; - WCHAR *path, *pos; - NTSTATUS status; - unsigned int i; - UINT32 handle; - HANDLE file; - - if (!query_reg_value( key, symbolic_linkW, value, sizeof(value_buffer) )) - { - ERR( "failed to get symbolic link value\n" ); - return NULL; - } - - if (!(path = malloc( value->DataLength + sizeof(WCHAR) ))) - return NULL; - memcpy( path, value->Data, value->DataLength ); - path[value->DataLength / sizeof(WCHAR)] = 0; - - /* upper case everything but the GUID */ - for (pos = path; *pos && *pos != '{'; pos++) *pos = towupper(*pos); - - file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); - if (file == INVALID_HANDLE_VALUE) - { - ERR( "Failed to open device file %s, error %lu.\n", debugstr_w(path), GetLastError() ); - free( path ); - return NULL; - } - - status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, - IOCTL_HID_GET_WINE_RAWINPUT_HANDLE, - NULL, 0, &handle, sizeof(handle) ); - if (status) - { - ERR( "Failed to get raw input handle, status %#lx.\n", status ); - goto fail; - } - - memset( &info, 0, sizeof(info) ); - info.cbSize = sizeof(info); - info.dwType = type; - - switch (type) - { - case RIM_TYPEHID: - status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, - IOCTL_HID_GET_COLLECTION_INFORMATION, - NULL, 0, &hid_info, sizeof(hid_info) ); - if (status) - { - ERR( "Failed to get collection information, status %#lx.\n", status ); - goto fail; - } - - info.hid.dwVendorId = hid_info.VendorID; - info.hid.dwProductId = hid_info.ProductID; - info.hid.dwVersionNumber = hid_info.VersionNumber; - - if (!(preparsed = malloc( hid_info.DescriptorSize ))) - { - ERR( "Failed to allocate memory.\n" ); - goto fail; - } - - status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, - IOCTL_HID_GET_COLLECTION_DESCRIPTOR, - NULL, 0, preparsed, hid_info.DescriptorSize ); - if (status) - { - ERR( "Failed to get collection descriptor, status %#lx.\n", status ); - goto fail; - } - - info.hid.usUsagePage = preparsed->usage_page; - info.hid.usUsage = preparsed->usage; - break; - - case RIM_TYPEMOUSE: - info.mouse = mouse_info; - break; - - case RIM_TYPEKEYBOARD: - info.keyboard = keyboard_info; - break; - } - - for (i = 0; i < rawinput_devices_count && !device; ++i) - if (rawinput_devices[i].handle == UlongToHandle(handle)) - device = rawinput_devices + i; - - if (device) - { - TRACE( "Updating device %#x / %s.\n", handle, debugstr_w(path) ); - free(device->data); - CloseHandle(device->file); - free( device->path ); - } - else if (array_reserve((void **)&rawinput_devices, &rawinput_devices_max, - rawinput_devices_count + 1, sizeof(*rawinput_devices))) - { - device = &rawinput_devices[rawinput_devices_count++]; - TRACE( "Adding device %#x / %s.\n", handle, debugstr_w(path) ); - } - else - { - ERR("Failed to allocate memory.\n"); - goto fail; - } - - device->path = path; - device->file = file; - device->handle = ULongToHandle(handle); - device->info = info; - device->data = preparsed; - - return device; - -fail: - free( preparsed ); - CloseHandle( file ); - free( path ); - return NULL; -} - -static HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len ) -{ - UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name }; - OBJECT_ATTRIBUTES attr; - HANDLE ret; - - attr.Length = sizeof(attr); - attr.RootDirectory = root; - attr.ObjectName = &nameW; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - - if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return 0; - return ret; -} - -static const WCHAR device_classesW[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\"; -static const WCHAR guid_devinterface_hidW[] = L"{4d1e55b2-f16f-11cf-88cb-001111000030}"; -static const WCHAR guid_devinterface_keyboardW[] = L"{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"; -static const WCHAR guid_devinterface_mouseW[] = L"{378de44c-56ef-11d1-bc8c-00a0c91405dd}"; - -static void enumerate_devices( DWORD type, const WCHAR *class ) -{ - WCHAR buffer[1024]; - KEY_NODE_INFORMATION *subkey_info = (void *)buffer; - HKEY class_key, device_key, iface_key; - unsigned int i, j; - DWORD size; - - wcscpy( buffer, device_classesW ); - wcscat( buffer, class ); - if (!(class_key = reg_open_key( NULL, buffer, wcslen( buffer ) * sizeof(WCHAR) ))) - return; - - for (i = 0; !NtEnumerateKey( class_key, i, KeyNodeInformation, buffer, sizeof(buffer), &size ); ++i) - { - if (!(device_key = reg_open_key( class_key, subkey_info->Name, subkey_info->NameLength ))) - { - ERR( "failed to open %s\n", debugstr_wn(subkey_info->Name, subkey_info->NameLength / sizeof(WCHAR)) ); - continue; - } - - for (j = 0; !NtEnumerateKey( device_key, j, KeyNodeInformation, buffer, sizeof(buffer), &size ); ++j) - { - if (!(iface_key = reg_open_key( device_key, subkey_info->Name, subkey_info->NameLength ))) - { - ERR( "failed to open %s\n", debugstr_wn(subkey_info->Name, subkey_info->NameLength / sizeof(WCHAR)) ); - continue; - } - - add_device( iface_key, type ); - NtClose( iface_key ); - } - - NtClose( device_key ); - } - - NtClose( class_key ); -} - -void CDECL rawinput_update_device_list(void) -{ - DWORD idx; - - TRACE("\n"); - - EnterCriticalSection(&rawinput_devices_cs); - - /* destroy previous list */ - for (idx = 0; idx < rawinput_devices_count; ++idx) - { - free(rawinput_devices[idx].data); - CloseHandle(rawinput_devices[idx].file); - free( rawinput_devices[idx].path ); - } - rawinput_devices_count = 0; - - enumerate_devices( RIM_TYPEHID, guid_devinterface_hidW ); - enumerate_devices( RIM_TYPEMOUSE, guid_devinterface_mouseW ); - enumerate_devices( RIM_TYPEKEYBOARD, guid_devinterface_keyboardW ); - - LeaveCriticalSection(&rawinput_devices_cs); -} - - -static struct device *find_device_from_handle(HANDLE handle) -{ - UINT i; - for (i = 0; i < rawinput_devices_count; ++i) - if (rawinput_devices[i].handle == handle) - return rawinput_devices + i; - rawinput_update_device_list(); - for (i = 0; i < rawinput_devices_count; ++i) - if (rawinput_devices[i].handle == handle) - return rawinput_devices + i; - return NULL; -} - - -BOOL rawinput_device_get_usages(HANDLE handle, USAGE *usage_page, USAGE *usage) -{ - struct device *device; - - *usage_page = *usage = 0; - - if (!(device = find_device_from_handle(handle))) return FALSE; - if (device->info.dwType != RIM_TYPEHID) return FALSE; - - *usage_page = device->info.hid.usUsagePage; - *usage = device->info.hid.usUsage; - return TRUE; -} - - -/*********************************************************************** - * GetRawInputDeviceList (USER32.@) - */ -UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_count, UINT size) -{ - static UINT last_check; - UINT i, ticks = GetTickCount(); - - TRACE("devices %p, device_count %p, size %u.\n", devices, device_count, size); - - if (size != sizeof(*devices)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return ~0U; - } - - if (!device_count) - { - SetLastError(ERROR_NOACCESS); - return ~0U; - } - - if (ticks - last_check > 2000) - { - last_check = ticks; - rawinput_update_device_list(); - } - - if (!devices) - { - *device_count = rawinput_devices_count; - return 0; - } - - if (*device_count < rawinput_devices_count) - { - SetLastError(ERROR_INSUFFICIENT_BUFFER); - *device_count = rawinput_devices_count; - return ~0U; - } - - for (i = 0; i < rawinput_devices_count; ++i) - { - devices[i].hDevice = rawinput_devices[i].handle; - devices[i].dwType = rawinput_devices[i].info.dwType; - } - - return rawinput_devices_count; -} - /*********************************************************************** * GetRawInputDeviceInfoA (USER32.@) */ @@ -424,7 +62,7 @@ UINT WINAPI GetRawInputDeviceInfoA(HANDLE device, UINT command, void *data, UINT else nameW = NULL; - ret = GetRawInputDeviceInfoW(device, command, nameW, &nameW_sz); + ret = NtUserGetRawInputDeviceInfo( device, command, nameW, &nameW_sz ); if (ret && ret != ~0U) WideCharToMultiByte(CP_ACP, 0, nameW, -1, data, *data_size, NULL, NULL); @@ -436,74 +74,7 @@ UINT WINAPI GetRawInputDeviceInfoA(HANDLE device, UINT command, void *data, UINT return ret; } - return GetRawInputDeviceInfoW(device, command, data, data_size); -} - -/*********************************************************************** - * GetRawInputDeviceInfoW (USER32.@) - */ -UINT WINAPI GetRawInputDeviceInfoW(HANDLE handle, UINT command, void *data, UINT *data_size) -{ - struct hid_preparsed_data *preparsed; - RID_DEVICE_INFO info; - struct device *device; - DWORD len, data_len; - - TRACE("handle %p, command %#x, data %p, data_size %p.\n", - handle, command, data, data_size); - - if (!data_size) - { - SetLastError(ERROR_NOACCESS); - return ~0U; - } - if (!(device = find_device_from_handle(handle))) - { - SetLastError(ERROR_INVALID_HANDLE); - return ~0U; - } - - data_len = *data_size; - switch (command) - { - case RIDI_DEVICENAME: - if ((len = wcslen( device->path ) + 1) <= data_len && data) - memcpy( data, device->path, len * sizeof(WCHAR) ); - *data_size = len; - break; - - case RIDI_DEVICEINFO: - if ((len = sizeof(info)) <= data_len && data) - memcpy(data, &device->info, len); - *data_size = len; - break; - - case RIDI_PREPARSEDDATA: - if (!(preparsed = device->data)) len = 0; - else len = preparsed->caps_size + FIELD_OFFSET(struct hid_preparsed_data, value_caps[0]) + - preparsed->number_link_collection_nodes * sizeof(struct hid_collection_node); - - if (preparsed && len <= data_len && data) - memcpy(data, preparsed, len); - *data_size = len; - break; - - default: - FIXME("command %#x not supported\n", command); - SetLastError(ERROR_INVALID_PARAMETER); - return ~0U; - } - - if (!data) - return 0; - - if (data_len < len) - { - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return ~0U; - } - - return *data_size; + return NtUserGetRawInputDeviceInfo( device, command, data, data_size ); } /*********************************************************************** diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 3e20277251a..e1cc18f7287 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -369,8 +369,8 @@ @ stdcall GetRawInputBuffer(ptr ptr long) NtUserGetRawInputBuffer @ stdcall GetRawInputData(ptr long ptr ptr long) NtUserGetRawInputData @ stdcall GetRawInputDeviceInfoA(ptr long ptr ptr) -@ stdcall GetRawInputDeviceInfoW(ptr long ptr ptr) -@ stdcall GetRawInputDeviceList(ptr ptr long) +@ stdcall GetRawInputDeviceInfoW(ptr long ptr ptr) NtUserGetRawInputDeviceInfo +@ stdcall GetRawInputDeviceList(ptr ptr long) NtUserGetRawInputDeviceList # @ stub GetReasonTitleFromReasonCode @ stdcall GetRegisteredRawInputDevices(ptr ptr long) NtUserGetRegisteredRawInputDevices @ stdcall GetScrollBarInfo(long long ptr) diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 038f1f0796f..2391131e4a5 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -161,8 +161,6 @@ static const struct user_callbacks user_funcs = free_win_ptr, notify_ime, post_dde_message, - rawinput_update_device_list, - rawinput_device_get_usages, SCROLL_SetStandardScrollPainted, unpack_dde_message, register_imm, diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 71248e03bb8..a646f9a234d 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -60,14 +60,8 @@ extern HMODULE user32_module DECLSPEC_HIDDEN; struct dce; struct tagWND; -struct hardware_msg_data; -extern BOOL rawinput_device_get_usages(HANDLE handle, USAGE *usage_page, USAGE *usage); -extern void CDECL rawinput_update_device_list(void); - extern BOOL post_dde_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD dest_tid, DWORD type ) DECLSPEC_HIDDEN; -extern BOOL process_rawinput_message( MSG *msg, UINT hw_id, - const struct hardware_msg_data *msg_data ) DECLSPEC_HIDDEN; extern BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, void **buffer, size_t size ) DECLSPEC_HIDDEN; extern void free_cached_data( UINT format, HANDLE handle ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 94a1bc71520..0603a248f60 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2381,9 +2381,8 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r hid_usage_page = ((USAGE *)rawinput->data.hid.bRawData)[0]; hid_usage = ((USAGE *)rawinput->data.hid.bRawData)[1]; } - if (input->hi.uMsg == WM_INPUT && user_callbacks && - !user_callbacks->rawinput_device_get_usages( rawinput->header.hDevice, - &hid_usage_page, &hid_usage )) + if (input->hi.uMsg == WM_INPUT && + !rawinput_device_get_usages( rawinput->header.hDevice, &hid_usage_page, &hid_usage )) { WARN( "unable to get HID usages for device %p\n", rawinput->header.hDevice ); return STATUS_INVALID_HANDLE; diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index fd70c022c6f..82d70ec93bb 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -40,8 +40,6 @@ struct user_callbacks void (CDECL *notify_ime)( HWND hwnd, UINT param ); BOOL (CDECL *post_dde_message)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD dest_tid, DWORD type ); - void (CDECL *rawinput_update_device_list)(void); - BOOL (CDECL *rawinput_device_get_usages)(HANDLE handle, USHORT *usage_page, USHORT *usage); void (WINAPI *set_standard_scroll_painted)( HWND hwnd, INT bar, BOOL visible ); BOOL (CDECL *unpack_dde_message)( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, void **buffer, size_t size ); diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index 1caf11f2e76..81403771c4a 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -24,8 +24,14 @@ #endif #include +#include + #include "win32u_private.h" #include "ntuser_private.h" +#define WIN32_NO_STATUS +#include "winioctl.h" +#include "ddk/hidclass.h" +#include "wine/hid.h" #include "wine/server.h" #include "wine/debug.h" @@ -188,6 +194,432 @@ static bool rawinput_from_hardware_message( RAWINPUT *rawinput, const struct har return true; } +struct device +{ + WCHAR *path; + HANDLE file; + HANDLE handle; + RID_DEVICE_INFO info; + struct hid_preparsed_data *data; +}; + +static struct device *rawinput_devices; +static unsigned int rawinput_devices_count, rawinput_devices_max; + +static pthread_mutex_t rawinput_devices_mutex = PTHREAD_MUTEX_INITIALIZER; + +static bool array_reserve( void **elements, unsigned int *capacity, unsigned int count, unsigned int size ) +{ + unsigned int new_capacity, max_capacity; + void *new_elements; + + if (count <= *capacity) + return true; + + max_capacity = ~(unsigned int)0 / size; + if (count > max_capacity) + return false; + + new_capacity = max( 4, *capacity ); + while (new_capacity < count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + if (new_capacity < count) + new_capacity = max_capacity; + + if (!(new_elements = realloc( *elements, new_capacity * size ))) + return false; + + *elements = new_elements; + *capacity = new_capacity; + + return true; +} + +static struct device *add_device( HKEY key, DWORD type ) +{ + static const WCHAR symbolic_linkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0}; + char value_buffer[4096]; + KEY_VALUE_PARTIAL_INFORMATION *value = (KEY_VALUE_PARTIAL_INFORMATION *)value_buffer; + static const RID_DEVICE_INFO_KEYBOARD keyboard_info = {0, 0, 1, 12, 3, 101}; + static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE}; + struct hid_preparsed_data *preparsed = NULL; + HID_COLLECTION_INFORMATION hid_info; + struct device *device = NULL; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING string; + RID_DEVICE_INFO info; + IO_STATUS_BLOCK io; + WCHAR *path, *pos; + NTSTATUS status; + unsigned int i; + UINT32 handle; + HANDLE file; + + if (!query_reg_value( key, symbolic_linkW, value, sizeof(value_buffer) )) + { + ERR( "failed to get symbolic link value\n" ); + return NULL; + } + + if (!(path = malloc( value->DataLength + sizeof(WCHAR) ))) + return NULL; + memcpy( path, value->Data, value->DataLength ); + path[value->DataLength / sizeof(WCHAR)] = 0; + + /* upper case everything but the GUID */ + for (pos = path; *pos && *pos != '{'; pos++) *pos = towupper( *pos ); + + /* path is in DOS format and begins with \\?\ prefix */ + path[1] = '?'; + + RtlInitUnicodeString( &string, path ); + InitializeObjectAttributes( &attr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL ); + if ((status = NtOpenFile( &file, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &attr, &io, + FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT ))) + { + ERR( "Failed to open device file %s, status %#x.\n", debugstr_w(path), status ); + free( path ); + return NULL; + } + + path[1] = '\\'; + + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, IOCTL_HID_GET_WINE_RAWINPUT_HANDLE, + NULL, 0, &handle, sizeof(handle) ); + if (status) + { + ERR( "Failed to get raw input handle, status %#x.\n", status ); + goto fail; + } + + memset( &info, 0, sizeof(info) ); + info.cbSize = sizeof(info); + info.dwType = type; + + switch (type) + { + case RIM_TYPEHID: + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, + IOCTL_HID_GET_COLLECTION_INFORMATION, + NULL, 0, &hid_info, sizeof(hid_info) ); + if (status) + { + ERR( "Failed to get collection information, status %#x.\n", status ); + goto fail; + } + + info.hid.dwVendorId = hid_info.VendorID; + info.hid.dwProductId = hid_info.ProductID; + info.hid.dwVersionNumber = hid_info.VersionNumber; + + if (!(preparsed = malloc( hid_info.DescriptorSize ))) + { + ERR( "Failed to allocate memory.\n" ); + goto fail; + } + + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, + IOCTL_HID_GET_COLLECTION_DESCRIPTOR, + NULL, 0, preparsed, hid_info.DescriptorSize ); + if (status) + { + ERR( "Failed to get collection descriptor, status %#x.\n", status ); + goto fail; + } + + info.hid.usUsagePage = preparsed->usage_page; + info.hid.usUsage = preparsed->usage; + break; + + case RIM_TYPEMOUSE: + info.mouse = mouse_info; + break; + + case RIM_TYPEKEYBOARD: + info.keyboard = keyboard_info; + break; + } + + for (i = 0; i < rawinput_devices_count && !device; ++i) + { + if (rawinput_devices[i].handle == UlongToHandle(handle)) + device = rawinput_devices + i; + } + + if (device) + { + TRACE( "Updating device %#x / %s.\n", handle, debugstr_w(path) ); + free( device->data ); + NtClose( device->file ); + free( device->path ); + } + else if (array_reserve( (void **)&rawinput_devices, &rawinput_devices_max, + rawinput_devices_count + 1, sizeof(*rawinput_devices) )) + { + device = &rawinput_devices[rawinput_devices_count++]; + TRACE( "Adding device %#x / %s.\n", handle, debugstr_w(path) ); + } + else + { + ERR( "Failed to allocate memory.\n" ); + goto fail; + } + + device->path = path; + device->file = file; + device->handle = ULongToHandle(handle); + device->info = info; + device->data = preparsed; + + return device; + +fail: + free( preparsed ); + NtClose( file ); + free( path ); + return NULL; +} + +static const WCHAR device_classesW[] = +{ + '\\','R','e','g','i','s','t','r','y', + '\\','M','a','c','h','i','n','e', + '\\','S','y','s','t','e','m', + '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t', + '\\','C','o','n','t','r','o','l', + '\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',0 +}; +static const WCHAR guid_devinterface_hidW[] = +{ + '{','4','d','1','e','5','5','b','2','-','f','1','6','f','-','1','1','c','f', + '-','8','8','c','b','-','0','0','1','1','1','1','0','0','0','0','3','0','}',0 +}; +static const WCHAR guid_devinterface_keyboardW[] = +{ + '{','8','8','4','b','9','6','c','3','-','5','6','e','f','-','1','1','d','1', + '-','b','c','8','c','-','0','0','a','0','c','9','1','4','0','5','d','d','}',0 +}; +static const WCHAR guid_devinterface_mouseW[] = +{ + '{','3','7','8','d','e','4','4','c','-','5','6','e','f','-','1','1','d','1', + '-','b','c','8','c','-','0','0','a','0','c','9','1','4','0','5','d','d','}',0 +}; + +static void enumerate_devices( DWORD type, const WCHAR *class ) +{ + WCHAR buffer[1024]; + KEY_NODE_INFORMATION *subkey_info = (void *)buffer; + HKEY class_key, device_key, iface_key; + unsigned int i, j; + DWORD size; + + wcscpy( buffer, device_classesW ); + wcscat( buffer, class ); + if (!(class_key = reg_open_key( NULL, buffer, wcslen( buffer ) * sizeof(WCHAR) ))) + return; + + for (i = 0; !NtEnumerateKey( class_key, i, KeyNodeInformation, buffer, sizeof(buffer), &size ); ++i) + { + if (!(device_key = reg_open_key( class_key, subkey_info->Name, subkey_info->NameLength ))) + { + ERR( "failed to open %s\n", debugstr_wn(subkey_info->Name, subkey_info->NameLength / sizeof(WCHAR)) ); + continue; + } + + for (j = 0; !NtEnumerateKey( device_key, j, KeyNodeInformation, buffer, sizeof(buffer), &size ); ++j) + { + if (!(iface_key = reg_open_key( device_key, subkey_info->Name, subkey_info->NameLength ))) + { + ERR( "failed to open %s\n", debugstr_wn(subkey_info->Name, subkey_info->NameLength / sizeof(WCHAR)) ); + continue; + } + + add_device( iface_key, type ); + NtClose( iface_key ); + } + + NtClose( device_key ); + } + + NtClose( class_key ); +} + +static void rawinput_update_device_list(void) +{ + unsigned int i; + + TRACE( "\n" ); + + pthread_mutex_lock( &rawinput_devices_mutex ); + + /* destroy previous list */ + for (i = 0; i < rawinput_devices_count; ++i) + { + free( rawinput_devices[i].data ); + NtClose( rawinput_devices[i].file ); + free( rawinput_devices[i].path ); + } + rawinput_devices_count = 0; + + enumerate_devices( RIM_TYPEHID, guid_devinterface_hidW ); + enumerate_devices( RIM_TYPEMOUSE, guid_devinterface_mouseW ); + enumerate_devices( RIM_TYPEKEYBOARD, guid_devinterface_keyboardW ); + + pthread_mutex_unlock( &rawinput_devices_mutex ); +} + +static struct device *find_device_from_handle( HANDLE handle ) +{ + unsigned int i; + + for (i = 0; i < rawinput_devices_count; ++i) + { + if (rawinput_devices[i].handle == handle) + return rawinput_devices + i; + } + + rawinput_update_device_list(); + + for (i = 0; i < rawinput_devices_count; ++i) + { + if (rawinput_devices[i].handle == handle) + return rawinput_devices + i; + } + return NULL; +} + +BOOL rawinput_device_get_usages( HANDLE handle, USAGE *usage_page, USAGE *usage ) +{ + struct device *device; + + *usage_page = *usage = 0; + + if (!(device = find_device_from_handle( handle ))) return FALSE; + if (device->info.dwType != RIM_TYPEHID) return FALSE; + + *usage_page = device->info.hid.usUsagePage; + *usage = device->info.hid.usUsage; + return TRUE; +} + +/********************************************************************** + * NtUserGetRawInputDeviceList (win32u.@) + */ +UINT WINAPI NtUserGetRawInputDeviceList( RAWINPUTDEVICELIST *devices, UINT *device_count, UINT size ) +{ + static unsigned int last_check; + unsigned int i, ticks = NtGetTickCount(); + + TRACE("devices %p, device_count %p, size %u.\n", devices, device_count, size); + + if (size != sizeof(*devices)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + if (!device_count) + { + SetLastError( ERROR_NOACCESS ); + return ~0u; + } + + if (ticks - last_check > 2000) + { + last_check = ticks; + rawinput_update_device_list(); + } + + if (!devices) + { + *device_count = rawinput_devices_count; + return 0; + } + + if (*device_count < rawinput_devices_count) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + *device_count = rawinput_devices_count; + return ~0u; + } + + for (i = 0; i < rawinput_devices_count; ++i) + { + devices[i].hDevice = rawinput_devices[i].handle; + devices[i].dwType = rawinput_devices[i].info.dwType; + } + + return rawinput_devices_count; +} + +/********************************************************************** + * NtUserGetRawInputDeviceInfo (win32u.@) + */ +UINT WINAPI NtUserGetRawInputDeviceInfo( HANDLE handle, UINT command, void *data, UINT *data_size ) +{ + const struct hid_preparsed_data *preparsed; + struct device *device; + RID_DEVICE_INFO info; + DWORD len, data_len; + + TRACE( "handle %p, command %#x, data %p, data_size %p.\n", handle, command, data, data_size ); + + if (!data_size) + { + SetLastError( ERROR_NOACCESS ); + return ~0u; + } + if (!(device = find_device_from_handle( handle ))) + { + SetLastError( ERROR_INVALID_HANDLE ); + return ~0u; + } + + data_len = *data_size; + switch (command) + { + case RIDI_DEVICENAME: + if ((len = wcslen( device->path ) + 1) <= data_len && data) + memcpy( data, device->path, len * sizeof(WCHAR) ); + *data_size = len; + break; + + case RIDI_DEVICEINFO: + if ((len = sizeof(info)) <= data_len && data) + memcpy( data, &device->info, len ); + *data_size = len; + break; + + case RIDI_PREPARSEDDATA: + if (!(preparsed = device->data)) + len = 0; + else + len = preparsed->caps_size + FIELD_OFFSET(struct hid_preparsed_data, value_caps[0]) + + preparsed->number_link_collection_nodes * sizeof(struct hid_collection_node); + + if (preparsed && len <= data_len && data) + memcpy( data, preparsed, len ); + *data_size = len; + break; + + default: + FIXME( "command %#x not supported\n", command ); + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + if (!data) + return 0; + + if (data_len < len) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return ~0u; + } + + return *data_size; +} + /********************************************************************** * NtUserGetRawInputBuffer (win32u.@) */ @@ -353,7 +785,7 @@ BOOL process_rawinput_message( MSG *msg, UINT hw_id, const struct hardware_msg_d if (msg->message == WM_INPUT_DEVICE_CHANGE) { - if (user_callbacks) user_callbacks->rawinput_update_device_list(); + rawinput_update_device_list(); } else { diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 49746725816..e68519f15e5 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -147,6 +147,8 @@ static void * const syscalls[] = NtUserGetProp, NtUserGetRawInputBuffer, NtUserGetRawInputData, + NtUserGetRawInputDeviceInfo, + NtUserGetRawInputDeviceList, NtUserGetRegisteredRawInputDevices, NtUserGetSystemDpiForProcess, NtUserGetThreadDesktop, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index dab6e2a5ed8..68201f763ab 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -985,8 +985,8 @@ @ stub NtUserGetQueueStatusReadonly @ stdcall -syscall NtUserGetRawInputBuffer(ptr ptr long) @ stdcall -syscall NtUserGetRawInputData(ptr long ptr ptr long) -@ stub NtUserGetRawInputDeviceInfo -@ stub NtUserGetRawInputDeviceList +@ stdcall -syscall NtUserGetRawInputDeviceInfo(ptr long ptr ptr) +@ stdcall -syscall NtUserGetRawInputDeviceList(ptr ptr long) @ stub NtUserGetRawPointerDeviceData @ stdcall -syscall NtUserGetRegisteredRawInputDevices(ptr ptr long) @ stub NtUserGetRequiredCursorSizes diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index a3f3855de7a..d3f359fd4ee 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -437,6 +437,7 @@ extern LRESULT send_message_timeout( HWND hwnd, UINT msg, WPARAM wparam, LPARAM /* rawinput.c */ extern BOOL process_rawinput_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) DECLSPEC_HIDDEN; +extern BOOL rawinput_device_get_usages( HANDLE handle, USHORT *usage_page, USHORT *usage ) DECLSPEC_HIDDEN; /* sysparams.c */ extern BOOL enable_thunk_lock DECLSPEC_HIDDEN; diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index 903f146025d..30b6795f8e8 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -134,6 +134,8 @@ SYSCALL_ENTRY( NtUserGetProp ) \ SYSCALL_ENTRY( NtUserGetRawInputBuffer ) \ SYSCALL_ENTRY( NtUserGetRawInputData ) \ + SYSCALL_ENTRY( NtUserGetRawInputDeviceInfo ) \ + SYSCALL_ENTRY( NtUserGetRawInputDeviceList ) \ SYSCALL_ENTRY( NtUserGetRegisteredRawInputDevices ) \ SYSCALL_ENTRY( NtUserGetSystemDpiForProcess ) \ SYSCALL_ENTRY( NtUserGetThreadDesktop ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 46a399752a4..82f3881a8c6 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -72,6 +72,12 @@ typedef struct UINT32 hwndTarget; } RAWINPUTDEVICE32; +typedef struct +{ + UINT32 hDevice; + DWORD dwType; +} RAWINPUTDEVICELIST32; + static MSG *msg_32to64( MSG *msg, MSG32 *msg32 ) { if (!msg32) return NULL; @@ -1056,3 +1062,52 @@ NTSTATUS WINAPI wow64_NtUserGetRegisteredRawInputDevices( UINT *args ) return NtUserGetRegisteredRawInputDevices( NULL, count, sizeof(RAWINPUTDEVICE) ); } } + +NTSTATUS WINAPI wow64_NtUserGetRawInputDeviceInfo( UINT *args ) +{ + HANDLE handle = get_handle( &args ); + UINT command = get_ulong( &args ); + void *data = get_ptr( &args ); + UINT *data_size = get_ptr( &args ); + + return NtUserGetRawInputDeviceInfo( handle, command, data, data_size ); +} + +NTSTATUS WINAPI wow64_NtUserGetRawInputDeviceList( UINT *args ) +{ + RAWINPUTDEVICELIST32 *devices32 = get_ptr( &args ); + UINT *count = get_ptr( &args ); + UINT size = get_ulong( &args ); + + if (size != sizeof(RAWINPUTDEVICELIST32)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + if (devices32) + { + RAWINPUTDEVICELIST *devices64; + unsigned int ret, i; + + if (!(devices64 = Wow64AllocateTemp( (*count) * sizeof(*devices64) ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + + ret = NtUserGetRawInputDeviceList( devices64, count, sizeof(RAWINPUTDEVICELIST) ); + if (ret == ~0u) return ret; + + for (i = 0; i < *count; ++i) + { + devices32[i].hDevice = (UINT_PTR)devices64[i].hDevice; + devices32[i].dwType = devices64[i].dwType; + } + return ret; + } + else + { + return NtUserGetRawInputDeviceList( NULL, count, sizeof(RAWINPUTDEVICELIST) ); + } +} diff --git a/include/ntuser.h b/include/ntuser.h index 9c4aaf041a4..3862eb55054 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -621,6 +621,8 @@ ULONG WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process ); DWORD WINAPI NtUserGetQueueStatus( UINT flags ); UINT WINAPI NtUserGetRawInputBuffer( RAWINPUT *data, UINT *data_size, UINT header_size ); UINT WINAPI NtUserGetRawInputData( HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size ); +UINT WINAPI NtUserGetRawInputDeviceInfo( HANDLE handle, UINT command, void *data, UINT *data_size ); +UINT WINAPI NtUserGetRawInputDeviceList( RAWINPUTDEVICELIST *devices, UINT *device_count, UINT size ); UINT WINAPI NtUserGetRegisteredRawInputDevices( RAWINPUTDEVICE *devices, UINT *device_count, UINT size ); ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process ); HMENU WINAPI NtUserGetSystemMenu( HWND hwnd, BOOL revert ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/313