windows.gaming.input: Implement IForceFeedbackEffect interface for ConstantForceEffect.

Using COM aggregation and a new IWineForceFeedbackEffectImpl interface,
deriving from IUnknown as it is only used internally.

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 2022-04-27 17:45:09 +02:00 committed by Alexandre Julliard
parent aa37aad2c8
commit d5edf656ef
5 changed files with 168 additions and 6 deletions

View File

@ -5628,10 +5628,8 @@ static void test_windows_gaming_input(void)
IActivationFactory_Release( activation_factory );
hr = IInspectable_QueryInterface( tmp_inspectable, &IID_IForceFeedbackEffect, (void **)&effect );
todo_wine
ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
IInspectable_Release( tmp_inspectable );
if (hr != S_OK) goto skip_tests;
hr = IForceFeedbackEffect_QueryInterface( effect, &IID_IConstantForceEffect, (void **)&constant_effect );
ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
@ -5670,6 +5668,7 @@ static void test_windows_gaming_input(void)
hr = IForceFeedbackMotor_LoadEffectAsync( motor, effect, &result_async );
todo_wine
ok( hr == S_OK, "LoadEffectAsync returned %#lx\n", hr );
if (hr != S_OK) goto skip_tests;
result_async_handler = default_result_async_handler;
result_async_handler.event = CreateEventW( NULL, FALSE, FALSE, NULL );
ok( !!result_async_handler.event, "CreateEventW failed, error %lu\n", GetLastError() );

View File

