[PATCH 3/4] win32u: Move raw input device list management from user32.
Zebediah Figura
wine at gitlab.winehq.org
Sat Jun 25 11:57:54 CDT 2022
From: Zebediah Figura <zfigura at codeweavers.com>
---
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 55e72dcf203..cd1e6d9b9cf 100644
--- a/dlls/user32/user_main.c
+++ b/dlls/user32/user_main.c
@@ -162,8 +162,6 @@ static const struct user_callbacks user_funcs =
MENU_GetSysMenu,
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 eb851f57cdb..dc161267465 100644
--- a/dlls/win32u/ntuser_private.h
+++ b/dlls/win32u/ntuser_private.h
@@ -41,8 +41,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 <stdbool.h>
+#include <pthread.h>
+
#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 5e0d09d250a..e3417e55e30 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 2e71f0cfb52..4055e9efae7 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -613,6 +613,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
More information about the wine-devel
mailing list