[PATCH 8/8] winexinput.sys: Translate lower reports into XInput HID reports.

Rémi Bernon rbernon at codeweavers.com
Fri Sep 3 00:57:40 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/winexinput.sys/main.c           | 251 +++++++++++++++++++++++++--
 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, 409 insertions(+), 35 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 60f7a8ed5dd..e547f745347 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;
@@ -82,12 +151,22 @@ 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;
+
     /* everything below requires holding the cs */
     CRITICAL_SECTION cs;
     ULONG report_len;
     char *report_buf;
     IRP *pending_read;
     BOOL pending_is_gamepad;
+
+    HIDP_DEVICE_DESC device_desc;
+    struct xinput_state xinput_state;
 };
 
 static inline struct func_device *fdo_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
@@ -97,6 +176,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 HID_USAGE_PAGE_BUTTON 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 HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_HATSWITCH 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 HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_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 HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Y returned %#x\n", status);
+    status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &lt, preparsed,
+                            fdo->report_buf, fdo->report_len);
+    if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_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 HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_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 HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_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 HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_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);
@@ -113,7 +259,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);
     }
 
@@ -170,6 +318,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);
 
@@ -177,20 +326,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);
@@ -442,13 +625,28 @@ 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_BUTTON_CAPS *button_caps;
     HIDP_DEVICE_DESC device_desc;
+    HIDP_VALUE_CAPS *value_caps;
     HIDP_REPORT_IDS *reports;
     HID_DESCRIPTOR hid_desc;
     NTSTATUS status;
@@ -467,18 +665,50 @@ static NTSTATUS initialize_device(DEVICE_OBJECT *device)
 
     preparsed = device_desc.CollectionDesc->PreparsedData;
     status = HidP_GetCaps(preparsed, &caps);
-    if (status != HIDP_STATUS_SUCCESS) return status;
+    if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetCaps returned %#x\n", status);
+
+    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 (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 (!fdo->lt_caps.UsagePage) WARN("missing lt axis\n");
+    if (!fdo->rt_caps.UsagePage) WARN("missing rt axis\n");
+    if (!fdo->lx_caps.UsagePage) WARN("missing lx axis\n");
+    if (!fdo->ly_caps.UsagePage) WARN("missing ly axis\n");
+    if (!fdo->rx_caps.UsagePage) WARN("missing rx axis\n");
+    if (!fdo->ry_caps.UsagePage) WARN("missing ry axis\n");
 
     reports = device_desc.ReportIDs;
     report_count = 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 */
 
+    fdo->device_desc = device_desc;
     fdo->report_len = caps.InputReportByteLength;
     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 +786,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;
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));
     }
-- 
2.33.0




More information about the wine-devel mailing list