dinput: Write PID device gain reports when necessary.

Based on a patch from Ivo Ivanov <logos128@gmail.com>.

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-11-17 11:51:53 +01:00 committed by Alexandre Julliard
parent 9dc873ab99
commit 45986545f8
4 changed files with 38 additions and 23 deletions

View File

@ -1103,6 +1103,8 @@ static HRESULT WINAPI dinput_device_SetProperty( IDirectInputDevice8W *iface, co
if (value->dwData > 10000) return DIERR_INVALIDPARAM; if (value->dwData > 10000) return DIERR_INVALIDPARAM;
EnterCriticalSection( &impl->crit ); EnterCriticalSection( &impl->crit );
impl->device_gain = value->dwData; impl->device_gain = value->dwData;
if (!impl->acquired || !(impl->dwCoopLevel & DISCL_EXCLUSIVE)) hr = DI_OK;
else hr = impl->vtbl->send_device_gain( iface, impl->device_gain );
LeaveCriticalSection( &impl->crit ); LeaveCriticalSection( &impl->crit );
return hr; return hr;
} }
@ -1520,7 +1522,7 @@ static HRESULT WINAPI dinput_device_SendForceFeedbackCommand( IDirectInputDevice
EnterCriticalSection( &impl->crit ); EnterCriticalSection( &impl->crit );
if (!impl->acquired || !(impl->dwCoopLevel & DISCL_EXCLUSIVE)) hr = DIERR_NOTEXCLUSIVEACQUIRED; if (!impl->acquired || !(impl->dwCoopLevel & DISCL_EXCLUSIVE)) hr = DIERR_NOTEXCLUSIVEACQUIRED;
else hr = impl->vtbl->send_force_feedback_command( iface, command ); else hr = impl->vtbl->send_force_feedback_command( iface, command, FALSE );
LeaveCriticalSection( &impl->crit ); LeaveCriticalSection( &impl->crit );
return hr; return hr;

View File

@ -49,7 +49,7 @@ struct dinput_device_vtbl
const DIDEVICEOBJECTINSTANCEW *instance ); const DIDEVICEOBJECTINSTANCEW *instance );
HRESULT (*get_effect_info)( IDirectInputDevice8W *iface, DIEFFECTINFOW *info, const GUID *guid ); HRESULT (*get_effect_info)( IDirectInputDevice8W *iface, DIEFFECTINFOW *info, const GUID *guid );
HRESULT (*create_effect)( IDirectInputDevice8W *iface, IDirectInputEffect **out ); HRESULT (*create_effect)( IDirectInputDevice8W *iface, IDirectInputEffect **out );
HRESULT (*send_force_feedback_command)( IDirectInputDevice8W *iface, DWORD command ); HRESULT (*send_force_feedback_command)( IDirectInputDevice8W *iface, DWORD command, BOOL unacquire );
HRESULT (*send_device_gain)( IDirectInputDevice8W *iface, LONG device_gain ); HRESULT (*send_device_gain)( IDirectInputDevice8W *iface, LONG device_gain );
HRESULT (*enum_created_effect_objects)( IDirectInputDevice8W *iface, LPDIENUMCREATEDEFFECTOBJECTSCALLBACK callback, HRESULT (*enum_created_effect_objects)( IDirectInputDevice8W *iface, LPDIENUMCREATEDEFFECTOBJECTSCALLBACK callback,
void *context, DWORD flags ); void *context, DWORD flags );

View File

