From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/force_feedback.c | 6 +- dlls/windows.gaming.input/constant_effect.c | 45 +++++++++++++-- dlls/windows.gaming.input/force_feedback.c | 62 +++++++++++++++++++++ dlls/windows.gaming.input/provider.idl | 29 ++++++++++ 4 files changed, 132 insertions(+), 10 deletions(-)
diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 7755cca1927..8d06cdda3d8 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -5557,7 +5557,6 @@ static void test_windows_gaming_input(void) .report_id = 9, .report_len = 4, .report_buf = {9,0x01,0xc8,0x00}, - .todo = TRUE, }, /* set envelope */ { @@ -5565,14 +5564,13 @@ static void test_windows_gaming_input(void) .report_id = 8, .report_len = 8, .report_buf = {8,0x01,0x19,0x4c,0x14,0x00,0x3c,0x00}, - .todo = TRUE, }, /* update effect */ { .code = IOCTL_HID_WRITE_REPORT, .report_id = 3, .report_len = 18, - .report_buf = {3,0x01,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x7f,0x5a,0x00,0x00,0x00}, + .report_buf = {3,0x01,0x04,0x08,0x5a,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0xff,0x7f,0xce,0x00,0x00,0x00}, .wine_only = TRUE, .todo = TRUE, }, @@ -6304,11 +6302,9 @@ static void test_windows_gaming_input(void) ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
hr = IConstantForceEffect_SetParameters( constant_effect, direction, duration ); - todo_wine ok( hr == S_OK, "SetParameters returned %#lx\n", hr ); hr = IConstantForceEffect_SetParametersWithEnvelope( constant_effect, direction, 0.1, 0.2, 0.3, delay, attack_duration, duration, release_duration, 1 ); - todo_wine ok( hr == S_OK, "SetParametersWithEnvelope returned %#lx\n", hr ); IConstantForceEffect_Release( constant_effect );
diff --git a/dlls/windows.gaming.input/constant_effect.c b/dlls/windows.gaming.input/constant_effect.c index 928927144b9..0af5d736f48 100644 --- a/dlls/windows.gaming.input/constant_effect.c +++ b/dlls/windows.gaming.input/constant_effect.c @@ -99,8 +99,21 @@ static HRESULT WINAPI effect_GetTrustLevel( IConstantForceEffect *iface, TrustLe
static HRESULT WINAPI effect_SetParameters( IConstantForceEffect *iface, Vector3 direction, TimeSpan duration ) { - FIXME( "iface %p, direction %s, duration %I64u stub!\n", iface, debugstr_vector3( &direction ), duration.Duration ); - return E_NOTIMPL; + WineForceFeedbackEffectParameters params = + { + .constant = + { + .type = WineForceFeedbackEffectType_Constant, + .direction = direction, + .duration = duration, + .repeat_count = 1, + }, + }; + struct constant_effect *impl = impl_from_IConstantForceEffect( iface ); + + TRACE( "iface %p, direction %s, duration %I64u.\n", iface, debugstr_vector3( &direction ), duration.Duration ); + + return IWineForceFeedbackEffectImpl_put_Parameters( impl->IWineForceFeedbackEffectImpl_inner, params, NULL ); }
static HRESULT WINAPI effect_SetParametersWithEnvelope( IConstantForceEffect *iface, Vector3 direction, FLOAT attack_gain, @@ -108,11 +121,33 @@ static HRESULT WINAPI effect_SetParametersWithEnvelope( IConstantForceEffect *if TimeSpan attack_duration, TimeSpan sustain_duration, TimeSpan release_duration, UINT32 repeat_count ) { - FIXME( "iface %p, direction %s, attack_gain %f, sustain_gain %f, release_gain %f, start_delay %I64u, attack_duration %I64u, " - "sustain_duration %I64u, release_duration %I64u, repeat_count %u stub!\n", iface, debugstr_vector3( &direction ), + WineForceFeedbackEffectParameters params = + { + .constant = + { + .type = WineForceFeedbackEffectType_Constant, + .direction = direction, + .duration = {attack_duration.Duration + sustain_duration.Duration + release_duration.Duration}, + .start_delay = start_delay, + .repeat_count = repeat_count, + .gain = sustain_gain, + }, + }; + WineForceFeedbackEffectEnvelope envelope = + { + .attack_gain = attack_gain, + .release_gain = release_gain, + .attack_duration = attack_duration, + .release_duration = release_duration, + }; + struct constant_effect *impl = impl_from_IConstantForceEffect( iface ); + + TRACE( "iface %p, direction %s, attack_gain %f, sustain_gain %f, release_gain %f, start_delay %I64u, attack_duration %I64u, " + "sustain_duration %I64u, release_duration %I64u, repeat_count %u.\n", iface, debugstr_vector3( &direction ), attack_gain, sustain_gain, release_gain, start_delay.Duration, attack_duration.Duration, sustain_duration.Duration, release_duration.Duration, repeat_count ); - return E_NOTIMPL; + + return IWineForceFeedbackEffectImpl_put_Parameters( impl->IWineForceFeedbackEffectImpl_inner, params, &envelope ); }
static const struct IConstantForceEffectVtbl effect_vtbl = diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index 667174829f5..ce30db14cd9 100644 --- a/dlls/windows.gaming.input/force_feedback.c +++ b/dlls/windows.gaming.input/force_feedback.c @@ -43,10 +43,12 @@ struct effect GUID type; DWORD axes[3]; LONG directions[3]; + ULONG repeat_count; DICONSTANTFORCE constant_force; DIRAMPFORCE ramp_force; DICONDITION condition; DIPERIODIC periodic; + DIENVELOPE envelope; DIEFFECT params; };
@@ -107,12 +109,71 @@ static ULONG WINAPI effect_impl_Release( IWineForceFeedbackEffectImpl *iface ) return ref; }
+static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl *iface, WineForceFeedbackEffectParameters params, + WineForceFeedbackEffectEnvelope *envelope ) +{ + struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface ); + HRESULT hr; + + TRACE( "iface %p, params %p, envelope %p.\n", iface, ¶ms, envelope ); + + EnterCriticalSection( &impl->cs ); + switch (params.type) + { + case WineForceFeedbackEffectType_Constant: + impl->repeat_count = params.constant.repeat_count; + impl->constant_force.lMagnitude = round( params.constant.gain * params.constant.direction.X * 10000 ); + impl->params.dwDuration = params.constant.duration.Duration / 10; + impl->params.dwStartDelay = params.constant.start_delay.Duration / 10; + impl->directions[0] = round( -params.constant.direction.X * 10000 ); + impl->directions[1] = round( -params.constant.direction.Y * 10000 ); + impl->directions[2] = round( -params.constant.direction.Z * 10000 ); + break; + + case WineForceFeedbackEffectType_Ramp: + FIXME("stub!\n"); + break; + + case WineForceFeedbackEffectType_Periodic_SineWave: + case WineForceFeedbackEffectType_Periodic_TriangleWave: + case WineForceFeedbackEffectType_Periodic_SquareWave: + case WineForceFeedbackEffectType_Periodic_SawtoothWaveDown: + case WineForceFeedbackEffectType_Periodic_SawtoothWaveUp: + FIXME("stub!\n"); + break; + + case WineForceFeedbackEffectType_Condition_Spring: + case WineForceFeedbackEffectType_Condition_Damper: + case WineForceFeedbackEffectType_Condition_Inertia: + case WineForceFeedbackEffectType_Condition_Friction: + FIXME("stub!\n"); + break; + } + + if (!envelope) impl->params.lpEnvelope = NULL; + else + { + impl->envelope.dwAttackTime = envelope->attack_duration.Duration / 10; + impl->envelope.dwAttackLevel = round( envelope->attack_gain * 10000 ); + impl->envelope.dwFadeTime = impl->params.dwDuration - envelope->release_duration.Duration / 10; + impl->envelope.dwFadeLevel = round( envelope->release_gain * 10000 ); + impl->params.lpEnvelope = &impl->envelope; + } + + if (!impl->effect) hr = S_OK; + else hr = IDirectInputEffect_SetParameters( impl->effect, &impl->params, DIEP_ALLPARAMS & ~DIEP_AXES ); + LeaveCriticalSection( &impl->cs ); + + return hr; +} + static const struct IWineForceFeedbackEffectImplVtbl effect_impl_vtbl = { effect_impl_QueryInterface, effect_impl_AddRef, effect_impl_Release, /* IWineForceFeedbackEffectImpl methods */ + effect_impl_put_Parameters, };
DEFINE_IINSPECTABLE_OUTER( effect, IForceFeedbackEffect, struct effect, IInspectable_outer ) @@ -245,6 +306,7 @@ HRESULT force_feedback_effect_create( enum WineForceFeedbackEffectType type, IIn break; }
+ impl->envelope.dwSize = sizeof(DIENVELOPE); impl->params.dwSize = sizeof(DIEFFECT); impl->params.rgdwAxes = impl->axes; impl->params.rglDirection = impl->directions; diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl index 128e68893a9..16d394e7afa 100644 --- a/dlls/windows.gaming.input/provider.idl +++ b/dlls/windows.gaming.input/provider.idl @@ -37,6 +37,9 @@ namespace Windows.Gaming.Input.Custom { typedef enum WineForceFeedbackEffectType WineForceFeedbackEffectType; typedef struct WineGameControllerState WineGameControllerState; typedef struct WineGameControllerVibration WineGameControllerVibration; + typedef struct WineConstantEffectParameters WineConstantEffectParameters; + typedef struct WineForceFeedbackEffectEnvelope WineForceFeedbackEffectEnvelope; + typedef union WineForceFeedbackEffectParameters WineForceFeedbackEffectParameters; interface IWineGameControllerProvider; runtimeclass WineGameControllerProvider;
@@ -87,6 +90,30 @@ namespace Windows.Gaming.Input.Custom { UINT16 right; };
+ struct WineConstantEffectParameters + { + WineForceFeedbackEffectType type; + Windows.Foundation.Numerics.Vector3 direction; + Windows.Foundation.TimeSpan duration; + Windows.Foundation.TimeSpan start_delay; + UINT32 repeat_count; + FLOAT gain; + }; + + struct WineForceFeedbackEffectEnvelope + { + FLOAT attack_gain; + FLOAT release_gain; + Windows.Foundation.TimeSpan attack_duration; + Windows.Foundation.TimeSpan release_duration; + }; + + union WineForceFeedbackEffectParameters + { + WineForceFeedbackEffectType type; + WineConstantEffectParameters constant; + }; + [ uuid(06e58977-7684-4dc5-bad1-cda52a4aa06d) ] @@ -122,6 +149,8 @@ namespace Windows.Gaming.Input.Custom { interface IWineForceFeedbackEffectImpl : IUnknown requires Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect { + [propput] HRESULT Parameters([in] WineForceFeedbackEffectParameters parameters, + [in, optional] WineForceFeedbackEffectEnvelope *envelope); }
[