[PATCH 5/5] dinput/tests: Add a test for multiple top-level collections.

Rémi Bernon wine at gitlab.winehq.org
Thu Jun 2 02:39:14 CDT 2022


From: Rémi Bernon <rbernon at codeweavers.com>

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/tests/hid.c | 384 ++++++++++++++++++++++++++++++----------
 1 file changed, 292 insertions(+), 92 deletions(-)

diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c
index 81bf8ed46f8..2d7199fa3e5 100644
--- a/dlls/dinput/tests/hid.c
+++ b/dlls/dinput/tests/hid.c
@@ -3021,6 +3021,106 @@ struct hidp_kdr
     /* struct hidp_kdr_node nodes[1] */
 };
 
+static void check_preparsed_data( HANDLE file, const struct hidp_kdr *expect_kdr,
+                                  UINT expect_caps_count, const struct hidp_kdr_caps *expect_caps,
+                                  UINT expect_nodes_count, const struct hidp_kdr_node *expect_nodes )
+{
+    PHIDP_PREPARSED_DATA preparsed_data;
+    struct hidp_kdr *kdr;
+    BOOL ret;
+    UINT i;
+
+    ret = HidD_GetPreparsedData( file, &preparsed_data );
+    ok( ret, "HidD_GetPreparsedData failed with error %lu\n", GetLastError() );
+
+    kdr = (struct hidp_kdr *)preparsed_data;
+    ok( !strncmp( kdr->magic, expect_kdr->magic, 8 ), "got %s expected %s\n",
+        debugstr_an(kdr->magic, 8), debugstr_an(expect_kdr->magic, 8) );
+
+    if (!strncmp( kdr->magic, expect_kdr->magic, 8 ))
+    {
+        check_member( *kdr, *expect_kdr, "%04x", usage );
+        check_member( *kdr, *expect_kdr, "%04x", usage_page );
+        check_member( *kdr, *expect_kdr, "%#x", unknown[0] );
+        check_member( *kdr, *expect_kdr, "%#x", unknown[1] );
+        check_member( *kdr, *expect_kdr, "%d", input_caps_start );
+        check_member( *kdr, *expect_kdr, "%d", input_caps_count );
+        check_member( *kdr, *expect_kdr, "%d", input_caps_end );
+        check_member( *kdr, *expect_kdr, "%d", input_report_byte_length );
+        check_member( *kdr, *expect_kdr, "%d", output_caps_start );
+        check_member( *kdr, *expect_kdr, "%d", output_caps_count );
+        check_member( *kdr, *expect_kdr, "%d", output_caps_end );
+        check_member( *kdr, *expect_kdr, "%d", output_report_byte_length );
+        check_member( *kdr, *expect_kdr, "%d", feature_caps_start );
+        todo_wine
+        check_member( *kdr, *expect_kdr, "%d", feature_caps_count );
+        check_member( *kdr, *expect_kdr, "%d", feature_caps_end );
+        check_member( *kdr, *expect_kdr, "%d", feature_report_byte_length );
+        todo_wine
+        check_member( *kdr, *expect_kdr, "%d", caps_size );
+        check_member( *kdr, *expect_kdr, "%d", number_link_collection_nodes );
+
+        for (i = 0; i < min( expect_caps_count, kdr->caps_size / sizeof(struct hidp_kdr_caps) ); ++i)
+        {
+            winetest_push_context( "caps[%u]", i );
+            check_member( kdr->caps[i], expect_caps[i], "%04x", usage_page );
+            check_member( kdr->caps[i], expect_caps[i], "%d", report_id );
+            check_member( kdr->caps[i], expect_caps[i], "%d", start_bit );
+            check_member( kdr->caps[i], expect_caps[i], "%d", bit_size );
+            check_member( kdr->caps[i], expect_caps[i], "%d", report_count );
+            check_member( kdr->caps[i], expect_caps[i], "%d", start_byte );
+            check_member( kdr->caps[i], expect_caps[i], "%d", total_bits );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", bit_field );
+            check_member( kdr->caps[i], expect_caps[i], "%d", end_byte );
+            check_member( kdr->caps[i], expect_caps[i], "%d", link_collection );
+            check_member( kdr->caps[i], expect_caps[i], "%04x", link_usage_page );
+            check_member( kdr->caps[i], expect_caps[i], "%04x", link_usage );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", flags );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[0] );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[1] );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[2] );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[3] );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[4] );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[5] );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[6] );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[7] );
+            check_member( kdr->caps[i], expect_caps[i], "%04x", usage_min );
+            check_member( kdr->caps[i], expect_caps[i], "%04x", usage_max );
+            check_member( kdr->caps[i], expect_caps[i], "%d", string_min );
+            check_member( kdr->caps[i], expect_caps[i], "%d", string_max );
+            check_member( kdr->caps[i], expect_caps[i], "%d", designator_min );
+            check_member( kdr->caps[i], expect_caps[i], "%d", designator_max );
+            check_member( kdr->caps[i], expect_caps[i], "%#x", data_index_min );
+            check_member( kdr->caps[i], expect_caps[i], "%#x", data_index_max );
+            check_member( kdr->caps[i], expect_caps[i], "%d", null_value );
+            check_member( kdr->caps[i], expect_caps[i], "%d", unknown );
+            check_member( kdr->caps[i], expect_caps[i], "%ld", logical_min );
+            check_member( kdr->caps[i], expect_caps[i], "%ld", logical_max );
+            check_member( kdr->caps[i], expect_caps[i], "%ld", physical_min );
+            check_member( kdr->caps[i], expect_caps[i], "%ld", physical_max );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", units );
+            check_member( kdr->caps[i], expect_caps[i], "%#lx", units_exp );
+            winetest_pop_context();
+        }
+
+        for (i = 0; i < expect_nodes_count; ++i)
+        {
+            struct hidp_kdr_node *nodes = (struct hidp_kdr_node *)((char *)kdr->caps + kdr->caps_size);
+            winetest_push_context( "nodes[%u]", i );
+            check_member( nodes[i], expect_nodes[i], "%04x", usage );
+            check_member( nodes[i], expect_nodes[i], "%04x", usage_page );
+            check_member( nodes[i], expect_nodes[i], "%d", parent );
+            check_member( nodes[i], expect_nodes[i], "%d", number_of_children );
+            check_member( nodes[i], expect_nodes[i], "%d", next_sibling );
+            check_member( nodes[i], expect_nodes[i], "%d", first_child );
+            check_member( nodes[i], expect_nodes[i], "%#lx", collection_type );
+            winetest_pop_context();
+        }
+    }
+
+    HidD_FreePreparsedData( preparsed_data );
+}
+
 static void test_hidp_kdr(void)
 {
 #include "psh_hid_macros.h"
@@ -3240,12 +3340,9 @@ static void test_hidp_kdr(void)
         },
     };
 
-    PHIDP_PREPARSED_DATA preparsed_data;
     WCHAR device_path[MAX_PATH];
-    struct hidp_kdr *kdr;
     HANDLE file;
     BOOL ret;
-    DWORD i;
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
@@ -3262,95 +3359,8 @@ static void test_hidp_kdr(void)
                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
     ok( file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() );
 
-    ret = HidD_GetPreparsedData( file, &preparsed_data );
-    ok( ret, "HidD_GetPreparsedData failed with error %lu\n", GetLastError() );
-
-    kdr = (struct hidp_kdr *)preparsed_data;
-    ok( !strncmp( kdr->magic, expect_kdr.magic, 8 ), "got %s expected %s\n",
-        debugstr_an(kdr->magic, 8), debugstr_an(expect_kdr.magic, 8) );
-
-    if (!strncmp( kdr->magic, expect_kdr.magic, 8 ))
-    {
-        check_member( *kdr, expect_kdr, "%04x", usage );
-        check_member( *kdr, expect_kdr, "%04x", usage_page );
-        check_member( *kdr, expect_kdr, "%#x", unknown[0] );
-        check_member( *kdr, expect_kdr, "%#x", unknown[1] );
-        check_member( *kdr, expect_kdr, "%d", input_caps_start );
-        check_member( *kdr, expect_kdr, "%d", input_caps_count );
-        check_member( *kdr, expect_kdr, "%d", input_caps_end );
-        check_member( *kdr, expect_kdr, "%d", input_report_byte_length );
-        check_member( *kdr, expect_kdr, "%d", output_caps_start );
-        check_member( *kdr, expect_kdr, "%d", output_caps_count );
-        check_member( *kdr, expect_kdr, "%d", output_caps_end );
-        check_member( *kdr, expect_kdr, "%d", output_report_byte_length );
-        check_member( *kdr, expect_kdr, "%d", feature_caps_start );
-        todo_wine
-        check_member( *kdr, expect_kdr, "%d", feature_caps_count );
-        check_member( *kdr, expect_kdr, "%d", feature_caps_end );
-        check_member( *kdr, expect_kdr, "%d", feature_report_byte_length );
-        todo_wine
-        check_member( *kdr, expect_kdr, "%d", caps_size );
-        check_member( *kdr, expect_kdr, "%d", number_link_collection_nodes );
-
-        for (i = 0; i < min( ARRAY_SIZE(expect_caps), kdr->caps_size / sizeof(struct hidp_kdr_caps) ); ++i)
-        {
-            winetest_push_context( "caps[%ld]", i );
-            check_member( kdr->caps[i], expect_caps[i], "%04x", usage_page );
-            check_member( kdr->caps[i], expect_caps[i], "%d", report_id );
-            check_member( kdr->caps[i], expect_caps[i], "%d", start_bit );
-            check_member( kdr->caps[i], expect_caps[i], "%d", bit_size );
-            check_member( kdr->caps[i], expect_caps[i], "%d", report_count );
-            check_member( kdr->caps[i], expect_caps[i], "%d", start_byte );
-            check_member( kdr->caps[i], expect_caps[i], "%d", total_bits );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", bit_field );
-            check_member( kdr->caps[i], expect_caps[i], "%d", end_byte );
-            check_member( kdr->caps[i], expect_caps[i], "%d", link_collection );
-            check_member( kdr->caps[i], expect_caps[i], "%04x", link_usage_page );
-            check_member( kdr->caps[i], expect_caps[i], "%04x", link_usage );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", flags );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[0] );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[1] );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[2] );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[3] );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[4] );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[5] );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[6] );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", padding[7] );
-            check_member( kdr->caps[i], expect_caps[i], "%04x", usage_min );
-            check_member( kdr->caps[i], expect_caps[i], "%04x", usage_max );
-            check_member( kdr->caps[i], expect_caps[i], "%d", string_min );
-            check_member( kdr->caps[i], expect_caps[i], "%d", string_max );
-            check_member( kdr->caps[i], expect_caps[i], "%d", designator_min );
-            check_member( kdr->caps[i], expect_caps[i], "%d", designator_max );
-            check_member( kdr->caps[i], expect_caps[i], "%#x", data_index_min );
-            check_member( kdr->caps[i], expect_caps[i], "%#x", data_index_max );
-            check_member( kdr->caps[i], expect_caps[i], "%d", null_value );
-            check_member( kdr->caps[i], expect_caps[i], "%d", unknown );
-            check_member( kdr->caps[i], expect_caps[i], "%ld", logical_min );
-            check_member( kdr->caps[i], expect_caps[i], "%ld", logical_max );
-            check_member( kdr->caps[i], expect_caps[i], "%ld", physical_min );
-            check_member( kdr->caps[i], expect_caps[i], "%ld", physical_max );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", units );
-            check_member( kdr->caps[i], expect_caps[i], "%#lx", units_exp );
-            winetest_pop_context();
-        }
-
-        for (i = 0; i < ARRAY_SIZE(expect_nodes); ++i)
-        {
-            struct hidp_kdr_node *nodes = (struct hidp_kdr_node *)((char *)kdr->caps + kdr->caps_size);
-            winetest_push_context( "nodes[%ld]", i );
-            check_member( nodes[i], expect_nodes[i], "%04x", usage );
-            check_member( nodes[i], expect_nodes[i], "%04x", usage_page );
-            check_member( nodes[i], expect_nodes[i], "%d", parent );
-            check_member( nodes[i], expect_nodes[i], "%d", number_of_children );
-            check_member( nodes[i], expect_nodes[i], "%d", next_sibling );
-            check_member( nodes[i], expect_nodes[i], "%d", first_child );
-            check_member( nodes[i], expect_nodes[i], "%#lx", collection_type );
-            winetest_pop_context();
-        }
-    }
-
-    HidD_FreePreparsedData( preparsed_data );
+    check_preparsed_data( file, &expect_kdr, ARRAY_SIZE(expect_caps), expect_caps,
+                          ARRAY_SIZE(expect_nodes), expect_nodes );
 
     CloseHandle( file );
 
