diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c index 94343c0927d..9b08528b01b 100644 --- a/dlls/windows.gaming.input/controller.c +++ b/dlls/windows.gaming.input/controller.c @@ -18,11 +18,237 @@ */ #include "private.h" +#include "provider.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(input); +struct controller +{ + IGameControllerImpl IGameControllerImpl_iface; + IGameControllerInputSink IGameControllerInputSink_iface; + IRawGameController IRawGameController_iface; + IGameController *IGameController_outer; + LONG ref; + + IGameControllerProvider *provider; +}; + +static inline struct controller *impl_from_IGameControllerImpl( IGameControllerImpl *iface ) +{ + return CONTAINING_RECORD( iface, struct controller, IGameControllerImpl_iface ); +} + +static HRESULT WINAPI controller_QueryInterface( IGameControllerImpl *iface, REFIID iid, void **out ) +{ + struct controller *impl = impl_from_IGameControllerImpl( 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_IGameControllerImpl )) + { + IInspectable_AddRef( (*out = &impl->IGameControllerImpl_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IGameControllerInputSink )) + { + IInspectable_AddRef( (*out = &impl->IGameControllerInputSink_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IRawGameController )) + { + IInspectable_AddRef( (*out = &impl->IRawGameController_iface) ); + return S_OK; + } + + WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI controller_AddRef( IGameControllerImpl *iface ) +{ + struct controller *impl = impl_from_IGameControllerImpl( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI controller_Release( IGameControllerImpl *iface ) +{ + struct controller *impl = impl_from_IGameControllerImpl( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + IGameControllerProvider_Release( impl->provider ); + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI controller_GetIids( IGameControllerImpl *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 controller_GetRuntimeClassName( IGameControllerImpl *iface, HSTRING *class_name ) +{ + return WindowsCreateString( RuntimeClass_Windows_Gaming_Input_RawGameController, + ARRAY_SIZE(RuntimeClass_Windows_Gaming_Input_RawGameController), + class_name ); +} + +static HRESULT WINAPI controller_GetTrustLevel( IGameControllerImpl *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_Initialize( IGameControllerImpl *iface, IGameController *outer, + IGameControllerProvider *provider ) +{ + struct controller *impl = impl_from_IGameControllerImpl( iface ); + + TRACE( "iface %p, outer %p, provider %p.\n", iface, outer, provider ); + + impl->IGameController_outer = outer; + IGameControllerProvider_AddRef( (impl->provider = provider) ); + + return S_OK; +} + +static const struct IGameControllerImplVtbl controller_vtbl = +{ + controller_QueryInterface, + controller_AddRef, + controller_Release, + /* IInspectable methods */ + controller_GetIids, + controller_GetRuntimeClassName, + controller_GetTrustLevel, + /* IGameControllerImpl methods */ + controller_Initialize, +}; + +DEFINE_IINSPECTABLE_OUTER( input_sink, IGameControllerInputSink, struct controller, IGameController_outer ) + +static HRESULT WINAPI input_sink_OnInputResumed( IGameControllerInputSink *iface, UINT64 timestamp ) +{ + FIXME( "iface %p, timestamp %I64u stub!\n", iface, timestamp ); + return E_NOTIMPL; +} + +static HRESULT WINAPI input_sink_OnInputSuspended( IGameControllerInputSink *iface, UINT64 timestamp ) +{ + FIXME( "iface %p, timestamp %I64u stub!\n", iface, timestamp ); + return E_NOTIMPL; +} + +static const struct IGameControllerInputSinkVtbl input_sink_vtbl = +{ + input_sink_QueryInterface, + input_sink_AddRef, + input_sink_Release, + /* IInspectable methods */ + input_sink_GetIids, + input_sink_GetRuntimeClassName, + input_sink_GetTrustLevel, + /* IGameControllerInputSink methods */ + input_sink_OnInputResumed, + input_sink_OnInputSuspended, +}; + +DEFINE_IINSPECTABLE_OUTER( raw_controller, IRawGameController, struct controller, IGameController_outer ) + +static HRESULT WINAPI raw_controller_get_AxisCount( IRawGameController *iface, INT32 *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI raw_controller_get_ButtonCount( IRawGameController *iface, INT32 *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI raw_controller_get_ForceFeedbackMotors( IRawGameController *iface, IVectorView_ForceFeedbackMotor **value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI raw_controller_get_HardwareProductId( IRawGameController *iface, UINT16 *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI raw_controller_get_HardwareVendorId( IRawGameController *iface, UINT16 *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI raw_controller_get_SwitchCount( IRawGameController *iface, INT32 *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI raw_controller_GetButtonLabel( IRawGameController *iface, INT32 index, + enum GameControllerButtonLabel *value ) +{ + FIXME( "iface %p, index %d, value %p stub!\n", iface, index, value ); + return E_NOTIMPL; +} + +static HRESULT WINAPI raw_controller_GetCurrentReading( IRawGameController *iface, UINT32 buttons_size, BOOLEAN *buttons, + UINT32 switches_size, enum GameControllerSwitchPosition *switches, + UINT32 axes_size, DOUBLE *axes, UINT64 *timestamp ) +{ + FIXME( "iface %p, buttons_size %u, buttons %p, switches_size %u, switches %p, axes_size %u, axes %p, timestamp %p stub!\n", + iface, buttons_size, buttons, switches_size, switches, axes_size, axes, timestamp ); + return E_NOTIMPL; +} + +static HRESULT WINAPI raw_controller_GetSwitchKind( IRawGameController *iface, INT32 index, enum GameControllerSwitchKind *value ) +{ + FIXME( "iface %p, index %d, value %p stub!\n", iface, index, value ); + return E_NOTIMPL; +} + +static const struct IRawGameControllerVtbl raw_controller_vtbl = +{ + raw_controller_QueryInterface, + raw_controller_AddRef, + raw_controller_Release, + /* IInspectable methods */ + raw_controller_GetIids, + raw_controller_GetRuntimeClassName, + raw_controller_GetTrustLevel, + /* IRawGameController methods */ + raw_controller_get_AxisCount, + raw_controller_get_ButtonCount, + raw_controller_get_ForceFeedbackMotors, + raw_controller_get_HardwareProductId, + raw_controller_get_HardwareVendorId, + raw_controller_get_SwitchCount, + raw_controller_GetButtonLabel, + raw_controller_GetCurrentReading, + raw_controller_GetSwitchKind, +}; + struct controller_statics { IActivationFactory IActivationFactory_iface; @@ -213,8 +439,20 @@ DEFINE_IINSPECTABLE( controller_factory, ICustomGameControllerFactory, struct co static HRESULT WINAPI controller_factory_CreateGameController( ICustomGameControllerFactory *iface, IGameControllerProvider *provider, IInspectable **value ) { - FIXME( "iface %p, provider %p, value %p stub!\n", iface, provider, value ); - return E_NOTIMPL; + struct controller *impl; + + TRACE( "iface %p, provider %p, value %p.\n", iface, provider, value ); + + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + impl->IGameControllerImpl_iface.lpVtbl = &controller_vtbl; + impl->IGameControllerInputSink_iface.lpVtbl = &input_sink_vtbl; + impl->IRawGameController_iface.lpVtbl = &raw_controller_vtbl; + impl->ref = 1; + + TRACE( "created RawGameController %p\n", impl ); + + *value = (IInspectable *)&impl->IGameControllerImpl_iface; + return S_OK; } static HRESULT WINAPI controller_factory_OnGameControllerAdded( ICustomGameControllerFactory *iface, IGameController *value ) diff --git a/dlls/windows.gaming.input/manager.c b/dlls/windows.gaming.input/manager.c index f5b5654a4c6..489588a68ab 100644 --- a/dlls/windows.gaming.input/manager.c +++ b/dlls/windows.gaming.input/manager.c @@ -40,6 +40,7 @@ struct controller { IGameController IGameController_iface; IGameControllerBatteryInfo IGameControllerBatteryInfo_iface; + IInspectable *IInspectable_inner; LONG ref; struct list entry; @@ -73,9 +74,7 @@ static HRESULT WINAPI controller_QueryInterface( IGameController *iface, REFIID return S_OK; } - FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); - *out = NULL; - return E_NOINTERFACE; + return IInspectable_QueryInterface( impl->IInspectable_inner, iid, out ); } static ULONG WINAPI controller_AddRef( IGameController *iface ) @@ -95,6 +94,9 @@ static ULONG WINAPI controller_Release( IGameController *iface ) if (!ref) { + /* guard against re-entry if inner releases an outer iface */ + InterlockedIncrement( &impl->ref ); + IInspectable_Release( impl->IInspectable_inner ); ICustomGameControllerFactory_Release( impl->factory ); IGameControllerProvider_Release( impl->provider ); free( impl ); @@ -111,14 +113,14 @@ static HRESULT WINAPI controller_GetIids( IGameController *iface, ULONG *iid_cou static HRESULT WINAPI controller_GetRuntimeClassName( IGameController *iface, HSTRING *class_name ) { - FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); - return E_NOTIMPL; + struct controller *impl = impl_from_IGameController( iface ); + return IInspectable_GetRuntimeClassName( impl->IInspectable_inner, class_name ); } static HRESULT WINAPI controller_GetTrustLevel( IGameController *iface, TrustLevel *trust_level ) { - FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); - return E_NOTIMPL; + struct controller *impl = impl_from_IGameController( iface ); + return IInspectable_GetTrustLevel( impl->IInspectable_inner, trust_level ); } static HRESULT WINAPI controller_add_HeadsetConnected( IGameController *iface, ITypedEventHandler_IGameController_Headset *handler, @@ -421,13 +423,33 @@ IGameControllerFactoryManagerStatics2 *manager_factory = &manager_statics.IGameC static HRESULT controller_create( ICustomGameControllerFactory *factory, IGameControllerProvider *provider, struct controller **out ) { + IGameControllerImpl *inner_impl; struct controller *impl; + HRESULT hr; if (!(impl = malloc(sizeof(*impl)))) return E_OUTOFMEMORY; impl->IGameController_iface.lpVtbl = &controller_vtbl; impl->IGameControllerBatteryInfo_iface.lpVtbl = &battery_vtbl; impl->ref = 1; + if (FAILED(hr = ICustomGameControllerFactory_CreateGameController( factory, provider, &impl->IInspectable_inner ))) + WARN( "Failed to create game controller, hr %#lx\n", hr ); + else if (FAILED(hr = IInspectable_QueryInterface( impl->IInspectable_inner, &IID_IGameControllerImpl, (void **)&inner_impl ))) + WARN( "Failed to find IGameControllerImpl iface, hr %#lx\n", hr ); + else + { + if (FAILED(hr = IGameControllerImpl_Initialize( inner_impl, &impl->IGameController_iface, provider ))) + WARN( "Failed to initialize game controller, hr %#lx\n", hr ); + IGameControllerImpl_Release( inner_impl ); + } + + if (FAILED(hr)) + { + if (impl->IInspectable_inner) IInspectable_Release( impl->IInspectable_inner ); + free( impl ); + return hr; + } + ICustomGameControllerFactory_AddRef( (impl->factory = factory) ); IGameControllerProvider_AddRef( (impl->provider = provider) ); diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index 56d03abad44..e3da45621b4 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -49,38 +49,42 @@ extern void provider_remove( const WCHAR *device_path ); extern void manager_on_provider_created( IGameControllerProvider *provider ); extern void manager_on_provider_removed( IGameControllerProvider *provider ); -#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ - static inline impl_type *impl_from_##iface_type( iface_type *iface ) \ +#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ + static inline impl_type *impl_from( iface_type *iface ) \ { \ - return CONTAINING_RECORD( iface, impl_type, iface_type##_iface ); \ + return CONTAINING_RECORD( iface, impl_type, iface_mem ); \ } \ static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ { \ - impl_type *impl = impl_from_##iface_type( iface ); \ - return IInspectable_QueryInterface( (IInspectable *)&impl->base_iface, iid, out ); \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \ } \ static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ { \ - impl_type *impl = impl_from_##iface_type( iface ); \ - return IInspectable_AddRef( (IInspectable *)&impl->base_iface ); \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_AddRef( (IInspectable *)(expr) ); \ } \ static ULONG WINAPI pfx##_Release( iface_type *iface ) \ { \ - impl_type *impl = impl_from_##iface_type( iface ); \ - return IInspectable_Release( (IInspectable *)&impl->base_iface ); \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_Release( (IInspectable *)(expr) ); \ } \ static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ { \ - impl_type *impl = impl_from_##iface_type( iface ); \ - return IInspectable_GetIids( (IInspectable *)&impl->base_iface, iid_count, iids ); \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \ } \ static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ { \ - impl_type *impl = impl_from_##iface_type( iface ); \ - return IInspectable_GetRuntimeClassName( (IInspectable *)&impl->base_iface, class_name ); \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \ } \ static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ { \ - impl_type *impl = impl_from_##iface_type( iface ); \ - return IInspectable_GetTrustLevel( (IInspectable *)&impl->base_iface, trust_level ); \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \ } +#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface ) +#define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, impl->outer_iface )