[PATCH 5/9] dinput: Enumerate HID collections, input buttons and values.

Rémi Bernon rbernon at codeweavers.com
Fri Aug 27 04:10:01 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..5f709a7c30a 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