Commit 2eea1d61 authored by Rémi Bernon's avatar Rémi Bernon Committed by Alexandre Julliard

winexinput.sys: Translate lower reports into XInput HID reports.

parent b027f70a
......@@ -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,
&lt, 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);
......
/*
* 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
/*
* 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)
......@@ -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));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment