[PATCH v2 06/10] dinput: Enumerate HID collections, input buttons and values.
Rémi Bernon
rbernon at codeweavers.com
Fri Aug 27 05:45:25 CDT 2021
And initialize data format from them.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/dinput/joystick_hid.c | 417 ++++++++++++++++++++++++++++++++++++-
1 file changed, 415 insertions(+), 2 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index 601de3b00b0..e3654a38a6a 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -48,6 +48,93 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput);
DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7 );
DEFINE_DEVPROPKEY( DEVPROPKEY_HID_HANDLE, 0xbc62e415, 0xf4fe, 0x405c, 0x8e, 0xda, 0x63, 0x6f, 0xb5, 0x9f, 0x08, 0x98, 2 );
+static inline const char *debugstr_hidp_link_collection_node( HIDP_LINK_COLLECTION_NODE *node )
+{
+ if (!node) return "(null)";
+ return wine_dbg_sprintf( "Usg %02x:%02x Par %u Nxt %u Cnt %u Chld %u Type %u Alias %d User %p",
+ node->LinkUsagePage, node->LinkUsage, node->Parent, node->NextSibling,
+ node->NumberOfChildren, node->FirstChild, node->CollectionType, node->IsAlias,
+ node->UserContext );
+}
+
+static inline const char *debugstr_hidp_button_caps( HIDP_BUTTON_CAPS *caps )
+{
+ const char *str;
+ if (!caps) return "(null)";
+
+ str = wine_dbg_sprintf( "RId %d,", caps->ReportID );
+ if (!caps->IsRange)
+ str = wine_dbg_sprintf( "%s Usg %02x:%02x Dat %02x,", str, caps->UsagePage, caps->NotRange.Usage,
+ caps->NotRange.DataIndex );
+ else
+ str = wine_dbg_sprintf( "%s Usg %02x:%02x-%02x Dat %02x-%02x,", str, caps->UsagePage, caps->Range.UsageMin,
+ caps->Range.UsageMax, caps->Range.DataIndexMin, caps->Range.DataIndexMax );
+ if (!caps->IsStringRange)
+ str = wine_dbg_sprintf( "%s Str %d,", str, caps->NotRange.StringIndex );
+ else
+ str = wine_dbg_sprintf( "%s Str %d-%d,", str, caps->Range.StringMin, caps->Range.StringMax );
+ if (!caps->IsDesignatorRange)
+ str = wine_dbg_sprintf( "%s Des %d,", str, caps->NotRange.DesignatorIndex );
+ else
+ str = wine_dbg_sprintf( "%s Des %d-%d,", str, caps->Range.DesignatorMin, caps->Range.DesignatorMax );
+ return wine_dbg_sprintf( "%s Bits %02x Alias %d Abs %d, LCol %u LUsg %02x-%02x", str, caps->BitField, caps->IsAlias,
+ caps->IsAbsolute, caps->LinkCollection, caps->LinkUsagePage, caps->LinkUsage );
+}
+
+static inline const char *debugstr_hidp_value_caps( HIDP_VALUE_CAPS *caps )
+{
+ const char *str;
+ if (!caps) return "(null)";
+
+ str = wine_dbg_sprintf( "RId %d,", caps->ReportID );
+ if (!caps->IsRange)
+ str = wine_dbg_sprintf( "%s Usg %02x:%02x Dat %02x,", str, caps->UsagePage, caps->NotRange.Usage,
+ caps->NotRange.DataIndex );
+ else
+ str = wine_dbg_sprintf( "%s Usg %02x:%02x-%02x Dat %02x-%02x,", str, caps->UsagePage, caps->Range.UsageMin,
+ caps->Range.UsageMax, caps->Range.DataIndexMin, caps->Range.DataIndexMax );
+ if (!caps->IsStringRange)
+ str = wine_dbg_sprintf( "%s Str %d,", str, caps->NotRange.StringIndex );
+ else
+ str = wine_dbg_sprintf( "%s Str %d-%d,", str, caps->Range.StringMin, caps->Range.StringMax );
+ if (!caps->IsDesignatorRange)
+ str = wine_dbg_sprintf( "%s Des %d,", str, caps->NotRange.DesignatorIndex );
+ else
+ str = wine_dbg_sprintf( "%s Des %d-%d,", str, caps->Range.DesignatorMin, caps->Range.DesignatorMax );
+ return wine_dbg_sprintf( "%s Bits %02x Alias %d Abs %d Null %d, LCol %u LUsg %02x-%02x, "
+ "BitSz %d, RCnt %d, Unit %x E%+d, Log %+d-%+d, Phy %+d-%+d",
+ str, caps->BitField, caps->IsAlias, caps->IsAbsolute, caps->HasNull,
+ caps->LinkCollection, caps->LinkUsagePage, caps->LinkUsage,
+ caps->BitSize, caps->ReportCount, caps->Units, caps->UnitsExp,
+ caps->LogicalMin, caps->LogicalMax, caps->PhysicalMin, caps->PhysicalMax );
+}
+
+struct hid_caps
+{
+ enum { LINK_COLLECTION_NODE, BUTTON_CAPS, VALUE_CAPS } type;
+ union
+ {
+ HIDP_LINK_COLLECTION_NODE *node;
+ HIDP_BUTTON_CAPS *button;
+ HIDP_VALUE_CAPS *value;
+ };
+};
+
+static inline const char *debugstr_hid_caps( struct hid_caps *caps )
+{
+ switch (caps->type)
+ {
+ case LINK_COLLECTION_NODE:
+ return debugstr_hidp_link_collection_node( caps->node );
+ case BUTTON_CAPS:
+ return debugstr_hidp_button_caps( caps->button );
+ case VALUE_CAPS:
+ return debugstr_hidp_value_caps( caps->value );
+ }
+
+ return "(unknown type)";
+}
+
struct hid_joystick
{
IDirectInputDeviceImpl base;
@@ -60,6 +147,11 @@ struct hid_joystick
WCHAR device_path[MAX_PATH];
HIDD_ATTRIBUTES attrs;
DIDEVCAPS dev_caps;
+ HIDP_CAPS caps;
+
+ HIDP_LINK_COLLECTION_NODE *collection_nodes;
+ HIDP_BUTTON_CAPS *input_button_caps;
+ HIDP_VALUE_CAPS *input_value_caps;
};
static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface )
@@ -68,6 +160,242 @@ static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputD
struct hid_joystick, base );
}
+static const GUID *object_usage_to_guid( USAGE usage_page, USAGE usage )
+{
+ switch (usage_page)
+ {
+ case HID_USAGE_PAGE_BUTTON: return &GUID_Button;
+ case HID_USAGE_PAGE_GENERIC:
+ switch (usage)
+ {
+ case HID_USAGE_GENERIC_X: return &GUID_XAxis;
+ case HID_USAGE_GENERIC_Y: return &GUID_YAxis;
+ case HID_USAGE_GENERIC_Z: return &GUID_ZAxis;
+ case HID_USAGE_GENERIC_RX: return &GUID_RxAxis;
+ case HID_USAGE_GENERIC_RY: return &GUID_RyAxis;
+ case HID_USAGE_GENERIC_RZ: return &GUID_RzAxis;
+ case HID_USAGE_GENERIC_SLIDER: return &GUID_Slider;
+ case HID_USAGE_GENERIC_HATSWITCH: return &GUID_POV;
+ }
+ break;
+ }
+
+ return &GUID_Unknown;
+}
+
+typedef BOOL (*enum_object_callback)( struct hid_joystick *impl, struct hid_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data );
+
+static BOOL enum_object( struct hid_joystick *impl, const DIPROPHEADER *filter, DWORD flags,
+ enum_object_callback callback, struct hid_caps *caps,
+ DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+ if (flags != DIDFT_ALL && !(flags & DIDFT_GETTYPE( instance->dwType ))) return DIENUM_CONTINUE;
+
+ switch (filter->dwHow)
+ {
+ case DIPH_DEVICE:
+ return callback( impl, caps, instance, data );
+ case DIPH_BYOFFSET:
+ if (filter->dwObj != instance->dwOfs) return DIENUM_CONTINUE;
+ return callback( impl, caps, instance, data );
+ case DIPH_BYID:
+ if ((filter->dwObj & 0x00ffffff) != (instance->dwType & 0x00ffffff)) return DIENUM_CONTINUE;
+ return callback( impl, caps, instance, data );
+ case DIPH_BYUSAGE:
+ if (LOWORD(filter->dwObj) != instance->wUsagePage || HIWORD(filter->dwObj) != instance->wUsage) return DIENUM_CONTINUE;
+ return callback( impl, caps, instance, data );
+ default:
+ FIXME( "unimplemented filter dwHow %#x dwObj %#x\n", filter->dwHow, filter->dwObj );
+ break;
+ }
+
+ return DIENUM_CONTINUE;
+}
+
+static BOOL enum_value_objects( struct hid_joystick *impl, const DIPROPHEADER *filter,
+ DWORD flags, enum_object_callback callback, void *data )
+{
+ DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)};
+ struct hid_caps caps = {.type = VALUE_CAPS};
+ DWORD axis = 0, pov = 0, i;
+ BOOL ret;
+
+ for (i = 0; i < impl->caps.NumberInputValueCaps; ++i)
+ {
+ caps.value = impl->input_value_caps + i;
+
+ if (caps.value->UsagePage >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN)
+ TRACE( "Ignoring input value %s, vendor specific.\n", debugstr_hid_caps( &caps ) );
+ else if (caps.value->IsAlias)
+ TRACE( "Ignoring input value %s, aliased.\n", debugstr_hid_caps( &caps ) );
+ else if (caps.value->IsRange)
+ FIXME( "Ignoring input value %s, usage range not implemented.\n", debugstr_hid_caps( &caps ) );
+ else if (caps.value->ReportCount > 1)
+ FIXME( "Ignoring input value %s, array not implemented.\n", debugstr_hid_caps( &caps ) );
+ else if (caps.value->UsagePage != HID_USAGE_PAGE_GENERIC)
+ TRACE( "Ignoring input value %s, usage page not implemented.\n", debugstr_hid_caps( &caps ) );
+ else
+ {
+ instance.wUsagePage = caps.value->UsagePage;
+ instance.wUsage = caps.value->NotRange.Usage;
+ instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage );
+ instance.wReportId = caps.value->ReportID;
+
+ switch (instance.wUsage)
+ {
+ case HID_USAGE_GENERIC_X:
+ instance.dwOfs = DIJOFS_X;
+ instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( axis++ );
+ instance.dwFlags = DIDOI_ASPECTPOSITION;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ break;
+ case HID_USAGE_GENERIC_Y:
+ instance.dwOfs = DIJOFS_Y;
+ instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( axis++ );
+ instance.dwFlags = DIDOI_ASPECTPOSITION;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ break;
+ case HID_USAGE_GENERIC_Z:
+ instance.dwOfs = DIJOFS_Z;
+ instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( axis++ );
+ instance.dwFlags = DIDOI_ASPECTPOSITION;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ break;
+ case HID_USAGE_GENERIC_RX:
+ instance.dwOfs = DIJOFS_RX;
+ instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( axis++ );
+ instance.dwFlags = DIDOI_ASPECTPOSITION;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ break;
+ case HID_USAGE_GENERIC_RY:
+ instance.dwOfs = DIJOFS_RY;
+ instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( axis++ );
+ instance.dwFlags = DIDOI_ASPECTPOSITION;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ break;
+ case HID_USAGE_GENERIC_RZ:
+ instance.dwOfs = DIJOFS_RZ;
+ instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( axis++ );
+ instance.dwFlags = DIDOI_ASPECTPOSITION;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ break;
+ case HID_USAGE_GENERIC_SLIDER:
+ instance.dwOfs = DIJOFS_SLIDER( 0 );
+ instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( axis++ );
+ instance.dwFlags = DIDOI_ASPECTPOSITION;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ break;
+ case HID_USAGE_GENERIC_HATSWITCH:
+ instance.dwOfs = DIJOFS_POV( 0 );
+ instance.dwType = DIDFT_POV | DIDFT_MAKEINSTANCE( pov++ );
+ instance.dwFlags = 0;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ break;
+ default:
+ FIXME( "Ignoring input value %s, usage not implemented.\n", debugstr_hid_caps( &caps ) );
+ break;
+ }
+ }
+ }
+
+ return DIENUM_CONTINUE;
+}
+
+static BOOL enum_button_objects( struct hid_joystick *impl, const DIPROPHEADER *filter,
+ DWORD flags, enum_object_callback callback, void *data )
+{
+ DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)};
+ struct hid_caps caps = {.type = BUTTON_CAPS};
+ DWORD button = 0, i, j;
+ BOOL ret;
+
+ for (i = 0; i < impl->caps.NumberInputButtonCaps; ++i)
+ {
+ caps.button = impl->input_button_caps + i;
+
+ if (caps.button->UsagePage >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN)
+ TRACE( "Ignoring input button %s, vendor specific.\n", debugstr_hid_caps( &caps ) );
+ else if (caps.button->IsAlias)
+ TRACE( "Ignoring input button %s, aliased.\n", debugstr_hid_caps( &caps ) );
+ else if (caps.button->UsagePage != HID_USAGE_PAGE_BUTTON)
+ TRACE( "Ignoring input button %s, usage page not implemented.\n", debugstr_hid_caps( &caps ) );
+ else if (caps.button->IsRange)
+ {
+ if (caps.button->NotRange.Usage >= 128)
+ FIXME( "Ignoring input button %s, too many buttons.\n", debugstr_hid_caps( &caps ) );
+ else for (j = caps.button->Range.UsageMin; j <= caps.button->Range.UsageMax; ++j)
+ {
+ instance.dwOfs = DIJOFS_BUTTON( j - 1 );
+ instance.dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( button++ );
+ instance.dwFlags = 0;
+ instance.wUsagePage = caps.button->UsagePage;
+ instance.wUsage = j;
+ instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage );
+ instance.wReportId = caps.button->ReportID;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ }
+ }
+ else if (caps.button->NotRange.Usage >= 128)
+ FIXME( "Ignoring input button %s, too many buttons.\n", debugstr_hid_caps( &caps ) );
+ else
+ {
+ instance.dwOfs = DIJOFS_BUTTON( caps.button->NotRange.Usage - 1 );
+ instance.dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( button++ );
+ instance.dwFlags = 0;
+ instance.wUsagePage = caps.button->UsagePage;
+ instance.wUsage = caps.button->NotRange.Usage;
+ instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage );
+ instance.wReportId = caps.button->ReportID;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ }
+ }
+
+ return DIENUM_CONTINUE;
+}
+
+static BOOL enum_collections_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, DWORD flags,
+ enum_object_callback callback, void *data )
+{
+ DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)};
+ struct hid_caps caps = {.type = LINK_COLLECTION_NODE};
+ BOOL ret;
+ DWORD i;
+
+ for (i = 0; i < impl->caps.NumberLinkCollectionNodes; ++i)
+ {
+ caps.node = impl->collection_nodes + i;
+
+ if (caps.node->LinkUsagePage >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN)
+ TRACE( "Ignoring collection %s, vendor specific.\n", debugstr_hid_caps( &caps ) );
+ else if (caps.node->IsAlias)
+ TRACE( "Ignoring collection %s, aliased.\n", debugstr_hid_caps( &caps ) );
+ else
+ {
+ instance.dwOfs = 0;
+ instance.dwType = DIDFT_COLLECTION | DIDFT_NODATA;
+ instance.dwFlags = 0;
+ instance.wUsagePage = caps.node->LinkUsagePage;
+ instance.wUsage = caps.node->LinkUsage;
+ instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage );
+ instance.wReportId = 0;
+ ret = enum_object( impl, filter, flags, callback, &caps, &instance, data );
+ if (ret != DIENUM_CONTINUE) return ret;
+ }
+ }
+
+ return DIENUM_CONTINUE;
+}
+
static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface )
{
struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
@@ -76,6 +404,9 @@ static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface )
if (!(ref = IDirectInputDevice2WImpl_Release( iface )))
{
+ HeapFree( GetProcessHeap(), 0, tmp.input_value_caps );
+ HeapFree( GetProcessHeap(), 0, tmp.input_button_caps );
+ HeapFree( GetProcessHeap(), 0, tmp.collection_nodes );
HidD_FreePreparsedData( tmp.preparsed );
CloseHandle( tmp.device );
}
@@ -372,8 +703,44 @@ static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTAN
return DI_OK;
}
+static BOOL init_objects( struct hid_joystick *impl, struct hid_caps *caps,
+ DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+ DIDATAFORMAT *format = impl->base.data_format.wine_df;
+
+ format->dwNumObjs++;
+ if (instance->dwType & DIDFT_PSHBUTTON) impl->dev_caps.dwButtons++;
+ if (instance->dwType & DIDFT_AXIS) impl->dev_caps.dwAxes++;
+ if (instance->dwType & DIDFT_POV) impl->dev_caps.dwPOVs++;
+
+ return DIENUM_CONTINUE;
+}
+
+static BOOL init_data_format( struct hid_joystick *impl, struct hid_caps *caps,
+ DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+ DIDATAFORMAT *format = impl->base.data_format.wine_df;
+ DIOBJECTDATAFORMAT *obj_format;
+ DWORD *index = data;
+
+ obj_format = format->rgodf + *index;
+ obj_format->pguid = object_usage_to_guid( instance->wUsagePage, instance->wUsage );
+ obj_format->dwOfs = instance->dwOfs;
+ obj_format->dwType = instance->dwType;
+ obj_format->dwFlags = instance->dwFlags;
+ (*index)++;
+
+ return DIENUM_CONTINUE;
+}
+
static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID *guid, IDirectInputDevice8W **out )
{
+ static const DIPROPHEADER filter =
+ {
+ .dwSize = sizeof(filter),
+ .dwHeaderSize = sizeof(filter),
+ .dwHow = DIPH_DEVICE,
+ };
DIDEVICEINSTANCEW instance =
{
.dwSize = sizeof(instance),
@@ -381,8 +748,13 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
.guidInstance = *guid
};
HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)};
+ HIDP_LINK_COLLECTION_NODE *nodes;
struct hid_joystick *impl = NULL;
- HIDP_CAPS caps;
+ DIDATAFORMAT *format = NULL;
+ HIDP_BUTTON_CAPS *buttons;
+ HIDP_VALUE_CAPS *values;
+ DWORD size, index;
+ NTSTATUS status;
HRESULT hr;
TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out );
@@ -404,7 +776,7 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
hr = hid_joystick_device_open( -1, &instance, impl->device_path, &impl->device, &impl->preparsed,
- &attrs, &caps, dinput->dwVersion );
+ &attrs, &impl->caps, dinput->dwVersion );
if (hr != DI_OK) goto failed;
impl->instance = instance;
@@ -413,6 +785,47 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
impl->dev_caps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED;
impl->dev_caps.dwDevType = instance.dwDevType;
+ size = impl->caps.NumberLinkCollectionNodes * sizeof(HIDP_LINK_COLLECTION_NODE);
+ if (!(nodes = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
+ impl->collection_nodes = nodes;
+ size = impl->caps.NumberInputButtonCaps * sizeof(HIDP_BUTTON_CAPS);
+ if (!(buttons = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
+ impl->input_button_caps = buttons;
+ size = impl->caps.NumberInputValueCaps * sizeof(HIDP_VALUE_CAPS);
+ if (!(values = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
+ impl->input_value_caps = values;
+
+ size = impl->caps.NumberLinkCollectionNodes;
+ status = HidP_GetLinkCollectionNodes( nodes, &size, impl->preparsed );
+ if (status != HIDP_STATUS_SUCCESS) goto failed;
+ impl->caps.NumberLinkCollectionNodes = size;
+ status = HidP_GetButtonCaps( HidP_Input, impl->input_button_caps,
+ &impl->caps.NumberInputButtonCaps, impl->preparsed );
+ if (status != HIDP_STATUS_SUCCESS && status != HIDP_STATUS_USAGE_NOT_FOUND) goto failed;
+ status = HidP_GetValueCaps( HidP_Input, impl->input_value_caps,
+ &impl->caps.NumberInputValueCaps, impl->preparsed );
+ if (status != HIDP_STATUS_SUCCESS && status != HIDP_STATUS_USAGE_NOT_FOUND) goto failed;
+
+ /* enumerate collections first, so we can find report collections */
+ enum_collections_objects( impl, &filter, DIDFT_ALL, init_objects, NULL );
+ enum_value_objects( impl, &filter, DIDFT_ALL, init_objects, NULL );
+ enum_button_objects( impl, &filter, DIDFT_ALL, init_objects, NULL );
+
+ format = impl->base.data_format.wine_df;
+ size = format->dwNumObjs * sizeof(*format->rgodf);
+ if (!(format->rgodf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto failed;
+ format->dwSize = sizeof(*format);
+ format->dwObjSize = sizeof(*format->rgodf);
+ format->dwFlags = DIDF_ABSAXIS;
+ format->dwDataSize = sizeof(impl->state);
+
+ index = 0;
+ enum_value_objects( impl, &filter, DIDFT_ALL, init_data_format, &index );
+ enum_button_objects( impl, &filter, DIDFT_ALL, init_data_format, &index );
+ enum_collections_objects( impl, &filter, DIDFT_ALL, init_data_format, &index );
+
+ _dump_DIDATAFORMAT( impl->base.data_format.wine_df );
+
*out = &impl->base.IDirectInputDevice8W_iface;
return DI_OK;
--
2.33.0
More information about the wine-devel
mailing list