diff --git a/dlls/hid/hid.spec b/dlls/hid/hid.spec index b8e29fef16a..98508a456ce 100644 --- a/dlls/hid/hid.spec +++ b/dlls/hid/hid.spec @@ -27,7 +27,7 @@ @ stdcall HidP_GetSpecificButtonCaps(long long long long ptr ptr ptr) @ stdcall HidP_GetSpecificValueCaps(long long long long ptr ptr ptr) @ stdcall HidP_GetUsageValue(long long long long ptr ptr ptr long) -@ stub HidP_GetUsageValueArray +@ stdcall HidP_GetUsageValueArray(long long long long ptr long ptr ptr long) @ stdcall HidP_GetUsages(long long long ptr ptr ptr ptr long) @ stdcall HidP_GetUsagesEx(long long ptr ptr ptr ptr long) @ stdcall HidP_GetValueCaps(long ptr ptr ptr) diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c index 817e021fe4e..c4d162695a9 100644 --- a/dlls/hid/hidp.c +++ b/dlls/hid/hidp.c @@ -117,6 +117,46 @@ static NTSTATUS set_report_data(BYTE *report, INT reportLength, INT startBit, IN return HIDP_STATUS_SUCCESS; } +static NTSTATUS get_report_data_array(BYTE *report, UINT reportLength, UINT startBit, UINT elemSize, + UINT numElements, PCHAR values, UINT valuesSize) +{ + BYTE byte, *end, *p = report + startBit / 8; + ULONG size = elemSize * numElements; + ULONG m, bit_index = startBit % 8; + BYTE *data = (BYTE*)values; + + if ((startBit + size) / 8 > reportLength) + return HIDP_STATUS_INVALID_REPORT_LENGTH; + + if (valuesSize < (size + 7) / 8) + return HIDP_STATUS_BUFFER_TOO_SMALL; + + end = report + (startBit + size + 7) / 8; + + data--; + byte = *p++; + while (p != end) + { + *(++data) = byte >> bit_index; + byte = *p++; + *data |= byte << (8 - bit_index); + } + + /* Handle the end and mask out bits beyond */ + m = (startBit + size) % 8; + m = m ? m : 8; + + if (m > bit_index) + *(++data) = (byte >> bit_index) & ((1 << (m - bit_index)) - 1); + else + *data &= (1 << (m + 8 - bit_index)) - 1; + + if (++data < (BYTE*)values + valuesSize) + memset(data, 0, (BYTE*)values + valuesSize - data); + + return HIDP_STATUS_SUCCESS; +} + NTSTATUS WINAPI HidP_GetButtonCaps(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData) @@ -325,6 +365,31 @@ NTSTATUS WINAPI HidP_GetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, } +NTSTATUS WINAPI HidP_GetUsageValueArray(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, + USAGE Usage, PCHAR UsageValue, USHORT UsageValueByteLength, + PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength) +{ + WINE_HID_ELEMENT element; + NTSTATUS rc; + + TRACE("(%i, %x, %i, %i, %p, %u, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue, + UsageValueByteLength, PreparsedData, Report, ReportLength); + + rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element); + + if (rc == HIDP_STATUS_SUCCESS) + { + if (element.caps.value.IsRange || element.caps.value.ReportCount <= 1 || !element.bitCount) + return HIDP_STATUS_NOT_VALUE_ARRAY; + + return get_report_data_array((BYTE*)Report, ReportLength, element.valueStartBit, element.bitCount, + element.caps.value.ReportCount, UsageValue, UsageValueByteLength); + } + + return rc; +} + + NTSTATUS WINAPI HidP_GetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength) diff --git a/dlls/hid/tests/device.c b/dlls/hid/tests/device.c index 24c307704fe..3dd22b7f068 100644 --- a/dlls/hid/tests/device.c +++ b/dlls/hid/tests/device.c @@ -253,11 +253,38 @@ static void process_data(HIDP_CAPS Caps, PHIDP_PREPARSED_DATA ppd, CHAR *data, D trace("\tValues:\n"); for (i = 0; i < length; i++) { - status = HidP_GetUsageValue(HidP_Input, values[i].UsagePage, 0, - values[i].Range.UsageMin, &value, ppd, data, data_length); - ok(status == HIDP_STATUS_SUCCESS, "Failed to get value [%i,%i] (%x)\n", - values[i].UsagePage, values[i].Range.UsageMin, status); - trace("[%02x, %02x]: %u\n",values[i].UsagePage, values[i].Range.UsageMin, value); + ok(values[i].ReportCount, "Zero ReportCount for [%i,%i]\n", values[i].UsagePage, values[i].NotRange.Usage); + if (values[i].IsRange || values[i].ReportCount <= 1) + { + status = HidP_GetUsageValue(HidP_Input, values[i].UsagePage, 0, + values[i].Range.UsageMin, &value, ppd, data, data_length); + ok(status == HIDP_STATUS_SUCCESS, "Failed to get value [%i,%i] (%x)\n", + values[i].UsagePage, values[i].Range.UsageMin, status); + trace("[%02x, %02x]: %u\n", values[i].UsagePage, values[i].Range.UsageMin, value); + } + else + { + USHORT k, array_size = (values[i].BitSize * values[i].ReportCount + 7) / 8; + PCHAR array = HeapAlloc(GetProcessHeap(), 0, array_size); + char *dump = HeapAlloc(GetProcessHeap(), 0, array_size * 3 + 1); + + status = HidP_GetUsageValueArray(HidP_Input, values[i].UsagePage, 0, + values[i].NotRange.Usage, array, array_size, ppd, data, data_length); + ok(status == HIDP_STATUS_SUCCESS, "Failed to get value array [%i,%i] (%x)\n", + values[i].UsagePage, values[i].NotRange.Usage, status); + dump[0] = 0; + for (k = 0; k < array_size; k++) + { + char bytestr[5]; + sprintf(bytestr, " %02x", (BYTE)array[k]); + strcat(dump, bytestr); + } + trace("[%02x, %02x] element bit size %u num elements %u:%s\n", values[i].UsagePage, + values[i].NotRange.Usage, values[i].BitSize, values[i].ReportCount, dump); + + HeapFree(GetProcessHeap(), 0, dump); + HeapFree(GetProcessHeap(), 0, array); + } } HeapFree(GetProcessHeap(), 0, values); diff --git a/include/ddk/hidpi.h b/include/ddk/hidpi.h index 51d61ea8541..fb497f3282f 100644 --- a/include/ddk/hidpi.h +++ b/include/ddk/hidpi.h @@ -195,6 +195,7 @@ NTSTATUS WINAPI HidP_GetButtonCaps(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAP NTSTATUS WINAPI HidP_GetCaps(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities); NTSTATUS WINAPI HidP_GetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); NTSTATUS WINAPI HidP_GetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE Usage, PULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); +NTSTATUS WINAPI HidP_GetUsageValueArray(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE Usage, PCHAR UsageValue, USHORT UsageValueByteLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); NTSTATUS WINAPI HidP_GetValueCaps(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData); NTSTATUS WINAPI HidP_InitializeReportForID(HIDP_REPORT_TYPE ReportType, UCHAR ReportID, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); ULONG WINAPI HidP_MaxUsageListLength(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, PHIDP_PREPARSED_DATA PreparsedData);