From 4e04446c9b8721acb0098ff4a0b303923398ea21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 12 May 2022 12:04:29 +0200 Subject: [PATCH] windows.gaming.input: Implement Windows.Gaming.Input.ConditionForceEffect runtimeclass. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Bernon Signed-off-by: Alexandre Julliard --- dlls/dinput/tests/force_feedback.c | 3 - dlls/windows.gaming.input/Makefile.in | 1 + dlls/windows.gaming.input/condition_effect.c | 272 +++++++++++++++++++ dlls/windows.gaming.input/force_feedback.c | 18 ++ dlls/windows.gaming.input/main.c | 2 + dlls/windows.gaming.input/private.h | 1 + dlls/windows.gaming.input/provider.idl | 7 + 7 files changed, 301 insertions(+), 3 deletions(-) create mode 100644 dlls/windows.gaming.input/condition_effect.c diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 0ad85ba0cf4..696828df3fc 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -6197,10 +6197,8 @@ static void test_windows_gaming_input(void) hr = pWindowsCreateString( condition_effect_class_name, wcslen( condition_effect_class_name ), &str ); ok( hr == S_OK, "WindowsCreateString returned %#lx\n", hr ); hr = pRoGetActivationFactory( str, &IID_IConditionForceEffectFactory, (void **)&condition_factory ); - todo_wine ok( hr == S_OK, "RoGetActivationFactory returned %#lx\n", hr ); pWindowsDeleteString( str ); - if (hr != S_OK) goto skip_condition; check_interface( condition_factory, &IID_IUnknown, TRUE ); check_interface( condition_factory, &IID_IInspectable, TRUE ); @@ -6296,7 +6294,6 @@ static void test_windows_gaming_input(void) IConditionForceEffectFactory_Release( condition_factory ); -skip_condition: hr = pWindowsCreateString( constant_effect_class_name, wcslen( constant_effect_class_name ), &str ); ok( hr == S_OK, "WindowsCreateString returned %#lx\n", hr ); hr = pRoGetActivationFactory( str, &IID_IActivationFactory, (void **)&activation_factory ); diff --git a/dlls/windows.gaming.input/Makefile.in b/dlls/windows.gaming.input/Makefile.in index 3535b8ab365..3ec3dd0d864 100644 --- a/dlls/windows.gaming.input/Makefile.in +++ b/dlls/windows.gaming.input/Makefile.in @@ -3,6 +3,7 @@ IMPORTS = combase uuid user32 dinput8 setupapi hid C_SRCS = \ async.c \ + condition_effect.c \ constant_effect.c \ controller.c \ event_handlers.c \ diff --git a/dlls/windows.gaming.input/condition_effect.c b/dlls/windows.gaming.input/condition_effect.c new file mode 100644 index 00000000000..dccc50bb48f --- /dev/null +++ b/dlls/windows.gaming.input/condition_effect.c @@ -0,0 +1,272 @@ +/* WinRT Windows.Gaming.Input implementation + * + * Copyright 2022 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 "private.h" +#include "provider.h" + +WINE_DEFAULT_DEBUG_CHANNEL(input); + +struct condition_effect +{ + IConditionForceEffect IConditionForceEffect_iface; + IWineForceFeedbackEffectImpl *IWineForceFeedbackEffectImpl_inner; + LONG ref; + + ConditionForceEffectKind kind; +}; + +static inline struct condition_effect *impl_from_IConditionForceEffect( IConditionForceEffect *iface ) +{ + return CONTAINING_RECORD( iface, struct condition_effect, IConditionForceEffect_iface ); +} + +static HRESULT WINAPI effect_QueryInterface( IConditionForceEffect *iface, REFIID iid, void **out ) +{ + struct condition_effect *impl = impl_from_IConditionForceEffect( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IConditionForceEffect )) + { + IInspectable_AddRef( (*out = &impl->IConditionForceEffect_iface) ); + return S_OK; + } + + return IWineForceFeedbackEffectImpl_QueryInterface( impl->IWineForceFeedbackEffectImpl_inner, iid, out ); +} + +static ULONG WINAPI effect_AddRef( IConditionForceEffect *iface ) +{ + struct condition_effect *impl = impl_from_IConditionForceEffect( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI effect_Release( IConditionForceEffect *iface ) +{ + struct condition_effect *impl = impl_from_IConditionForceEffect( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + /* guard against re-entry if inner releases an outer iface */ + InterlockedIncrement( &impl->ref ); + IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI effect_GetIids( IConditionForceEffect *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_GetRuntimeClassName( IConditionForceEffect *iface, HSTRING *class_name ) +{ + return WindowsCreateString( RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConditionForceEffect, + ARRAY_SIZE(RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConditionForceEffect), + class_name ); +} + +static HRESULT WINAPI effect_GetTrustLevel( IConditionForceEffect *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI effect_get_Kind( IConditionForceEffect *iface, ConditionForceEffectKind *kind ) +{ + struct condition_effect *impl = impl_from_IConditionForceEffect( iface ); + TRACE( "iface %p, kind %p.\n", iface, kind ); + *kind = impl->kind; + return S_OK; +} + +static HRESULT WINAPI effect_SetParameters( IConditionForceEffect *iface, Vector3 direction, FLOAT positive_coeff, FLOAT negative_coeff, + FLOAT max_positive_magnitude, FLOAT max_negative_magnitude, FLOAT deadzone, FLOAT bias ) +{ + FIXME( "iface %p, direction %s, positive_coeff %f, negative_coeff %f, max_positive_magnitude %f, max_negative_magnitude %f, deadzone %f, bias %f stub!\n", + iface, debugstr_vector3( &direction ), positive_coeff, negative_coeff, max_positive_magnitude, max_negative_magnitude, deadzone, bias ); + + return E_NOTIMPL; +} + +static const struct IConditionForceEffectVtbl effect_vtbl = +{ + effect_QueryInterface, + effect_AddRef, + effect_Release, + /* IInspectable methods */ + effect_GetIids, + effect_GetRuntimeClassName, + effect_GetTrustLevel, + /* IConditionForceEffect methods */ + effect_get_Kind, + effect_SetParameters, +}; + +struct condition_factory +{ + IActivationFactory IActivationFactory_iface; + IConditionForceEffectFactory IConditionForceEffectFactory_iface; + LONG ref; +}; + +static inline struct condition_factory *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct condition_factory, IActivationFactory_iface ); +} + +static HRESULT WINAPI activation_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct condition_factory *impl = impl_from_IActivationFactory( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IActivationFactory )) + { + IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IConditionForceEffectFactory )) + { + IInspectable_AddRef( (*out = &impl->IConditionForceEffectFactory_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI activation_AddRef( IActivationFactory *iface ) +{ + struct condition_factory *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI activation_Release( IActivationFactory *iface ) +{ + struct condition_factory *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI activation_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) +{ + FIXME( "iface %p, instance %p stub!\n", iface, instance ); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl activation_vtbl = +{ + activation_QueryInterface, + activation_AddRef, + activation_Release, + /* IInspectable methods */ + activation_GetIids, + activation_GetRuntimeClassName, + activation_GetTrustLevel, + /* IActivationFactory methods */ + activation_ActivateInstance, +}; + +DEFINE_IINSPECTABLE( factory, IConditionForceEffectFactory, struct condition_factory, IActivationFactory_iface ) + +static HRESULT WINAPI factory_CreateInstance( IConditionForceEffectFactory *iface, enum ConditionForceEffectKind kind, IForceFeedbackEffect **out ) +{ + enum WineForceFeedbackEffectType type = WineForceFeedbackEffectType_Condition + kind; + struct condition_effect *impl; + HRESULT hr; + + TRACE( "iface %p, kind %u, out %p.\n", iface, kind, out ); + + if (!(impl = calloc( 1, sizeof(struct condition_effect) ))) return E_OUTOFMEMORY; + impl->IConditionForceEffect_iface.lpVtbl = &effect_vtbl; + impl->ref = 1; + impl->kind = kind; + + if (FAILED(hr = force_feedback_effect_create( type, (IInspectable *)&impl->IConditionForceEffect_iface, &impl->IWineForceFeedbackEffectImpl_inner )) || + FAILED(hr = IConditionForceEffect_QueryInterface( &impl->IConditionForceEffect_iface, &IID_IForceFeedbackEffect, (void **)out ))) + { + if (impl->IWineForceFeedbackEffectImpl_inner) IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner ); + free( impl ); + return hr; + } + + IConditionForceEffect_Release( &impl->IConditionForceEffect_iface ); + TRACE( "created ConditionForceEffect %p\n", *out ); + return S_OK; +} + +static const struct IConditionForceEffectFactoryVtbl factory_vtbl = +{ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IInspectable methods */ + factory_GetIids, + factory_GetRuntimeClassName, + factory_GetTrustLevel, + /* IConditionForceEffectFactory methods */ + factory_CreateInstance, +}; + +static struct condition_factory condition_statics = +{ + {&activation_vtbl}, + {&factory_vtbl}, + 1, +}; + +IInspectable *condition_effect_factory = (IInspectable *)&condition_statics.IActivationFactory_iface; diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index 3621f245d21..f3b5f16f8c0 100644 --- a/dlls/windows.gaming.input/force_feedback.c +++ b/dlls/windows.gaming.input/force_feedback.c @@ -43,6 +43,7 @@ struct effect LONG directions[3]; DICONSTANTFORCE constant_force; DIRAMPFORCE ramp_force; + DICONDITION condition; DIPERIODIC periodic; DIEFFECT params; }; @@ -206,6 +207,23 @@ HRESULT force_feedback_effect_create( enum WineForceFeedbackEffectType type, IIn impl->params.lpvTypeSpecificParams = &impl->periodic; impl->params.cbTypeSpecificParams = sizeof(impl->periodic); break; + + case WineForceFeedbackEffectType_Condition_Spring: + impl->type = GUID_Spring; + goto WineForceFeedbackEffectType_Condition; + case WineForceFeedbackEffectType_Condition_Damper: + impl->type = GUID_Damper; + goto WineForceFeedbackEffectType_Condition; + case WineForceFeedbackEffectType_Condition_Inertia: + impl->type = GUID_Inertia; + goto WineForceFeedbackEffectType_Condition; + case WineForceFeedbackEffectType_Condition_Friction: + impl->type = GUID_Friction; + goto WineForceFeedbackEffectType_Condition; + WineForceFeedbackEffectType_Condition: + impl->params.lpvTypeSpecificParams = &impl->condition; + impl->params.cbTypeSpecificParams = sizeof(impl->condition); + break; } impl->params.dwSize = sizeof(DIEFFECT); diff --git a/dlls/windows.gaming.input/main.c b/dlls/windows.gaming.input/main.c index e5f2f261eb4..a20630cd20b 100644 --- a/dlls/windows.gaming.input/main.c +++ b/dlls/windows.gaming.input/main.c @@ -191,6 +191,8 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory ** IInspectable_QueryInterface( ramp_effect_factory, &IID_IActivationFactory, (void **)factory ); if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_ForceFeedback_PeriodicForceEffect )) IInspectable_QueryInterface( periodic_effect_factory, &IID_IActivationFactory, (void **)factory ); + if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConditionForceEffect )) + IInspectable_QueryInterface( condition_effect_factory, &IID_IActivationFactory, (void **)factory ); if (*factory) return S_OK; return CLASS_E_CLASSNOTAVAILABLE; diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index 915695aa31b..f53d5b5bc37 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -52,6 +52,7 @@ extern IGameControllerFactoryManagerStatics2 *manager_factory; extern IInspectable *constant_effect_factory; extern IInspectable *ramp_effect_factory; extern IInspectable *periodic_effect_factory; +extern IInspectable *condition_effect_factory; struct vector_iids { diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl index 9b9cda0ddc5..128e68893a9 100644 --- a/dlls/windows.gaming.input/provider.idl +++ b/dlls/windows.gaming.input/provider.idl @@ -62,6 +62,13 @@ namespace Windows.Gaming.Input.Custom { Periodic_TriangleWave = 12, Periodic_SawtoothWaveUp = 13, Periodic_SawtoothWaveDown = 14, + + Condition = 20, + /* same order as ConditionForceEffectKind */ + Condition_Spring = 20, + Condition_Damper = 21, + Condition_Inertia = 22, + Condition_Friction = 23, }; struct WineGameControllerState