[PATCH v2 6/9] dinput: Enumerate HID joystick objects using internal HID caps.

Rémi Bernon rbernon at codeweavers.com
Wed Sep 29 03:24:58 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/joystick_hid.c | 349 +++++++++++++------------------------
 1 file changed, 123 insertions(+), 226 deletions(-)

diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index a20925b6176..4d6d53b588e 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -22,6 +22,8 @@
 #include <string.h>
 #include <math.h>
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "winternl.h"
@@ -36,6 +38,7 @@
 #include "setupapi.h"
 
 #include "wine/debug.h"
+#include "wine/hid.h"
 
 #include "dinput_private.h"
 #include "device_private.h"
@@ -50,91 +53,23 @@ DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x4
 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 )
+static inline const char *debugstr_hid_value_caps( struct hid_value_caps *caps )
 {
-    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 );
+    return wine_dbg_sprintf( "RId %d, Usg %02x:%02x-%02x Dat %02x-%02x, Str %d-%d, Des %d-%d, "
+                             "Bits %02x Flags %#x, LCol %d LUsg %02x:%02x, BitSz %d, RCnt %d, Unit %x E%+d, Log %+d-%+d, Phy %+d-%+d",
+                             caps->report_id, caps->usage_page, caps->usage_min, caps->usage_max, caps->data_index_min, caps->data_index_max,
+                             caps->string_min, caps->string_max, caps->designator_min, caps->designator_max, caps->bit_field, caps->flags,
+                             caps->link_collection, caps->link_usage_page, caps->link_usage, caps->bit_size, caps->report_count,
+                             caps->units, caps->units_exp, caps->logical_min, caps->logical_max, caps->physical_min, caps->physical_max );
 }
 
-struct hid_caps
+static inline const char *debugstr_hid_collection_node( struct hid_collection_node *node )
 {
-    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)";
+    if (!node) return "(null)";
+    return wine_dbg_sprintf( "Usg %02x:%02x, Parent %u, Next %u, NbChild %u, Child %u, Type %02x",
+                             node->usage_page, node->usage, node->parent, node->next_sibling,
+                             node->number_of_children, node->first_child, node->collection_type );
 }
 
 struct extra_caps
@@ -159,9 +94,6 @@ struct hid_joystick
     DIDEVCAPS dev_caps;
     HIDP_CAPS caps;
 
-    HIDP_LINK_COLLECTION_NODE *collection_nodes;
-    HIDP_BUTTON_CAPS *input_button_caps;
-    HIDP_VALUE_CAPS *input_value_caps;
     struct extra_caps *input_extra_caps;
 
     char *input_report_buf;
@@ -202,10 +134,11 @@ static const GUID *object_usage_to_guid( USAGE usage_page, USAGE usage )
     return &GUID_Unknown;
 }
 
-typedef BOOL (*enum_object_callback)( struct hid_joystick *impl, struct hid_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data );
+typedef BOOL (*enum_object_callback)( struct hid_joystick *impl, struct hid_value_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,
+                         enum_object_callback callback, struct hid_value_caps *caps,
                          DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
     if (flags != DIDFT_ALL && !(flags & DIDFT_GETTYPE( instance->dwType ))) return DIENUM_CONTINUE;
@@ -242,13 +175,15 @@ static void set_axis_type( DIDEVICEOBJECTINSTANCEW *instance, BOOL *seen, DWORD
 static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, DWORD flags,
                           enum_object_callback callback, void *data )
 {
-    DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)};
     DWORD collection = 0, axis = 0, button = 0, pov = 0, value_ofs = 0, button_ofs = 0, i, j;
+    struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed;
+    DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)};
     DIDATAFORMAT *format = impl->base.data_format.wine_df;
     int *offsets = impl->base.data_format.offsets;
+    struct hid_collection_node *node, *node_end;
+    struct hid_value_caps *caps, *caps_end;
     DIPROPHEADER filter = *header;
     BOOL ret, seen_axis[6] = {0};
-    struct hid_caps caps = {0};
 
     if (filter.dwHow == DIPH_BYOFFSET)
     {
@@ -263,83 +198,83 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header,
     button_ofs += impl->caps.NumberOutputValueCaps * sizeof(LONG);
     button_ofs += impl->caps.NumberFeatureValueCaps * sizeof(LONG);
 
-    for (i = 0; i < impl->caps.NumberInputValueCaps; ++i)
+    for (caps = HID_INPUT_VALUE_CAPS( preparsed ), caps_end = caps + preparsed->input_caps_count;
+         caps != caps_end; ++caps)
     {
-        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 ) );
+        if (!caps->usage_page) continue;
+        if (caps->flags & HID_VALUE_CAPS_IS_BUTTON) continue;
+
+        if (caps->usage_page >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN)
+            TRACE( "Ignoring input value %s, vendor specific.\n", debugstr_hid_value_caps( caps ) );
+        else if (caps->flags & HID_VALUE_CAPS_IS_RANGE)
+            FIXME( "Ignoring input value %s, usage range not implemented.\n", debugstr_hid_value_caps( caps ) );
+        else if (caps->report_count > 1)
+            FIXME( "Ignoring input value %s, array not implemented.\n", debugstr_hid_value_caps( caps ) );
+        else if (caps->usage_page != HID_USAGE_PAGE_GENERIC)
+            TRACE( "Ignoring input value %s, usage page not implemented.\n", debugstr_hid_value_caps( caps ) );
         else
         {
             instance.dwOfs = value_ofs;
-            instance.wUsagePage = caps.value->UsagePage;
-            instance.wUsage = caps.value->NotRange.Usage;
+            instance.wUsagePage = caps->usage_page;
+            instance.wUsage = caps->usage_min;
             instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage );
-            instance.wReportId = caps.value->ReportID;
-            instance.wCollectionNumber = caps.value->LinkCollection;
+            instance.wReportId = caps->report_id;
+            instance.wCollectionNumber = caps->link_collection;
 
             switch (instance.wUsage)
             {
             case HID_USAGE_GENERIC_X:
                 set_axis_type( &instance, seen_axis, 0, &axis );
                 instance.dwFlags = DIDOI_ASPECTPOSITION;
-                ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+                ret = enum_object( impl, &filter, flags, callback, caps, &instance, data );
                 if (ret != DIENUM_CONTINUE) return ret;
                 break;
             case HID_USAGE_GENERIC_Y:
                 set_axis_type( &instance, seen_axis, 1, &axis );
                 instance.dwFlags = DIDOI_ASPECTPOSITION;
-                ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+                ret = enum_object( impl, &filter, flags, callback, caps, &instance, data );
                 if (ret != DIENUM_CONTINUE) return ret;
                 break;
             case HID_USAGE_GENERIC_Z:
             case HID_USAGE_GENERIC_WHEEL:
                 set_axis_type( &instance, seen_axis, 2, &axis );
                 instance.dwFlags = DIDOI_ASPECTPOSITION;
-                ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+                ret = enum_object( impl, &filter, flags, callback, caps, &instance, data );
                 if (ret != DIENUM_CONTINUE) return ret;
                 break;
             case HID_USAGE_GENERIC_RX:
                 set_axis_type( &instance, seen_axis, 3, &axis );
                 instance.dwFlags = DIDOI_ASPECTPOSITION;
-                ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+                ret = enum_object( impl, &filter, flags, callback, caps, &instance, data );
                 if (ret != DIENUM_CONTINUE) return ret;
                 break;
             case HID_USAGE_GENERIC_RY:
                 set_axis_type( &instance, seen_axis, 4, &axis );
                 instance.dwFlags = DIDOI_ASPECTPOSITION;
-                ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+                ret = enum_object( impl, &filter, flags, callback, caps, &instance, data );
                 if (ret != DIENUM_CONTINUE) return ret;
                 break;
             case HID_USAGE_GENERIC_RZ:
                 set_axis_type( &instance, seen_axis, 5, &axis );
                 instance.dwFlags = DIDOI_ASPECTPOSITION;
-                ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+                ret = enum_object( impl, &filter, flags, callback, caps, &instance, data );
                 if (ret != DIENUM_CONTINUE) return ret;
                 break;
             case HID_USAGE_GENERIC_DIAL:
             case HID_USAGE_GENERIC_SLIDER:
                 instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 6 + axis++ );
                 instance.dwFlags = DIDOI_ASPECTPOSITION;
-                ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+                ret = enum_object( impl, &filter, flags, callback, caps, &instance, data );
                 if (ret != DIENUM_CONTINUE) return ret;
                 break;
             case HID_USAGE_GENERIC_HATSWITCH:
                 instance.dwType = DIDFT_POV | DIDFT_MAKEINSTANCE( pov++ );
                 instance.dwFlags = 0;
-                ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+                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 ) );
+                FIXME( "Ignoring input value %s, usage not implemented.\n", debugstr_hid_value_caps( caps ) );
                 break;
             }
         }
@@ -347,69 +282,53 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header,
         value_ofs += sizeof(LONG);
     }
 
-    for (i = 0; i < impl->caps.NumberInputButtonCaps; ++i)
+    for (caps = HID_INPUT_VALUE_CAPS( preparsed ), caps_end = caps + preparsed->input_caps_count;
+         caps != caps_end; ++caps)
     {
-        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->usage_page) continue;
+        if (!(caps->flags & HID_VALUE_CAPS_IS_BUTTON)) continue;
+
+        if (caps->usage_page >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN)
+            TRACE( "Ignoring input button %s, vendor specific.\n", debugstr_hid_value_caps( caps ) );
+        else if (caps->usage_page != HID_USAGE_PAGE_BUTTON)
+            TRACE( "Ignoring input button %s, usage page not implemented.\n", debugstr_hid_value_caps( caps ) );
+        else
         {
-            for (j = caps.button->Range.UsageMin; j <= caps.button->Range.UsageMax; ++j)
+            for (j = caps->usage_min; j <= caps->usage_max; ++j)
             {
-                instance.dwOfs = button_ofs + (j - caps.button->Range.UsageMin);
+                instance.dwOfs = button_ofs + (j - caps->usage_min);
                 instance.dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( button++ );
                 instance.dwFlags = 0;
-                instance.wUsagePage = caps.button->UsagePage;
+                instance.wUsagePage = caps->usage_page;
                 instance.wUsage = j;
                 instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage );
-                instance.wReportId = caps.button->ReportID;
-                instance.wCollectionNumber = caps.button->LinkCollection;
-                ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+                instance.wReportId = caps->report_id;
+                instance.wCollectionNumber = caps->link_collection;
+                ret = enum_object( impl, &filter, flags, callback, caps, &instance, data );
                 if (ret != DIENUM_CONTINUE) return ret;
             }
         }
-        else
-        {
-            instance.dwOfs = button_ofs;
-            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;
-            instance.wCollectionNumber = caps.button->LinkCollection;
-            ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
-            if (ret != DIENUM_CONTINUE) return ret;
-        }
 
-        if (caps.button->IsRange) button_ofs += caps.button->Range.UsageMax - caps.button->Range.UsageMin;
-        button_ofs++;
+        button_ofs += caps->usage_max - caps->usage_min + 1;
     }
 
-    for (i = 0; i < impl->caps.NumberLinkCollectionNodes; ++i)
+    for (node = HID_COLLECTION_NODES( preparsed ), node_end = node + preparsed->number_link_collection_nodes;
+         node != node_end; ++node)
     {
-        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 ) );
+        if (!node->usage_page) continue;
+        if (node->usage_page >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN)
+            TRACE( "Ignoring collection %s, vendor specific.\n", debugstr_hid_collection_node( node ) );
         else
         {
             instance.dwOfs = 0;
             instance.dwType = DIDFT_COLLECTION | DIDFT_MAKEINSTANCE( collection++ ) | DIDFT_NODATA;
             instance.dwFlags = 0;
-            instance.wUsagePage = caps.node->LinkUsagePage;
-            instance.wUsage = caps.node->LinkUsage;
+            instance.wUsagePage = node->usage_page;
+            instance.wUsage = node->usage;
             instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage );
             instance.wReportId = 0;
-            instance.wCollectionNumber = caps.node->Parent;
-            ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data );
+            instance.wCollectionNumber = node->parent;
+            ret = enum_object( impl, &filter, flags, callback, NULL, &instance, data );
             if (ret != DIENUM_CONTINUE) return ret;
         }
     }
@@ -428,9 +347,6 @@ static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface )
         HeapFree( GetProcessHeap(), 0, tmp.usages_buf );
         HeapFree( GetProcessHeap(), 0, tmp.input_report_buf );
         HeapFree( GetProcessHeap(), 0, tmp.input_extra_caps );
-        HeapFree( GetProcessHeap(), 0, tmp.input_value_caps );
-        HeapFree( GetProcessHeap(), 0, tmp.input_button_caps );
-        HeapFree( GetProcessHeap(), 0, tmp.collection_nodes );
         HidD_FreePreparsedData( tmp.preparsed );
         CancelIoEx( tmp.device, &tmp.read_ovl );
         CloseHandle( tmp.base.read_event );
@@ -459,7 +375,7 @@ struct enum_objects_params
     void *context;
 };
 
-static BOOL enum_objects_callback( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL enum_objects_callback( struct hid_joystick *impl, struct hid_value_caps *caps,
                                    DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
     struct enum_objects_params *params = data;
@@ -513,37 +429,38 @@ static HRESULT WINAPI hid_joystick_EnumObjects( IDirectInputDevice8W *iface, LPD
     return DI_OK;
 }
 
-static BOOL get_property_prop_range( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL get_property_prop_range( struct hid_joystick *impl, struct hid_value_caps *caps,
                                      DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
-    HIDP_VALUE_CAPS *value_caps = caps->value;
     DIPROPRANGE *value = data;
-    value->lMin = value_caps->PhysicalMin;
-    value->lMax = value_caps->PhysicalMax;
+    value->lMin = caps->physical_min;
+    value->lMax = caps->physical_max;
     return DIENUM_STOP;
 }
 
-static BOOL get_property_prop_deadzone( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL get_property_prop_deadzone( struct hid_joystick *impl, struct hid_value_caps *caps,
                                         DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
+    struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed;
     struct extra_caps *extra;
     DIPROPDWORD *deadzone = data;
-    extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+    extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed ));
     deadzone->dwData = extra->deadzone;
     return DIENUM_STOP;
 }
 
-static BOOL get_property_prop_saturation( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL get_property_prop_saturation( struct hid_joystick *impl, struct hid_value_caps *caps,
                                           DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
+    struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed;
     struct extra_caps *extra;
     DIPROPDWORD *saturation = data;
-    extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+    extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed ));
     saturation->dwData = extra->saturation;
     return DIENUM_STOP;
 }
 
-static BOOL get_property_prop_granularity( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL get_property_prop_granularity( struct hid_joystick *impl, struct hid_value_caps *caps,
                                            DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
     DIPROPDWORD *granularity = data;
@@ -634,47 +551,48 @@ static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, con
     return DI_OK;
 }
 
-static BOOL set_property_prop_range( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL set_property_prop_range( struct hid_joystick *impl, struct hid_value_caps *caps,
                                      DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
-    HIDP_VALUE_CAPS *value_caps = caps->value;
     DIPROPRANGE *value = data;
     LONG tmp;
 
-    value_caps->PhysicalMin = value->lMin;
-    value_caps->PhysicalMax = value->lMax;
+    caps->physical_min = value->lMin;
+    caps->physical_max = value->lMax;
 
     if (instance->dwType & DIDFT_AXIS)
     {
-        if (!value_caps->PhysicalMin) tmp = value_caps->PhysicalMax / 2;
-        else tmp = round( (value_caps->PhysicalMin + value_caps->PhysicalMax) / 2.0 );
+        if (!caps->physical_min) tmp = caps->physical_max / 2;
+        else tmp = round( (caps->physical_min + caps->physical_max) / 2.0 );
         *(LONG *)(impl->device_state + instance->dwOfs) = tmp;
     }
     else if (instance->dwType & DIDFT_POV)
     {
-        tmp = value_caps->LogicalMax - value_caps->LogicalMin;
-        if (tmp > 0) value_caps->PhysicalMax -= value->lMax / (tmp + 1);
+        tmp = caps->logical_max - caps->logical_min;
+        if (tmp > 0) caps->physical_max -= value->lMax / (tmp + 1);
         *(LONG *)(impl->device_state + instance->dwOfs) = -1;
     }
     return DIENUM_CONTINUE;
 }
 
-static BOOL set_property_prop_deadzone( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL set_property_prop_deadzone( struct hid_joystick *impl, struct hid_value_caps *caps,
                                         DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
+    struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed;
     struct extra_caps *extra;
     DIPROPDWORD *deadzone = data;
-    extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+    extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed ));
     extra->deadzone = deadzone->dwData;
     return DIENUM_CONTINUE;
 }
 
-static BOOL set_property_prop_saturation( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL set_property_prop_saturation( struct hid_joystick *impl, struct hid_value_caps *caps,
                                           DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
+    struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed;
     struct extra_caps *extra;
     DIPROPDWORD *saturation = data;
-    extra = impl->input_extra_caps + (caps->value - impl->input_value_caps);
+    extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed ));
     extra->saturation = saturation->dwData;
     return DIENUM_CONTINUE;
 }
@@ -797,7 +715,7 @@ static HRESULT WINAPI hid_joystick_GetDeviceState( IDirectInputDevice8W *iface,
     return hr;
 }
 
-static BOOL get_object_info( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL get_object_info( struct hid_joystick *impl, struct hid_value_caps *caps,
                              DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
     DIDEVICEOBJECTINSTANCEW *dest = data;
@@ -930,7 +848,7 @@ struct parse_device_state_params
     DWORD seq;
 };
 
-static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_value_caps *caps,
                                        DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
     IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface;
@@ -948,29 +866,29 @@ static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_cap
     return DIENUM_CONTINUE;
 }
 
-static LONG sign_extend( ULONG value, const HIDP_VALUE_CAPS *caps )
+static LONG sign_extend( ULONG value, struct hid_value_caps *caps )
 {
-    UINT sign = 1 << (caps->BitSize - 1);
-    if (sign <= 1 || caps->LogicalMin >= 0) return value;
+    UINT sign = 1 << (caps->bit_size - 1);
+    if (sign <= 1 || caps->logical_min >= 0) return value;
     return value - ((value & sign) << 1);
 }
 
-static LONG scale_value( ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LONG max )
+static LONG scale_value( ULONG value, struct hid_value_caps *caps, LONG min, LONG max )
 {
     LONG tmp = sign_extend( value, caps );
-    if (caps->LogicalMin > tmp || caps->LogicalMax < tmp) return -1; /* invalid / null value */
-    return min + MulDiv( tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin );
+    if (caps->logical_min > tmp || caps->logical_max < tmp) return -1; /* invalid / null value */
+    return min + MulDiv( tmp - caps->logical_min, max - min, caps->logical_max - caps->logical_min );
 }
 
-static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps, struct extra_caps *extra )
+static LONG scale_axis_value( ULONG value, struct hid_value_caps *caps, struct extra_caps *extra )
 {
     LONG tmp = sign_extend( value, caps ), log_ctr, log_min, log_max, phy_ctr, phy_min, phy_max;
-    ULONG bit_max = (1 << caps->BitSize) - 1;
+    ULONG bit_max = (1 << caps->bit_size) - 1;
 
-    log_min = caps->LogicalMin;
-    log_max = caps->LogicalMax;
-    phy_min = caps->PhysicalMin;
-    phy_max = caps->PhysicalMax;
+    log_min = caps->logical_min;
+    log_max = caps->logical_max;
+    phy_min = caps->physical_min;
+    phy_max = caps->physical_max;
     /* xinput HID gamepad have bogus logical value range, let's use the bit range instead */
     if (log_min == 0 && log_max == -1) log_max = bit_max;
 
@@ -998,27 +916,27 @@ static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps, struct e
     return phy_min + MulDiv( tmp - log_min, phy_max - phy_min, log_max - log_min );
 }
 
-static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_value_caps *caps,
                                      DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
+    struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed;
     IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface;
     ULONG logical_value, report_len = impl->caps.InputReportByteLength;
     struct parse_device_state_params *params = data;
     char *report_buf = impl->input_report_buf;
-    HIDP_VALUE_CAPS *value_caps = caps->value;
     struct extra_caps *extra;
     LONG old_value, value;
     NTSTATUS status;
 
     if (instance->wReportId != impl->device_state_report_id) return DIENUM_CONTINUE;
 
-    extra = impl->input_extra_caps + (value_caps - impl->input_value_caps);
+    extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed ));
     status = HidP_GetUsageValue( HidP_Input, instance->wUsagePage, 0, instance->wUsage,
                                  &logical_value, impl->preparsed, report_buf, report_len );
     if (status != HIDP_STATUS_SUCCESS) WARN( "HidP_GetUsageValue %04x:%04x returned %#x\n",
                                              instance->wUsagePage, instance->wUsage, status );
-    if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, value_caps, extra );
-    else value = scale_value( logical_value, value_caps, value_caps->PhysicalMin, value_caps->PhysicalMax );
+    if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, caps, extra );
+    else value = scale_value( logical_value, caps, caps->physical_min, caps->physical_max );
 
     old_value = *(LONG *)(params->old_state + instance->dwOfs);
     *(LONG *)(impl->device_state + instance->dwOfs) = value;
@@ -1353,7 +1271,7 @@ 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,
+static BOOL init_objects( struct hid_joystick *impl, struct hid_value_caps *caps,
                           DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
     DIDATAFORMAT *format = impl->base.data_format.wine_df;
@@ -1377,7 +1295,7 @@ static BOOL init_objects( struct hid_joystick *impl, struct hid_caps *caps,
     return DIENUM_CONTINUE;
 }
 
-static BOOL init_data_format( struct hid_joystick *impl, struct hid_caps *caps,
+static BOOL init_data_format( struct hid_joystick *impl, struct hid_value_caps *caps,
                               DIDEVICEOBJECTINSTANCEW *instance, void *data )
 {
     DIDATAFORMAT *format = impl->base.data_format.wine_df;
@@ -1427,15 +1345,12 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
         },
     };
     HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)};
-    HIDP_LINK_COLLECTION_NODE *nodes;
+    struct hid_preparsed_data *preparsed;
     struct hid_joystick *impl = NULL;
     struct extra_caps *extra;
     DIDATAFORMAT *format = NULL;
-    HIDP_BUTTON_CAPS *buttons;
-    HIDP_VALUE_CAPS *values;
     USAGE_AND_PAGE *usages;
     DWORD size, index;
-    NTSTATUS status;
     char *buffer;
     HRESULT hr;
 
@@ -1469,16 +1384,9 @@ 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.NumberInputValueCaps * sizeof(struct extra_caps);
+    preparsed = (struct hid_preparsed_data *)impl->preparsed;
+
+    size = preparsed->input_caps_count * sizeof(struct extra_caps);
     if (!(extra = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto failed;
     impl->input_extra_caps = extra;
 
@@ -1490,17 +1398,6 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
     if (!(usages = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
     impl->usages_buf = usages;
 
-    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;
-
     enum_objects( impl, &filter, DIDFT_ALL, init_objects, NULL );
 
     format = impl->base.data_format.wine_df;
-- 
2.33.0




More information about the wine-devel mailing list