@ -674,11 +674,11 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter,
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
static void set_parameter_value( struct hid_joystick_effect *impl, char *report_buf, static void set_report_value( struct hid_joystick *impl, char *report_buf,
struct hid_value_caps *caps, LONG value ) struct hid_value_caps *caps, LONG value )
{ {
ULONG report_len = impl->joystick->caps.OutputReportByteLength; ULONG report_len = impl->caps.OutputReportByteLength;
PHIDP_PREPARSED_DATA preparsed = impl->joystick->preparsed; PHIDP_PREPARSED_DATA preparsed = impl->preparsed;
LONG log_min, log_max, phy_min, phy_max; LONG log_min, log_max, phy_min, phy_max;
NTSTATUS status; NTSTATUS status;
@ -819,9 +819,23 @@ static void set_extra_caps_range( struct hid_joystick *impl, const DIDEVICEOBJEC
static HRESULT hid_joystick_send_device_gain( IDirectInputDevice8W *iface, LONG device_gain ) static HRESULT hid_joystick_send_device_gain( IDirectInputDevice8W *iface, LONG device_gain )
{ {
FIXME( "iface %p stub!\n", iface ); struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
struct pid_device_gain *report = &impl->pid_device_gain;
ULONG report_len = impl->caps.OutputReportByteLength;
char *report_buf = impl->output_report_buf;
NTSTATUS status;
return DIERR_UNSUPPORTED; TRACE( "iface %p.\n", iface );
if (!report->id || !report->device_gain_caps) return DI_OK;
status = HidP_InitializeReportForID( HidP_Output, report->id, impl->preparsed, report_buf, report_len );
if (status != HIDP_STATUS_SUCCESS) return status;
set_report_value( impl, report_buf, report->device_gain_caps, device_gain );
if (!WriteFile( impl->device, report_buf, report_len, NULL, NULL )) return DIERR_INPUTLOST;
return DI_OK;
} }
static HRESULT hid_joystick_set_property( IDirectInputDevice8W *iface, DWORD property, static HRESULT hid_joystick_set_property( IDirectInputDevice8W *iface, DWORD property,
@ -884,6 +898,8 @@ static HRESULT hid_joystick_acquire( IDirectInputDevice8W *iface )
return DI_OK; return DI_OK;
} }
static HRESULT hid_joystick_send_force_feedback_command( IDirectInputDevice8W *iface, DWORD command, BOOL unacquire );
static HRESULT hid_joystick_unacquire( IDirectInputDevice8W *iface ) static HRESULT hid_joystick_unacquire( IDirectInputDevice8W *iface )
{ {
struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
@ -895,7 +911,9 @@ static HRESULT hid_joystick_unacquire( IDirectInputDevice8W *iface )
if (!ret) WARN( "CancelIoEx failed, last error %u\n", GetLastError() ); if (!ret) WARN( "CancelIoEx failed, last error %u\n", GetLastError() );
else WaitForSingleObject( impl->base.read_event, INFINITE ); else WaitForSingleObject( impl->base.read_event, INFINITE );
IDirectInputDevice8_SendForceFeedbackCommand( iface, DISFFC_RESET ); if (!(impl->base.caps.dwFlags & DIDC_FORCEFEEDBACK)) return DI_OK;
if (!impl->base.acquired || !(impl->base.dwCoopLevel & DISCL_EXCLUSIVE)) return DI_OK;
hid_joystick_send_force_feedback_command( iface, DISFFC_RESET, TRUE );
return DI_OK; return DI_OK;
} }
@ -1027,7 +1045,7 @@ static BOOL CALLBACK unload_effect_object( IDirectInputEffect *effect, void *con
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
static HRESULT hid_joystick_send_force_feedback_command( IDirectInputDevice8W *iface, DWORD command ) static HRESULT hid_joystick_send_force_feedback_command( IDirectInputDevice8W *iface, DWORD command, BOOL unacquire )
{ {
struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
struct pid_control_report *report = &impl->pid_device_control; struct pid_control_report *report = &impl->pid_device_control;
@ -1060,6 +1078,8 @@ static HRESULT hid_joystick_send_force_feedback_command( IDirectInputDevice8W *i
if (status != HIDP_STATUS_SUCCESS) return status; if (status != HIDP_STATUS_SUCCESS) return status;
if (!WriteFile( impl->device, report_buf, report_len, NULL, NULL )) return DIERR_INPUTLOST; if (!WriteFile( impl->device, report_buf, report_len, NULL, NULL )) return DIERR_INPUTLOST;
if (!unacquire) hid_joystick_send_device_gain( iface, impl->base.device_gain );
return DI_OK; return DI_OK;
} }
@ -2655,6 +2675,12 @@ static HRESULT WINAPI hid_joystick_effect_GetEffectStatus( IDirectInputEffect *i
return DIERR_UNSUPPORTED; return DIERR_UNSUPPORTED;
} }
static void set_parameter_value( struct hid_joystick_effect *impl, char *report_buf,
struct hid_value_caps *caps, LONG value )
{
return set_report_value( impl->joystick, report_buf, caps, value );
}
static void set_parameter_value_us( struct hid_joystick_effect *impl, char *report_buf, static void set_parameter_value_us( struct hid_joystick_effect *impl, char *report_buf,
struct hid_value_caps *caps, LONG value ) struct hid_value_caps *caps, LONG value )
{ {

View File

@ -754,15 +754,7 @@ static BOOL sync_ioctl( HANDLE file, DWORD code, void *in_buf, DWORD in_len, voi
if (!ret && GetLastError() == ERROR_IO_PENDING) if (!ret && GetLastError() == ERROR_IO_PENDING)
{ {
ret = GetOverlappedResultEx( file, &ovl, &out_len, timeout, TRUE ); ret = GetOverlappedResultEx( file, &ovl, &out_len, timeout, TRUE );
todo_wine_if( timeout != INFINITE )
ok( ret, "GetOverlappedResultEx returned %u\n", GetLastError() ); ok( ret, "GetOverlappedResultEx returned %u\n", GetLastError() );
if (!ret)
{
ret = CancelIoEx( file, &ovl );
ok( ret, "CancelIoEx returned %u\n", GetLastError() );
ret = WaitForSingleObject( ovl.hEvent, INFINITE );
ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
}
} }
CloseHandle( ovl.hEvent ); CloseHandle( ovl.hEvent );
@ -793,7 +785,6 @@ static void set_hid_expect_( int line, HANDLE file, struct hid_expect *expect, D
static void wait_hid_expect_( int line, HANDLE file, DWORD timeout ) static void wait_hid_expect_( int line, HANDLE file, DWORD timeout )
{ {
BOOL ret = sync_ioctl( file, IOCTL_WINETEST_HID_WAIT_EXPECT, NULL, 0, NULL, 0, timeout ); BOOL ret = sync_ioctl( file, IOCTL_WINETEST_HID_WAIT_EXPECT, NULL, 0, NULL, 0, timeout );
todo_wine
ok( ret, "IOCTL_WINETEST_HID_WAIT_EXPECT failed, last error %u\n", GetLastError() ); ok( ret, "IOCTL_WINETEST_HID_WAIT_EXPECT failed, last error %u\n", GetLastError() );
set_hid_expect( file, NULL, 0 ); set_hid_expect( file, NULL, 0 );
@ -5584,7 +5575,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO
.report_id = 8, .report_id = 8,
.report_len = 2, .report_len = 2,
.report_buf = {8, 0x19}, .report_buf = {8, 0x19},
.todo = TRUE,
}, },
}; };
struct hid_expect expect_reset[] = struct hid_expect expect_reset[] =
@ -6947,7 +6937,6 @@ static void test_force_feedback_joystick( DWORD version )
.report_id = 8, .report_id = 8,
.report_len = 2, .report_len = 2,
.report_buf = {8, 0x19}, .report_buf = {8, 0x19},
.todo = TRUE,
}, },
}; };
struct hid_expect expect_reset[] = struct hid_expect expect_reset[] =
@ -6965,7 +6954,6 @@ static void test_force_feedback_joystick( DWORD version )
.report_id = 8, .report_id = 8,
.report_len = 2, .report_len = 2,
.report_buf = {8, 0x19}, .report_buf = {8, 0x19},
.todo = TRUE,
}; };
struct hid_expect expect_set_device_gain_2 = struct hid_expect expect_set_device_gain_2 =
{ {
@ -6973,7 +6961,6 @@ static void test_force_feedback_joystick( DWORD version )
.report_id = 8, .report_id = 8,
.report_len = 2, .report_len = 2,
.report_buf = {8, 0x33}, .report_buf = {8, 0x33},
.todo = TRUE,
}; };
const DIDEVICEINSTANCEW expect_devinst = const DIDEVICEINSTANCEW expect_devinst =