@ -25,6 +25,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(input);
struct constant_effect
{
IConstantForceEffect IConstantForceEffect_iface;
IWineForceFeedbackEffectImpl *IWineForceFeedbackEffectImpl_inner;
LONG ref;
};
@ -48,9 +49,7 @@ static HRESULT WINAPI effect_QueryInterface( IConstantForceEffect *iface, REFIID
return S_OK;
}
FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
*out = NULL;
return E_NOINTERFACE;
return IWineForceFeedbackEffectImpl_QueryInterface( impl->IWineForceFeedbackEffectImpl_inner, iid, out );
}
static ULONG WINAPI effect_AddRef( IConstantForceEffect *iface )
@ -68,7 +67,13 @@ static ULONG WINAPI effect_Release( IConstantForceEffect *iface )
TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
if (!ref) free( impl );
if (!ref)
{
/* guard against re-entry if inner releases an outer iface */
InterlockedIncrement( &impl->ref );
IWineForceFeedbackEffectImpl_Release( impl->IWineForceFeedbackEffectImpl_inner );
free( impl );
}
return ref;
}
@ -192,6 +197,7 @@ static HRESULT WINAPI activation_GetTrustLevel( IActivationFactory *iface, Trust
static HRESULT WINAPI activation_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
{
struct constant_effect *impl;
HRESULT hr;
TRACE( "iface %p, instance %p.\n", iface, instance );
@ -199,6 +205,13 @@ static HRESULT WINAPI activation_ActivateInstance( IActivationFactory *iface, II
impl->IConstantForceEffect_iface.lpVtbl = &effect_vtbl;
impl->ref = 1;
if (FAILED(hr = force_feedback_effect_create( (IInspectable *)&impl->IConstantForceEffect_iface,
&impl->IWineForceFeedbackEffectImpl_inner )))
{
free( impl );
return hr;
}
*instance = (IInspectable *)&impl->IConstantForceEffect_iface;
TRACE( "created ConstantForceEffect %p\n", *instance );
return S_OK;

View File

@ -27,6 +27,139 @@
WINE_DEFAULT_DEBUG_CHANNEL(input);
struct effect
{
IWineForceFeedbackEffectImpl IWineForceFeedbackEffectImpl_iface;
IForceFeedbackEffect IForceFeedbackEffect_iface;
IInspectable *IInspectable_outer;
LONG ref;
};
static inline struct effect *impl_from_IWineForceFeedbackEffectImpl( IWineForceFeedbackEffectImpl *iface )
{
return CONTAINING_RECORD( iface, struct effect, IWineForceFeedbackEffectImpl_iface );
}
static HRESULT WINAPI effect_impl_QueryInterface( IWineForceFeedbackEffectImpl *iface, REFIID iid, void **out )
{
struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( 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_IWineForceFeedbackEffectImpl ))
{
IWineForceFeedbackEffectImpl_AddRef( (*out = &impl->IWineForceFeedbackEffectImpl_iface) );
return S_OK;
}
if (IsEqualGUID( iid, &IID_IForceFeedbackEffect ))
{
IInspectable_AddRef( (*out = &impl->IForceFeedbackEffect_iface) );
return S_OK;
}
FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
*out = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI effect_impl_AddRef( IWineForceFeedbackEffectImpl *iface )
{
struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface );
ULONG ref = InterlockedIncrement( &impl->ref );
TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
return ref;
}
static ULONG WINAPI effect_impl_Release( IWineForceFeedbackEffectImpl *iface )
{
struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface );
ULONG ref = InterlockedDecrement( &impl->ref );
TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
if (!ref) free( impl );
return ref;
}
static const struct IWineForceFeedbackEffectImplVtbl effect_impl_vtbl =
{
effect_impl_QueryInterface,
effect_impl_AddRef,
effect_impl_Release,
/* IWineForceFeedbackEffectImpl methods */
};
DEFINE_IINSPECTABLE_OUTER( effect, IForceFeedbackEffect, struct effect, IInspectable_outer )
static HRESULT WINAPI effect_get_Gain( IForceFeedbackEffect *iface, DOUBLE *value )
{
FIXME( "iface %p, value %p stub!\n", iface, value );
return E_NOTIMPL;
}
static HRESULT WINAPI effect_put_Gain( IForceFeedbackEffect *iface, DOUBLE value )
{
FIXME( "iface %p, value %f stub!\n", iface, value );
return E_NOTIMPL;
}
static HRESULT WINAPI effect_get_State( IForceFeedbackEffect *iface, ForceFeedbackEffectState *value )
{
FIXME( "iface %p, value %p stub!\n", iface, value );
return E_NOTIMPL;
}
static HRESULT WINAPI effect_Start( IForceFeedbackEffect *iface )
{
FIXME( "iface %p stub!\n", iface );
return E_NOTIMPL;
}
static HRESULT WINAPI effect_Stop( IForceFeedbackEffect *iface )
{
FIXME( "iface %p stub!\n", iface );
return E_NOTIMPL;
}
static const struct IForceFeedbackEffectVtbl effect_vtbl =
{
effect_QueryInterface,
effect_AddRef,
effect_Release,
/* IInspectable methods */
effect_GetIids,
effect_GetRuntimeClassName,
effect_GetTrustLevel,
/* IForceFeedbackEffect methods */
effect_get_Gain,
effect_put_Gain,
effect_get_State,
effect_Start,
effect_Stop,
};
HRESULT force_feedback_effect_create( IInspectable *outer, IWineForceFeedbackEffectImpl **out )
{
struct effect *impl;
TRACE( "outer %p, out %p\n", outer, out );
if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
impl->IWineForceFeedbackEffectImpl_iface.lpVtbl = &effect_impl_vtbl;
impl->IForceFeedbackEffect_iface.lpVtbl = &effect_vtbl;
impl->IInspectable_outer = outer;
impl->ref = 1;
*out = &impl->IWineForceFeedbackEffectImpl_iface;
TRACE( "created ForceFeedbackEffect %p\n", *out );
return S_OK;
}
struct motor
{
IForceFeedbackMotor IForceFeedbackMotor_iface;

View File

@ -42,6 +42,8 @@
#include "wine/debug.h"
#include "wine/list.h"
#include "provider.h"
extern HINSTANCE windows_gaming_input;
extern ICustomGameControllerFactory *controller_factory;
extern ICustomGameControllerFactory *gamepad_factory;
@ -69,6 +71,7 @@ extern HRESULT event_handlers_remove( struct list *list, EventRegistrationToken
extern void event_handlers_notify( struct list *list, IInspectable *element );
extern HRESULT force_feedback_motor_create( IDirectInputDevice8W *device, IForceFeedbackMotor **out );
extern HRESULT force_feedback_effect_create( IInspectable *outer, IWineForceFeedbackEffectImpl **out );
typedef HRESULT (WINAPI *async_operation_callback)( IUnknown *invoker, IUnknown *param, PROPVARIANT *result );
extern HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback,

View File

@ -34,6 +34,7 @@ import "windows.gaming.input.forcefeedback.idl";
namespace Windows.Gaming.Input.Custom {
typedef enum WineGameControllerType WineGameControllerType;
typedef enum WineForceFeedbackEffectType WineForceFeedbackEffectType;
typedef struct WineGameControllerState WineGameControllerState;
typedef struct WineGameControllerVibration WineGameControllerVibration;
interface IWineGameControllerProvider;
@ -49,6 +50,11 @@ namespace Windows.Gaming.Input.Custom {
RacingWheel = 2,
};
enum WineForceFeedbackEffectType
{
Constant = 1,
};
struct WineGameControllerState
{
UINT64 timestamp;
@ -94,6 +100,14 @@ namespace Windows.Gaming.Input.Custom {
[propget] HRESULT ForceFeedbackMotor([out, retval] Windows.Gaming.Input.ForceFeedback.ForceFeedbackMotor **motor);
}
[
uuid(27833469-7760-417e-adbe-e011a66e16ee)
]
interface IWineForceFeedbackEffectImpl : IUnknown
requires Windows.Gaming.Input.ForceFeedback.IForceFeedbackEffect
{
}
[
uuid(83f377ee-c799-11ec-9d64-0242ac120002)
]