mirror of
git://source.winehq.org/git/wine.git
synced 2024-07-24 05:46:23 +00:00
win32u: Move raw input device list management from user32.
This commit is contained in:
parent
cbbab65571
commit
0a93089019
|
@ -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 );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -147,6 +147,8 @@ static void * const syscalls[] =
|
|||
NtUserGetProp,
|
||||
NtUserGetRawInputBuffer,
|
||||
NtUserGetRawInputData,
|
||||
NtUserGetRawInputDeviceInfo,
|
||||
NtUserGetRawInputDeviceList,
|
||||
NtUserGetRegisteredRawInputDevices,
|
||||
NtUserGetSystemDpiForProcess,
|
||||
NtUserGetThreadDesktop,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ) \
|
||||
|
|
|
@ -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 ~0u;
|
||||
}
|
||||
|
||||
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) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue