From: "Rémi Bernon" Subject: [PATCH 5/6] hidclass.sys: Support parsing of explicit usage page. Message-Id: <20210618073940.3507834-5-rbernon@codeweavers.com> Date: Fri, 18 Jun 2021 09:39:39 +0200 In-Reply-To: <20210618073940.3507834-1-rbernon@codeweavers.com> References: <20210618073940.3507834-1-rbernon@codeweavers.com> Signed-off-by: Rémi Bernon --- dlls/hidclass.sys/descriptor.c | 50 ++++++++++++++++++++++++------ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 2 +- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index 930dcd52715..26edb102034 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -272,7 +272,9 @@ struct hid_parser_state { HIDP_CAPS caps; - USAGE usages[256]; + USAGE usages_page[256]; + USAGE usages_min[256]; + USAGE usages_max[256]; DWORD usages_size; struct hid_value_caps items; @@ -352,14 +354,42 @@ static BOOL parse_global_pop( struct hid_parser_state *state ) return TRUE; } -static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage ) +static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage_page, USAGE usage ) { - state->usages[state->usages_size] = usage; + if (!usage_page) usage_page = state->items.usage_page; + if (state->items.is_range) state->usages_size = 0; + state->usages_page[state->usages_size] = usage_page; + state->usages_min[state->usages_size] = usage; + state->usages_max[state->usages_size] = usage; + state->items.usage_min = usage; + state->items.usage_max = usage; state->items.is_range = FALSE; if (state->usages_size++ == 255) ERR( "HID parser usages stack overflow!\n" ); return state->usages_size <= 255; } +static void parse_local_usage_min( struct hid_parser_state *state, USAGE usage_page, USAGE usage ) +{ + if (!usage_page) usage_page = state->items.usage_page; + if (!state->items.is_range) state->usages_max[0] = 0; + state->usages_page[0] = usage_page; + state->usages_min[0] = usage; + state->items.usage_min = usage; + state->items.is_range = TRUE; + state->usages_size = 1; +} + +static void parse_local_usage_max( struct hid_parser_state *state, USAGE usage_page, USAGE usage ) +{ + if (!usage_page) usage_page = state->items.usage_page; + if (!state->items.is_range) state->usages_min[0] = 0; + state->usages_page[0] = usage_page; + state->usages_max[0] = usage; + state->items.usage_max = usage; + state->items.is_range = TRUE; + state->usages_size = 1; +} + static BOOL parse_new_collection( struct hid_parser_state *state ) { if (!array_reserve( &state->stack, &state->stack_size, state->collection_idx )) @@ -377,6 +407,9 @@ static BOOL parse_new_collection( struct hid_parser_state *state ) copy_collection_items( state->stack + state->collection_idx, &state->items ); state->collection_idx++; + state->items.usage_min = state->usages_min[0]; + state->items.usage_max = state->usages_max[0]; + state->collections[state->caps.NumberLinkCollectionNodes] = state->items; state->items.link_collection = state->caps.NumberLinkCollectionNodes; state->items.link_usage_page = state->items.usage_page; @@ -417,8 +450,8 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY list_add_tail( &collection->features, &feature->entry ); feature->type = type; feature->isData = ((state->items.bit_field & INPUT_DATA_CONST) == 0); - if (j < state->usages_size) state->items.usage_min = state->usages[j]; copy_hidp_value_caps( &feature->caps, &state->items ); + if (j < state->usages_size) feature->caps.NotRange.Usage = state->usages_min[j]; feature->caps.ReportCount = 1; if (j + 1 >= state->usages_size) { @@ -508,7 +541,6 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int subcollection->parent = collection; /* Only set our collection once... We do not properly handle composite devices yet. */ - if (state->usages_size) state->items.usage_min = state->usages[state->usages_size - 1]; list_init(&subcollection->features); list_init(&subcollection->collections); parse_collection(size, value, subcollection); @@ -559,15 +591,13 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int break; case SHORT_ITEM(TAG_LOCAL_USAGE, TAG_TYPE_LOCAL): - if (!parse_local_usage( state, value )) return -1; + if (!parse_local_usage( state, value >> 16, value & 0xffff )) return -1; break; case SHORT_ITEM(TAG_LOCAL_USAGE_MINIMUM, TAG_TYPE_LOCAL): - state->items.usage_min = value; - state->items.is_range = TRUE; + parse_local_usage_min( state, value >> 16, value & 0xffff ); break; case SHORT_ITEM(TAG_LOCAL_USAGE_MAXIMUM, TAG_TYPE_LOCAL): - state->items.usage_max = value; - state->items.is_range = TRUE; + parse_local_usage_max( state, value >> 16, value & 0xffff ); break; case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_INDEX, TAG_TYPE_LOCAL): state->items.designator_min = state->items.designator_max = value; diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 19099a5a19c..24782a733ff 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -2026,7 +2026,7 @@ static void test_hidp(HANDLE file, int report_id) check_member(value_caps[i], expect_value_caps[i], "%d", PhysicalMax); todo_wine check_member(value_caps[i], expect_value_caps[i], "%04x", Range.UsageMin); - todo_wine + todo_wine_if(i >= 1) check_member(value_caps[i], expect_value_caps[i], "%04x", Range.UsageMax); check_member(value_caps[i], expect_value_caps[i], "%d", Range.StringMin); check_member(value_caps[i], expect_value_caps[i], "%d", Range.StringMax); -- 2.31.0