dinput: Look for the PID device control output report.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-10-01 09:31:01 +02:00 committed by Alexandre Julliard
parent 903c7ea75d
commit ff7685dea4
2 changed files with 90 additions and 6 deletions

View File

@ -78,6 +78,13 @@ struct extra_caps
LONG saturation; LONG saturation;
}; };
struct pid_control_report
{
BYTE id;
ULONG collection;
ULONG control_coll;
};
#define DEVICE_STATE_MAX_SIZE 1024 #define DEVICE_STATE_MAX_SIZE 1024
struct hid_joystick struct hid_joystick
@ -102,6 +109,8 @@ struct hid_joystick
BYTE device_state_report_id; BYTE device_state_report_id;
BYTE device_state[DEVICE_STATE_MAX_SIZE]; BYTE device_state[DEVICE_STATE_MAX_SIZE];
struct pid_control_report pid_device_control;
}; };
static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface )
@ -1176,6 +1185,12 @@ static BOOL hid_joystick_device_try_open( UINT32 handle, const WCHAR *path, HAND
instance->wUsagePage = caps->UsagePage; instance->wUsagePage = caps->UsagePage;
instance->wUsage = caps->Usage; instance->wUsage = caps->Usage;
count = ARRAY_SIZE(buttons);
status = HidP_GetSpecificButtonCaps( HidP_Output, HID_USAGE_PAGE_PID, 0,
PID_USAGE_DC_DEVICE_RESET, buttons, &count, preparsed_data );
if (status == HIDP_STATUS_SUCCESS && count > 0)
instance->guidFFDriver = IID_IDirectInputPIDDriver;
count = ARRAY_SIZE(buttons); count = ARRAY_SIZE(buttons);
status = HidP_GetSpecificButtonCaps( HidP_Input, HID_USAGE_PAGE_BUTTON, 0, 0, buttons, &count, preparsed_data ); status = HidP_GetSpecificButtonCaps( HidP_Input, HID_USAGE_PAGE_BUTTON, 0, 0, buttons, &count, preparsed_data );
if (status != HIDP_STATUS_SUCCESS) count = button_count = 0; if (status != HIDP_STATUS_SUCCESS) count = button_count = 0;
@ -1398,6 +1413,67 @@ static BOOL init_data_format( struct hid_joystick *impl, struct hid_value_caps *
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
static BOOL init_pid_reports( struct hid_joystick *impl, struct hid_value_caps *caps,
DIDEVICEOBJECTINSTANCEW *instance, void *data )
{
struct pid_control_report *device_control = &impl->pid_device_control;
#define SET_COLLECTION( rep ) \
do \
{ \
if (rep->collection) FIXME( "duplicate " #rep " report!\n" ); \
else rep->collection = DIDFT_GETINSTANCE( instance->dwType ); \
} while (0)
#define SET_SUB_COLLECTION( rep, sub ) \
do { \
if (instance->wCollectionNumber != rep->collection) \
FIXME( "unexpected " #rep "." #sub " parent!\n" ); \
else if (rep->sub) \
FIXME( "duplicate " #rep "." #sub " collection!\n" ); \
else \
rep->sub = DIDFT_GETINSTANCE( instance->dwType ); \
} while (0)
if (instance->wUsagePage == HID_USAGE_PAGE_PID)
{
switch (instance->wUsage)
{
case PID_USAGE_DEVICE_CONTROL_REPORT: SET_COLLECTION( device_control ); break;
case PID_USAGE_DEVICE_CONTROL: SET_SUB_COLLECTION( device_control, control_coll ); break;
}
}
#undef SET_SUB_COLLECTION
#undef SET_COLLECTION
return DIENUM_CONTINUE;
}
static BOOL init_pid_caps( struct hid_joystick *impl, struct hid_value_caps *caps,
DIDEVICEOBJECTINSTANCEW *instance, void *data )
{
struct pid_control_report *device_control = &impl->pid_device_control;
if (!(instance->dwType & DIDFT_OUTPUT)) return DIENUM_CONTINUE;
#define SET_REPORT_ID( rep ) \
do \
{ \
if (!rep->id) \
rep->id = instance->wReportId; \
else if (rep->id != instance->wReportId) \
FIXME( "multiple " #rep " report ids!\n" ); \
} while (0)
if (instance->wCollectionNumber == device_control->control_coll)
SET_REPORT_ID( device_control );
#undef SET_REPORT_ID
return DIENUM_CONTINUE;
}
static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID *guid, IDirectInputDevice8W **out ) static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID *guid, IDirectInputDevice8W **out )
{ {
static const DIPROPHEADER filter = static const DIPROPHEADER filter =
@ -1485,6 +1561,20 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
impl->usages_buf = usages; impl->usages_buf = usages;
enum_objects( impl, &filter, DIDFT_ALL, init_objects, NULL ); enum_objects( impl, &filter, DIDFT_ALL, init_objects, NULL );
enum_objects( impl, &filter, DIDFT_COLLECTION, init_pid_reports, NULL );
enum_objects( impl, &filter, DIDFT_NODATA, init_pid_caps, NULL );
TRACE( "device control id %u, coll %u, control coll %u\n", impl->pid_device_control.id,
impl->pid_device_control.collection, impl->pid_device_control.control_coll );
if (impl->pid_device_control.id)
{
impl->dev_caps.dwFlags |= DIDC_FORCEFEEDBACK;
impl->dev_caps.dwFFSamplePeriod = 1000000;
impl->dev_caps.dwFFMinTimeResolution = 1000000;
impl->dev_caps.dwHardwareRevision = 1;
impl->dev_caps.dwFFDriverVersion = 1;
}
format = impl->base.data_format.wine_df; format = impl->base.data_format.wine_df;
if (format->dwDataSize > DEVICE_STATE_MAX_SIZE) if (format->dwDataSize > DEVICE_STATE_MAX_SIZE)

View File

@ -5646,7 +5646,6 @@ static void test_force_feedback_joystick( void )
check_member_wstr( devinst, expect_devinst, tszInstanceName ); check_member_wstr( devinst, expect_devinst, tszInstanceName );
todo_wine todo_wine
check_member_wstr( devinst, expect_devinst, tszProductName ); check_member_wstr( devinst, expect_devinst, tszProductName );
todo_wine
check_member_guid( devinst, expect_devinst, guidFFDriver ); check_member_guid( devinst, expect_devinst, guidFFDriver );
check_member( devinst, expect_devinst, "%04x", wUsagePage ); check_member( devinst, expect_devinst, "%04x", wUsagePage );
check_member( devinst, expect_devinst, "%04x", wUsage ); check_member( devinst, expect_devinst, "%04x", wUsage );
@ -5655,20 +5654,15 @@ static void test_force_feedback_joystick( void )
hr = IDirectInputDevice8_GetCapabilities( device, &caps ); hr = IDirectInputDevice8_GetCapabilities( device, &caps );
ok( hr == DI_OK, "IDirectInputDevice8_GetCapabilities returned %#x\n", hr ); ok( hr == DI_OK, "IDirectInputDevice8_GetCapabilities returned %#x\n", hr );
check_member( caps, expect_caps, "%d", dwSize ); check_member( caps, expect_caps, "%d", dwSize );
todo_wine
check_member( caps, expect_caps, "%#x", dwFlags ); check_member( caps, expect_caps, "%#x", dwFlags );
check_member( caps, expect_caps, "%#x", dwDevType ); check_member( caps, expect_caps, "%#x", dwDevType );
check_member( caps, expect_caps, "%d", dwAxes ); check_member( caps, expect_caps, "%d", dwAxes );
check_member( caps, expect_caps, "%d", dwButtons ); check_member( caps, expect_caps, "%d", dwButtons );
check_member( caps, expect_caps, "%d", dwPOVs ); check_member( caps, expect_caps, "%d", dwPOVs );
todo_wine
check_member( caps, expect_caps, "%d", dwFFSamplePeriod ); check_member( caps, expect_caps, "%d", dwFFSamplePeriod );
todo_wine
check_member( caps, expect_caps, "%d", dwFFMinTimeResolution ); check_member( caps, expect_caps, "%d", dwFFMinTimeResolution );
check_member( caps, expect_caps, "%d", dwFirmwareRevision ); check_member( caps, expect_caps, "%d", dwFirmwareRevision );
todo_wine
check_member( caps, expect_caps, "%d", dwHardwareRevision ); check_member( caps, expect_caps, "%d", dwHardwareRevision );
todo_wine
check_member( caps, expect_caps, "%d", dwFFDriverVersion ); check_member( caps, expect_caps, "%d", dwFFDriverVersion );
prop_dword.dwData = 0xdeadbeef; prop_dword.dwData = 0xdeadbeef;