Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
Fixed a leak when HidP_GetButtonCaps / HidP_GetValueCaps failed, split the patches from the other.
dlls/winexinput.sys/main.c | 69 ++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 7 deletions(-)
diff --git a/dlls/winexinput.sys/main.c b/dlls/winexinput.sys/main.c index 60f7a8ed5dd..dfe747d6515 100644 --- a/dlls/winexinput.sys/main.c +++ b/dlls/winexinput.sys/main.c @@ -82,6 +82,14 @@ struct func_device
WCHAR instance_id[MAX_DEVICE_ID_LEN];
+ HIDP_VALUE_CAPS lx_caps; + HIDP_VALUE_CAPS ly_caps; + HIDP_VALUE_CAPS lt_caps; + HIDP_VALUE_CAPS rx_caps; + HIDP_VALUE_CAPS ry_caps; + HIDP_VALUE_CAPS rt_caps; + HIDP_DEVICE_DESC device_desc; + /* everything below requires holding the cs */ CRITICAL_SECTION cs; ULONG report_len; @@ -442,13 +450,27 @@ static NTSTATUS sync_ioctl(DEVICE_OBJECT *device, DWORD code, void *in_buf, DWOR return io.Status; }
+static void check_value_caps(struct func_device *fdo, USHORT usage, HIDP_VALUE_CAPS *caps) +{ + switch (usage) + { + case HID_USAGE_GENERIC_X: fdo->lx_caps = *caps; break; + case HID_USAGE_GENERIC_Y: fdo->ly_caps = *caps; break; + case HID_USAGE_GENERIC_Z: fdo->lt_caps = *caps; break; + case HID_USAGE_GENERIC_RX: fdo->rx_caps = *caps; break; + case HID_USAGE_GENERIC_RY: fdo->ry_caps = *caps; break; + case HID_USAGE_GENERIC_RZ: fdo->rt_caps = *caps; break; + } +} + static NTSTATUS initialize_device(DEVICE_OBJECT *device) { struct func_device *fdo = fdo_from_DEVICE_OBJECT(device); - ULONG i, report_desc_len, report_count; + ULONG i, u, button_count, report_desc_len, report_count; PHIDP_REPORT_DESCRIPTOR report_desc; PHIDP_PREPARSED_DATA preparsed; - HIDP_DEVICE_DESC device_desc; + HIDP_BUTTON_CAPS *button_caps; + HIDP_VALUE_CAPS *value_caps; HIDP_REPORT_IDS *reports; HID_DESCRIPTOR hid_desc; NTSTATUS status; @@ -461,16 +483,49 @@ static NTSTATUS initialize_device(DEVICE_OBJECT *device) if (!(report_desc = malloc(report_desc_len))) return STATUS_NO_MEMORY;
status = sync_ioctl(fdo->bus_device, IOCTL_HID_GET_REPORT_DESCRIPTOR, NULL, 0, report_desc, report_desc_len); - if (!status) status = HidP_GetCollectionDescription(report_desc, report_desc_len, PagedPool, &device_desc); + if (!status) status = HidP_GetCollectionDescription(report_desc, report_desc_len, PagedPool, &fdo->device_desc); free(report_desc); if (status != HIDP_STATUS_SUCCESS) return status;
- preparsed = device_desc.CollectionDesc->PreparsedData; + preparsed = fdo->device_desc.CollectionDesc->PreparsedData; status = HidP_GetCaps(preparsed, &caps); if (status != HIDP_STATUS_SUCCESS) return status;
- reports = device_desc.ReportIDs; - report_count = device_desc.ReportIDsLength; + button_count = 0; + if (!(button_caps = malloc(sizeof(*button_caps) * caps.NumberInputButtonCaps))) return STATUS_NO_MEMORY; + status = HidP_GetButtonCaps(HidP_Input, button_caps, &caps.NumberInputButtonCaps, preparsed); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetButtonCaps returned %#x\n", status); + else for (i = 0; i < caps.NumberInputButtonCaps; i++) + { + if (button_caps[i].UsagePage != HID_USAGE_PAGE_BUTTON) continue; + if (button_caps[i].IsRange) button_count = max(button_count, button_caps[i].Range.UsageMax); + else button_count = max(button_count, button_caps[i].NotRange.Usage); + } + free(button_caps); + if (status != HIDP_STATUS_SUCCESS) return status; + if (button_count < 10) WARN("only %u buttons found\n", button_count); + + if (!(value_caps = malloc(sizeof(*value_caps) * caps.NumberInputValueCaps))) return STATUS_NO_MEMORY; + status = HidP_GetValueCaps(HidP_Input, value_caps, &caps.NumberInputValueCaps, preparsed); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetValueCaps returned %#x\n", status); + else for (i = 0; i < caps.NumberInputValueCaps; i++) + { + HIDP_VALUE_CAPS *caps = value_caps + i; + if (caps->UsagePage != HID_USAGE_PAGE_GENERIC) continue; + if (!caps->IsRange) check_value_caps(fdo, caps->NotRange.Usage, caps); + else for (u = caps->Range.UsageMin; u <=caps->Range.UsageMax; u++) check_value_caps(fdo, u, value_caps + i); + } + free(value_caps); + if (status != HIDP_STATUS_SUCCESS) return status; + if (!fdo->lx_caps.UsagePage) WARN("missing lx axis\n"); + if (!fdo->ly_caps.UsagePage) WARN("missing ly axis\n"); + if (!fdo->lt_caps.UsagePage) WARN("missing lt axis\n"); + if (!fdo->rx_caps.UsagePage) WARN("missing rx axis\n"); + if (!fdo->ry_caps.UsagePage) WARN("missing ry axis\n"); + if (!fdo->rt_caps.UsagePage) WARN("missing rt axis\n"); + + reports = fdo->device_desc.ReportIDs; + report_count = fdo->device_desc.ReportIDsLength; for (i = 0; i < report_count; ++i) if (!reports[i].ReportID || reports[i].InputLength) break; if (i == report_count) i = 0; /* no input report?!, just use first ID */
@@ -478,7 +533,6 @@ static NTSTATUS initialize_device(DEVICE_OBJECT *device) if (!(fdo->report_buf = malloc(fdo->report_len))) return STATUS_NO_MEMORY; fdo->report_buf[0] = reports[i].ReportID;
- HidP_FreeCollectionDescription(&device_desc); return STATUS_SUCCESS; }
@@ -556,6 +610,7 @@ static NTSTATUS WINAPI fdo_pnp(DEVICE_OBJECT *device, IRP *irp) status = IoCallDriver(fdo->bus_device, irp); IoDetachDevice(fdo->bus_device); RtlDeleteCriticalSection(&fdo->cs); + HidP_FreeCollectionDescription(&fdo->device_desc); free(fdo->report_buf); IoDeleteDevice(device); return status;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winexinput.sys/main.c | 188 ++++++++++++++++++++++++++- dlls/winexinput.sys/pop_hid_macros.h | 83 ++++++++++++ dlls/winexinput.sys/psh_hid_macros.h | 85 ++++++++++++ dlls/xinput1_3/tests/xinput.c | 25 ---- 4 files changed, 349 insertions(+), 32 deletions(-) create mode 100644 dlls/winexinput.sys/pop_hid_macros.h create mode 100644 dlls/winexinput.sys/psh_hid_macros.h
diff --git a/dlls/winexinput.sys/main.c b/dlls/winexinput.sys/main.c index dfe747d6515..3832c97ef26 100644 --- a/dlls/winexinput.sys/main.c +++ b/dlls/winexinput.sys/main.c @@ -50,6 +50,75 @@ __ASM_STDCALL_FUNC(wrap_fastcall_func1, 8, #define call_fastcall_func1(func,a) func(a) #endif
+#include "psh_hid_macros.h" + +const BYTE xinput_report_desc[] = +{ + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_GAMEPAD), + COLLECTION(1, Application), + USAGE(1, 0), + COLLECTION(1, Physical), + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + LOGICAL_MAXIMUM(2, 0xffff), + PHYSICAL_MAXIMUM(2, 0xffff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + COLLECTION(1, Physical), + USAGE(1, HID_USAGE_GENERIC_RX), + USAGE(1, HID_USAGE_GENERIC_RY), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + COLLECTION(1, Physical), + USAGE(1, HID_USAGE_GENERIC_Z), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 10), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 1), + REPORT_COUNT(1, 10), + REPORT_SIZE(1, 1), + INPUT(1, Data|Var|Abs), + + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_HATSWITCH), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 8), + PHYSICAL_MAXIMUM(2, 0x103b), + REPORT_SIZE(1, 4), + REPORT_COUNT(4, 1), + UNIT(1, 0x0e /* none */), + INPUT(1, Data|Var|Abs|Null), + + REPORT_COUNT(1, 18), + REPORT_SIZE(1, 1), + INPUT(1, Cnst|Var|Abs), + END_COLLECTION, +}; + +#include "pop_hid_macros.h" + +struct xinput_state +{ + WORD lx_axis; + WORD ly_axis; + WORD rx_axis; + WORD ry_axis; + WORD trigger; + WORD buttons; + WORD padding; +}; + struct device { BOOL is_fdo; @@ -96,6 +165,7 @@ struct func_device char *report_buf; IRP *pending_read; BOOL pending_is_gamepad; + struct xinput_state xinput_state; };
static inline struct func_device *fdo_from_DEVICE_OBJECT(DEVICE_OBJECT *device) @@ -105,6 +175,73 @@ static inline struct func_device *fdo_from_DEVICE_OBJECT(DEVICE_OBJECT *device) else return CONTAINING_RECORD(impl, struct phys_device, base)->fdo; }
+static LONG sign_extend(ULONG value, const HIDP_VALUE_CAPS *caps) +{ + UINT sign = 1 << (caps->BitSize - 1); + if (sign <= 1 || caps->LogicalMin >= 0) return value; + return value - ((value & sign) << 1); +} + +static LONG scale_value(ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LONG max) +{ + LONG tmp = sign_extend(value, caps); + if (caps->LogicalMin > caps->LogicalMax) return 0; + if (caps->LogicalMin > tmp || caps->LogicalMax < tmp) return 0; + return min + MulDiv(tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin); +} + +static void translate_report_to_xinput_state(struct func_device *fdo) +{ + ULONG lx = 0, ly = 0, rx = 0, ry = 0, lt = 0, rt = 0, hat = 0; + PHIDP_PREPARSED_DATA preparsed; + USAGE usages[10]; + NTSTATUS status; + ULONG i, count; + + preparsed = fdo->device_desc.CollectionDesc->PreparsedData; + + count = ARRAY_SIZE(usages); + status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usages, + &count, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsages returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, + &hat, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue hat returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, + &lx, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue x returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y, + &ly, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue y returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, + <, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue z returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, + &rx, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue rx returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, + &ry, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue ry returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, + &rt, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue rz returned %#x\n", status); + + if (hat < 1 || hat > 8) fdo->xinput_state.buttons = 0; + else fdo->xinput_state.buttons = hat << 10; + for (i = 0; i < count; i++) + { + if (usages[i] < 1 || usages[i] > 10) continue; + fdo->xinput_state.buttons |= (1 << (usages[i] - 1)); + } + fdo->xinput_state.lx_axis = scale_value(lx, &fdo->lx_caps, 0, 65535); + fdo->xinput_state.ly_axis = scale_value(ly, &fdo->ly_caps, 0, 65535); + fdo->xinput_state.rx_axis = scale_value(rx, &fdo->rx_caps, 0, 65535); + fdo->xinput_state.ry_axis = scale_value(ry, &fdo->ry_caps, 0, 65535); + rt = scale_value(rt, &fdo->rt_caps, 0, 255); + lt = scale_value(lt, &fdo->lt_caps, 0, 255); + fdo->xinput_state.trigger = 0x8000 + (lt - rt) * 128; +} + static NTSTATUS WINAPI read_completion(DEVICE_OBJECT *device, IRP *xinput_irp, void *context) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(xinput_irp); @@ -121,7 +258,9 @@ static NTSTATUS WINAPI read_completion(DEVICE_OBJECT *device, IRP *xinput_irp, v RtlEnterCriticalSection(&fdo->cs); offset = fdo->report_buf[0] ? 0 : 1; memcpy(fdo->report_buf + offset, read_buf, read_len); - memcpy(gamepad_irp->UserBuffer, read_buf, read_len); + translate_report_to_xinput_state(fdo); + memcpy(gamepad_irp->UserBuffer, &fdo->xinput_state, sizeof(fdo->xinput_state)); + gamepad_irp->IoStatus.Information = sizeof(fdo->xinput_state); RtlLeaveCriticalSection(&fdo->cs); }
@@ -178,6 +317,7 @@ static NTSTATUS try_complete_pending_read(DEVICE_OBJECT *device, IRP *irp) static NTSTATUS WINAPI gamepad_internal_ioctl(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + ULONG output_len = stack->Parameters.DeviceIoControl.OutputBufferLength; ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; struct func_device *fdo = fdo_from_DEVICE_OBJECT(device);
@@ -185,20 +325,54 @@ static NTSTATUS WINAPI gamepad_internal_ioctl(DEVICE_OBJECT *device, IRP *irp)
switch (code) { - case IOCTL_HID_GET_INPUT_REPORT: + case IOCTL_HID_GET_DEVICE_DESCRIPTOR: { - HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer; + HID_DESCRIPTOR *descriptor = (HID_DESCRIPTOR *)irp->UserBuffer;
- RtlEnterCriticalSection(&fdo->cs); - memcpy(packet->reportBuffer, fdo->report_buf, fdo->report_len); - irp->IoStatus.Information = fdo->report_len; - RtlLeaveCriticalSection(&fdo->cs); + irp->IoStatus.Information = sizeof(*descriptor); + if (output_len < sizeof(*descriptor)) + { + irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + + memset(descriptor, 0, sizeof(*descriptor)); + descriptor->bLength = sizeof(*descriptor); + descriptor->bDescriptorType = HID_HID_DESCRIPTOR_TYPE; + descriptor->bcdHID = HID_REVISION; + descriptor->bCountry = 0; + descriptor->bNumDescriptors = 1; + descriptor->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE; + descriptor->DescriptorList[0].wReportLength = sizeof(xinput_report_desc);
irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_SUCCESS; }
+ case IOCTL_HID_GET_REPORT_DESCRIPTOR: + irp->IoStatus.Information = sizeof(xinput_report_desc); + if (output_len < sizeof(xinput_report_desc)) + { + irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + + memcpy(irp->UserBuffer, xinput_report_desc, sizeof(xinput_report_desc)); + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + + case IOCTL_HID_GET_INPUT_REPORT: + case IOCTL_HID_SET_OUTPUT_REPORT: + case IOCTL_HID_GET_FEATURE: + case IOCTL_HID_SET_FEATURE: + irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_INVALID_PARAMETER; + default: IoSkipCurrentIrpStackLocation(irp); return IoCallDriver(fdo->bus_device, irp); diff --git a/dlls/winexinput.sys/pop_hid_macros.h b/dlls/winexinput.sys/pop_hid_macros.h new file mode 100644 index 00000000000..767c26e8ecb --- /dev/null +++ b/dlls/winexinput.sys/pop_hid_macros.h @@ -0,0 +1,83 @@ +/* + * HID report helper macros. + * + * Copyright 2021 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#undef Data +#undef Cnst +#undef Array +#undef Var +#undef Abs +#undef Rel +#undef NoWrap +#undef Wrap +#undef NonLin +#undef Lin +#undef NoPref +#undef Pref +#undef NoNull +#undef Null +#undef NonVol +#undef Vol +#undef Bits +#undef Buff + +#undef Physical +#undef Application +#undef Logical +#undef Report +#undef NamedArray +#undef UsageSwitch +#undef UsageModifier + +#undef SHORT_ITEM_0 +#undef SHORT_ITEM_1 +#undef SHORT_ITEM_2 +#undef SHORT_ITEM_4 + +#undef LONG_ITEM + +#undef INPUT +#undef OUTPUT +#undef FEATURE +#undef COLLECTION +#undef END_COLLECTION + +#undef USAGE_PAGE +#undef LOGICAL_MINIMUM +#undef LOGICAL_MAXIMUM +#undef PHYSICAL_MINIMUM +#undef PHYSICAL_MAXIMUM +#undef UNIT_EXPONENT +#undef UNIT +#undef REPORT_SIZE +#undef REPORT_ID +#undef REPORT_COUNT +#undef PUSH +#undef POP + +#undef USAGE +#undef USAGE_MINIMUM +#undef USAGE_MAXIMUM +#undef DESIGNATOR_INDEX +#undef DESIGNATOR_MINIMUM +#undef DESIGNATOR_MAXIMUM +#undef STRING_INDEX +#undef STRING_MINIMUM +#undef STRING_MAXIMUM +#undef DELIMITER diff --git a/dlls/winexinput.sys/psh_hid_macros.h b/dlls/winexinput.sys/psh_hid_macros.h new file mode 100644 index 00000000000..4623af20598 --- /dev/null +++ b/dlls/winexinput.sys/psh_hid_macros.h @@ -0,0 +1,85 @@ +/* + * HID report helper macros. + * + * Copyright 2021 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <hidusage.h> + +#define Data 0 +#define Cnst 0x01 +#define Ary 0 +#define Var 0x02 +#define Abs 0 +#define Rel 0x04 +#define NoWrap 0 +#define Wrap 0x08 +#define NonLin 0 +#define Lin 0x10 +#define NoPref 0 +#define Pref 0x20 +#define NoNull 0 +#define Null 0x40 +#define NonVol 0 +#define Vol 0x80 +#define Bits 0 +#define Buff 0x100 + +#define Physical 0x00 +#define Application 0x01 +#define Logical 0x02 +#define Report 0x03 +#define NamedArray 0x04 +#define UsageSwitch 0x05 +#define UsageModifier 0x06 + +#define SHORT_ITEM_0(tag,type) (((tag)<<4)|((type)<<2)|0) +#define SHORT_ITEM_1(tag,type,data) (((tag)<<4)|((type)<<2)|1),((data)&0xff) +#define SHORT_ITEM_2(tag,type,data) (((tag)<<4)|((type)<<2)|2),((data)&0xff),(((data)>>8)&0xff) +#define SHORT_ITEM_4(tag,type,data) (((tag)<<4)|((type)<<2)|3),((data)&0xff),(((data)>>8)&0xff),(((data)>>16)&0xff),(((data)>>24)&0xff) + +#define LONG_ITEM(tag,size) SHORT_ITEM_2(0xf,0x3,((tag)<<8)|(size)) + +#define INPUT(n,data) SHORT_ITEM_##n(0x8,0,data) +#define OUTPUT(n,data) SHORT_ITEM_##n(0x9,0,data) +#define FEATURE(n,data) SHORT_ITEM_##n(0xb,0,data) +#define COLLECTION(n,data) SHORT_ITEM_##n(0xa,0,data) +#define END_COLLECTION SHORT_ITEM_0(0xc,0) + +#define USAGE_PAGE(n,data) SHORT_ITEM_##n(0x0,1,data) +#define LOGICAL_MINIMUM(n,data) SHORT_ITEM_##n(0x1,1,data) +#define LOGICAL_MAXIMUM(n,data) SHORT_ITEM_##n(0x2,1,data) +#define PHYSICAL_MINIMUM(n,data) SHORT_ITEM_##n(0x3,1,data) +#define PHYSICAL_MAXIMUM(n,data) SHORT_ITEM_##n(0x4,1,data) +#define UNIT_EXPONENT(n,data) SHORT_ITEM_##n(0x5,1,data) +#define UNIT(n,data) SHORT_ITEM_##n(0x6,1,data) +#define REPORT_SIZE(n,data) SHORT_ITEM_##n(0x7,1,data) +#define REPORT_ID(n,data) SHORT_ITEM_##n(0x8,1,data) +#define REPORT_COUNT(n,data) SHORT_ITEM_##n(0x9,1,data) +#define PUSH(n,data) SHORT_ITEM_##n(0xa,1,data) +#define POP(n,data) SHORT_ITEM_##n(0xb,1,data) + +#define USAGE(n,data) SHORT_ITEM_##n(0x0,2,data) +#define USAGE_MINIMUM(n,data) SHORT_ITEM_##n(0x1,2,data) +#define USAGE_MAXIMUM(n,data) SHORT_ITEM_##n(0x2,2,data) +#define DESIGNATOR_INDEX(n,data) SHORT_ITEM_##n(0x3,2,data) +#define DESIGNATOR_MINIMUM(n,data) SHORT_ITEM_##n(0x4,2,data) +#define DESIGNATOR_MAXIMUM(n,data) SHORT_ITEM_##n(0x5,2,data) +#define STRING_INDEX(n,data) SHORT_ITEM_##n(0x6,2,data) +#define STRING_MINIMUM(n,data) SHORT_ITEM_##n(0x7,2,data) +#define STRING_MAXIMUM(n,data) SHORT_ITEM_##n(0x8,2,data) +#define DELIMITER(n,data) SHORT_ITEM_##n(0x9,2,data) diff --git a/dlls/xinput1_3/tests/xinput.c b/dlls/xinput1_3/tests/xinput.c index 811fe045d10..60c5817c79a 100644 --- a/dlls/xinput1_3/tests/xinput.c +++ b/dlls/xinput1_3/tests/xinput.c @@ -455,21 +455,15 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre
check_member(*hid_caps, expect_hid_caps, "%04x", Usage); check_member(*hid_caps, expect_hid_caps, "%04x", UsagePage); - todo_wine check_member(*hid_caps, expect_hid_caps, "%d", InputReportByteLength); - todo_wine_if(xi_caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) check_member(*hid_caps, expect_hid_caps, "%d", OutputReportByteLength); check_member(*hid_caps, expect_hid_caps, "%d", FeatureReportByteLength); check_member(*hid_caps, expect_hid_caps, "%d", NumberLinkCollectionNodes); check_member(*hid_caps, expect_hid_caps, "%d", NumberInputButtonCaps); - todo_wine check_member(*hid_caps, expect_hid_caps, "%d", NumberInputValueCaps); - todo_wine check_member(*hid_caps, expect_hid_caps, "%d", NumberInputDataIndices); check_member(*hid_caps, expect_hid_caps, "%d", NumberOutputButtonCaps); - todo_wine_if(xi_caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) check_member(*hid_caps, expect_hid_caps, "%d", NumberOutputValueCaps); - todo_wine_if(xi_caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) check_member(*hid_caps, expect_hid_caps, "%d", NumberOutputDataIndices); check_member(*hid_caps, expect_hid_caps, "%d", NumberFeatureButtonCaps); check_member(*hid_caps, expect_hid_caps, "%d", NumberFeatureValueCaps); @@ -522,11 +516,8 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre else if (button_caps[i].IsRange && expect_button_caps[i].IsRange) { check_member(button_caps[i], expect_button_caps[i], "%04x", Range.UsageMin); - todo_wine check_member(button_caps[i], expect_button_caps[i], "%04x", Range.UsageMax); - todo_wine check_member(button_caps[i], expect_button_caps[i], "%d", Range.DataIndexMin); - todo_wine check_member(button_caps[i], expect_button_caps[i], "%d", Range.DataIndexMax); }
@@ -551,7 +542,6 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre count = hid_caps->NumberInputValueCaps; status = HidP_GetValueCaps(HidP_Input, value_caps, &count, preparsed); ok(status == HIDP_STATUS_SUCCESS, "HidP_GetValueCaps returned %#x\n", status); - todo_wine ok(count == ARRAY_SIZE(expect_value_caps), "got %d value caps\n", count);
for (i = 0; i < min(count, ARRAY_SIZE(expect_value_caps)); ++i) @@ -560,11 +550,8 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre check_member(value_caps[i], expect_value_caps[i], "%04x", UsagePage); check_member(value_caps[i], expect_value_caps[i], "%d", ReportID); check_member(value_caps[i], expect_value_caps[i], "%d", IsAlias); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", BitField); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", LinkCollection); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", LinkUsage); check_member(value_caps[i], expect_value_caps[i], "%d", LinkUsagePage); check_member(value_caps[i], expect_value_caps[i], "%d", IsRange); @@ -572,27 +559,19 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre check_member(value_caps[i], expect_value_caps[i], "%d", IsDesignatorRange); check_member(value_caps[i], expect_value_caps[i], "%d", IsAbsolute);
- todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", HasNull); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", BitSize); check_member(value_caps[i], expect_value_caps[i], "%d", ReportCount); check_member(value_caps[i], expect_value_caps[i], "%d", UnitsExp); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", Units); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", LogicalMin); - todo_wine check_member(value_caps[i], expect_value_caps[i], "%d", LogicalMax); check_member(value_caps[i], expect_value_caps[i], "%d", PhysicalMin); - todo_wine check_member(value_caps[i], expect_value_caps[i], "%d", PhysicalMax);
if (!value_caps[i].IsRange && !expect_value_caps[i].IsRange) { - todo_wine_if(i >= 4) check_member(value_caps[i], expect_value_caps[i], "%04x", NotRange.Usage); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", NotRange.DataIndex); } else if (value_caps[i].IsRange && expect_value_caps[i].IsRange) @@ -627,9 +606,7 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre SetLastError(0xdeadbeef); memset(buffer, 0, sizeof(buffer)); ret = HidD_GetInputReport(device, buffer, hid_caps->InputReportByteLength); - todo_wine ok(!ret, "HidD_GetInputReport succeeded\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "HidD_GetInputReport returned error %u\n", GetLastError());
if (!winetest_interactive) skip("skipping interactive tests\n"); @@ -737,12 +714,10 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre value = 0; status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &value, preparsed, buffer, hid_caps->InputReportByteLength); ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsageValue returned %#x\n", status); - todo_wine ok(value == 32768 + (state.Gamepad.bLeftTrigger - state.Gamepad.bRightTrigger) * 128, "got Z value %d (RT %d, LT %d)\n", value, state.Gamepad.bRightTrigger, state.Gamepad.bLeftTrigger); value = 0; status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, &value, preparsed, buffer, hid_caps->InputReportByteLength); - todo_wine ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_GetUsageValue returned %#x\n", status); } while (ret && (state.Gamepad.bRightTrigger != 255 || state.Gamepad.bLeftTrigger != 255)); }