@@ -3730,6 +3740,195 @@ done:
     bus_device_stop();
 }
 
+static void test_hid_multiple_tlc(void)
+{
+#include "psh_hid_macros.h"
+    const unsigned char report_desc[] =
+    {
+        USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC),
+        USAGE(1, HID_USAGE_GENERIC_JOYSTICK),
+        COLLECTION(1, Application),
+            USAGE(1, HID_USAGE_GENERIC_JOYSTICK),
+            COLLECTION(1, Physical),
+                REPORT_ID(1, 1),
+
+                USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON),
+                USAGE_MINIMUM(1, 1),
+                USAGE_MAXIMUM(1, 2),
+                LOGICAL_MINIMUM(1, 0),
+                LOGICAL_MAXIMUM(1, 1),
+                REPORT_SIZE(1, 1),
+                REPORT_COUNT(1, 8),
+                INPUT(1, Data|Var|Abs),
+
+                USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC),
+                USAGE(1, HID_USAGE_GENERIC_X),
+                USAGE(1, HID_USAGE_GENERIC_Y),
+                REPORT_SIZE(1, 16),
+                REPORT_COUNT(1, 2),
+                LOGICAL_MINIMUM(2, -10),
+                LOGICAL_MAXIMUM(2, +10),
+                INPUT(1, Data|Var|Rel),
+            END_COLLECTION,
+        END_COLLECTION,
+
+        USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC),
+        USAGE(1, HID_USAGE_GENERIC_GAMEPAD),
+        COLLECTION(1, Application),
+            USAGE(1, HID_USAGE_GENERIC_GAMEPAD),
+            COLLECTION(1, Physical),
+                REPORT_ID(1, 2),
+
+                USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON),
+                USAGE_MINIMUM(1, 1),
+                USAGE_MAXIMUM(1, 40),
+                LOGICAL_MINIMUM(1, 0),
+                LOGICAL_MAXIMUM(1, 1),
+                REPORT_SIZE(1, 1),
+                REPORT_COUNT(1, 40),
+                INPUT(1, Data|Var|Abs),
+            END_COLLECTION,
+        END_COLLECTION,
+    };
+    C_ASSERT(sizeof(report_desc) < MAX_HID_DESCRIPTOR_LEN);
+#include "pop_hid_macros.h"
+
+    struct hid_device_desc desc =
+    {
+        .caps = { .InputReportByteLength = 7 },
+        .attributes = default_attributes,
+    };
+
+    static const struct hidp_kdr expect_kdr_joystick =
+    {
+        .magic = "HidP KDR",
+        .usage = 0x04,
+        .usage_page = 0x01,
+        .input_caps_count = 3,
+        .input_caps_end = 3,
+        .input_report_byte_length = 6,
+        .output_caps_start = 3,
+        .output_caps_end = 3,
+        .feature_caps_start = 3,
+        .feature_caps_end = 3,
+        .caps_size = 312,
+        .number_link_collection_nodes = 2,
+    };
+    static const struct hidp_kdr expect_kdr_gamepad =
+    {
+        .magic = "HidP KDR",
+        .usage = 0x05,
+        .usage_page = 0x01,
+        .input_caps_count = 1,
+        .input_caps_end = 1,
+        .input_report_byte_length = 6,
+        .output_caps_start = 1,
+        .output_caps_end = 1,
+        .feature_caps_start = 1,
+        .feature_caps_end = 1,
+        .caps_size = 104,
+        .number_link_collection_nodes = 2,
+    };
+    static const struct hidp_kdr_caps expect_caps_joystick[] =
+    {
+        {
+            .usage_page = 9, .report_id = 1, .bit_size = 1, .report_count = 8, .start_byte = 1, .total_bits = 8,
+            .bit_field = 2, .end_byte = 2, .link_collection = 1, .link_usage_page = 0x01, .link_usage = 0x04, .flags = 0x1c,
+            .usage_min = 1, .usage_max = 2, .data_index_max = 1,
+        },
+        {
+            .usage_page = 1, .report_id = 1, .bit_size = 16, .report_count = 1, .start_byte = 4, .total_bits = 16,
+            .bit_field = 6, .end_byte = 6, .link_collection = 1, .link_usage_page = 0x01, .link_usage = 0x04,
+            .usage_min = 0x31, .usage_max = 0x31, .data_index_min = 2, .data_index_max = 2, .logical_min = -10, .logical_max = +10,
+        },
+        {
+            .usage_page = 1, .report_id = 1, .bit_size = 16, .report_count = 1, .start_byte = 2, .total_bits = 16,
+            .bit_field = 6, .end_byte = 4, .link_collection = 1, .link_usage_page = 0x01, .link_usage = 0x04,
+            .usage_min = 0x30, .usage_max = 0x30, .data_index_min = 3, .data_index_max = 3, .logical_min = -10, .logical_max = +10,
+        },
+    };
+    static const struct hidp_kdr_caps expect_caps_gamepad[] =
+    {
+        {
+            .usage_page = 9, .report_id = 2, .bit_size = 1, .report_count = 40, .start_byte = 1, .total_bits = 40,
+            .bit_field = 2, .end_byte = 6, .link_collection = 1, .link_usage_page = 0x01, .link_usage = 0x05, .flags = 0x1c,
+            .usage_min = 0x01, .usage_max = 0x28, .data_index_max = 0x27,
+        },
+    };
+    static const struct hidp_kdr_node expect_nodes_joystick[] =
+    {
+        {
+            .usage = 0x04,
+            .usage_page = 0x01,
+            .number_of_children = 1,
+            .first_child = 1,
+            .collection_type = 0x1,
+        },
+        {
+            .usage = 0x04,
+            .usage_page = 0x01,
+        },
+    };
+    static const struct hidp_kdr_node expect_nodes_gamepad[] =
+    {
+        {
+            .usage = 0x05,
+            .usage_page = 0x01,
+            .number_of_children = 1,
+            .first_child = 1,
+            .collection_type = 1,
+        },
+        {
+            .usage = 0x05,
+            .usage_page = 0x01,
+        },
+    };
+
+    WCHAR device_path[MAX_PATH];
+    HANDLE file;
+    BOOL ret;
+
+    desc.report_descriptor_len = sizeof(report_desc);
+    memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
+    fill_context( desc.context, ARRAY_SIZE(desc.context) );
+
+    if (!hid_device_start( &desc )) goto done;
+
+    swprintf( device_path, MAX_PATH, L"\\\\?\\hid#vid_%04x&pid_%04x&col01", desc.attributes.VendorID,
+              desc.attributes.ProductID );
+    ret = find_hid_device_path( device_path );
+    todo_wine
+    ok( ret, "Failed to find HID device matching %s\n", debugstr_w( device_path ) );
+    if (!ret) goto done;
+
+    file = CreateFileW( device_path, FILE_READ_ACCESS | FILE_WRITE_ACCESS,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
+    ok( file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() );
+    check_preparsed_data( file, &expect_kdr_joystick, ARRAY_SIZE(expect_caps_joystick), expect_caps_joystick,
+                          ARRAY_SIZE(expect_nodes_joystick), expect_nodes_joystick );
+    CloseHandle( file );
+
+    swprintf( device_path, MAX_PATH, L"\\\\?\\hid#vid_%04x&pid_%04x&col02", desc.attributes.VendorID,
+              desc.attributes.ProductID );
+    ret = find_hid_device_path( device_path );
+    ok( ret, "Failed to find HID device matching %s\n", debugstr_w( device_path ) );
+
+    file = CreateFileW( device_path, FILE_READ_ACCESS | FILE_WRITE_ACCESS,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
+    ok( file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() );
+    check_preparsed_data( file, &expect_kdr_gamepad, ARRAY_SIZE(expect_caps_gamepad), expect_caps_gamepad,
+                          ARRAY_SIZE(expect_nodes_gamepad), expect_nodes_gamepad );
+    CloseHandle( file );
+
+    swprintf( device_path, MAX_PATH, L"\\\\?\\hid#vid_%04x&pid_%04x&col03", desc.attributes.VendorID,
+              desc.attributes.ProductID );
+    ret = find_hid_device_path( device_path );
+    ok( !ret, "Failed to find HID device matching %s\n", debugstr_w( device_path ) );
+
+done:
+    hid_device_stop( &desc );
+}
+
 START_TEST( hid )
 {
     if (!dinput_test_init()) return;
@@ -3742,6 +3941,7 @@ START_TEST( hid )
     test_hid_driver( 1, FALSE );
     test_hid_driver( 0, TRUE );
     test_hid_driver( 1, TRUE );
+    test_hid_multiple_tlc();
 
 done:
     bus_device_stop();
-- 
GitLab

https://gitlab.winehq.org/wine/wine/-/merge_requests/171



More information about the wine-devel mailing list