mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 18:37:19 +00:00
winexinput.sys: Translate lower reports into XInput HID reports.
Signed-off-by: Rémi Bernon <rbernon@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b027f70a91
commit
2eea1d615a
|
@ -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);
|
||||
|
|
83
dlls/winexinput.sys/pop_hid_macros.h
Normal file
83
dlls/winexinput.sys/pop_hid_macros.h
Normal file
|
@ -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
|
85
dlls/winexinput.sys/psh_hid_macros.h
Normal file
85
dlls/winexinput.sys/psh_hid_macros.h
Normal file
|
@ -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)
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue