1 /* WinRT Windows.Gaming.Input implementation
3 * Copyright 2021 RĂ©mi Bernon for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(input
);
27 static CRITICAL_SECTION gamepad_cs
;
28 static CRITICAL_SECTION_DEBUG gamepad_cs_debug
=
31 { &gamepad_cs_debug
.ProcessLocksList
, &gamepad_cs_debug
.ProcessLocksList
},
32 0, 0, { (DWORD_PTR
)(__FILE__
": gamepad_cs") }
34 static CRITICAL_SECTION gamepad_cs
= { &gamepad_cs_debug
, -1, 0, 0, 0, 0 };
36 static IVector_Gamepad
*gamepads
;
37 static struct list gamepad_added_handlers
= LIST_INIT( gamepad_added_handlers
);
38 static struct list gamepad_removed_handlers
= LIST_INIT( gamepad_removed_handlers
);
40 static HRESULT
init_gamepads(void)
42 static const struct vector_iids iids
=
44 .vector
= &IID_IVector_Gamepad
,
45 .view
= &IID_IVectorView_Gamepad
,
46 .iterable
= &IID_IIterable_Gamepad
,
47 .iterator
= &IID_IIterator_Gamepad
,
51 EnterCriticalSection( &gamepad_cs
);
52 if (gamepads
) hr
= S_OK
;
53 else hr
= vector_create( &iids
, (void **)&gamepads
);
54 LeaveCriticalSection( &gamepad_cs
);
61 IGameControllerImpl IGameControllerImpl_iface
;
62 IGameControllerInputSink IGameControllerInputSink_iface
;
63 IGamepad IGamepad_iface
;
64 IGamepad2 IGamepad2_iface
;
65 IGameController
*IGameController_outer
;
68 IGameControllerProvider
*provider
;
69 IWineGameControllerProvider
*wine_provider
;
72 static inline struct gamepad
*impl_from_IGameControllerImpl( IGameControllerImpl
*iface
)
74 return CONTAINING_RECORD( iface
, struct gamepad
, IGameControllerImpl_iface
);
77 static HRESULT WINAPI
controller_QueryInterface( IGameControllerImpl
*iface
, REFIID iid
, void **out
)
79 struct gamepad
*impl
= impl_from_IGameControllerImpl( iface
);
81 TRACE( "iface %p, iid %s, out %p.\n", iface
, debugstr_guid( iid
), out
);
83 if (IsEqualGUID( iid
, &IID_IUnknown
) ||
84 IsEqualGUID( iid
, &IID_IInspectable
) ||
85 IsEqualGUID( iid
, &IID_IGameControllerImpl
))
87 IInspectable_AddRef( (*out
= &impl
->IGameControllerImpl_iface
) );
91 if (IsEqualGUID( iid
, &IID_IGameControllerInputSink
))
93 IInspectable_AddRef( (*out
= &impl
->IGameControllerInputSink_iface
) );
97 if (IsEqualGUID( iid
, &IID_IGamepad
))
99 IInspectable_AddRef( (*out
= &impl
->IGamepad_iface
) );
103 if (IsEqualGUID( iid
, &IID_IGamepad2
))
105 IInspectable_AddRef( (*out
= &impl
->IGamepad2_iface
) );
109 FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid
) );
111 return E_NOINTERFACE
;
114 static ULONG WINAPI
controller_AddRef( IGameControllerImpl
*iface
)
116 struct gamepad
*impl
= impl_from_IGameControllerImpl( iface
);
117 ULONG ref
= InterlockedIncrement( &impl
->ref
);
118 TRACE( "iface %p increasing refcount to %lu.\n", iface
, ref
);
122 static ULONG WINAPI
controller_Release( IGameControllerImpl
*iface
)
124 struct gamepad
*impl
= impl_from_IGameControllerImpl( iface
);
125 ULONG ref
= InterlockedDecrement( &impl
->ref
);
127 TRACE( "iface %p decreasing refcount to %lu.\n", iface
, ref
);
131 if (impl
->wine_provider
)
132 IWineGameControllerProvider_Release( impl
->wine_provider
);
133 IGameControllerProvider_Release( impl
->provider
);
140 static HRESULT WINAPI
controller_GetIids( IGameControllerImpl
*iface
, ULONG
*iid_count
, IID
**iids
)
142 FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
146 static HRESULT WINAPI
controller_GetRuntimeClassName( IGameControllerImpl
*iface
, HSTRING
*class_name
)
148 return WindowsCreateString( RuntimeClass_Windows_Gaming_Input_Gamepad
,
149 ARRAY_SIZE(RuntimeClass_Windows_Gaming_Input_Gamepad
),
153 static HRESULT WINAPI
controller_GetTrustLevel( IGameControllerImpl
*iface
, TrustLevel
*trust_level
)
155 FIXME( "iface %p, trust_level %p stub!\n", iface
, trust_level
);
159 static HRESULT WINAPI
controller_Initialize( IGameControllerImpl
*iface
, IGameController
*outer
,
160 IGameControllerProvider
*provider
)
162 struct gamepad
*impl
= impl_from_IGameControllerImpl( iface
);
165 TRACE( "iface %p, outer %p, provider %p.\n", iface
, outer
, provider
);
167 impl
->IGameController_outer
= outer
;
168 IGameControllerProvider_AddRef( (impl
->provider
= provider
) );
170 hr
= IGameControllerProvider_QueryInterface( provider
, &IID_IWineGameControllerProvider
,
171 (void **)&impl
->wine_provider
);
172 if (FAILED(hr
)) return hr
;
174 EnterCriticalSection( &gamepad_cs
);
175 if (SUCCEEDED(hr
= init_gamepads()))
176 hr
= IVector_Gamepad_Append( gamepads
, &impl
->IGamepad_iface
);
177 LeaveCriticalSection( &gamepad_cs
);
182 static const struct IGameControllerImplVtbl controller_vtbl
=
184 controller_QueryInterface
,
187 /* IInspectable methods */
189 controller_GetRuntimeClassName
,
190 controller_GetTrustLevel
,
191 /* IGameControllerImpl methods */
192 controller_Initialize
,
195 DEFINE_IINSPECTABLE_OUTER( input_sink
, IGameControllerInputSink
, struct gamepad
, IGameController_outer
)
197 static HRESULT WINAPI
input_sink_OnInputResumed( IGameControllerInputSink
*iface
, UINT64 timestamp
)
199 FIXME( "iface %p, timestamp %I64u stub!\n", iface
, timestamp
);
203 static HRESULT WINAPI
input_sink_OnInputSuspended( IGameControllerInputSink
*iface
, UINT64 timestamp
)
205 FIXME( "iface %p, timestamp %I64u stub!\n", iface
, timestamp
);
209 static const struct IGameControllerInputSinkVtbl input_sink_vtbl
=
211 input_sink_QueryInterface
,
214 /* IInspectable methods */
216 input_sink_GetRuntimeClassName
,
217 input_sink_GetTrustLevel
,
218 /* IGameControllerInputSink methods */
219 input_sink_OnInputResumed
,
220 input_sink_OnInputSuspended
,
223 DEFINE_IINSPECTABLE_OUTER( gamepad
, IGamepad
, struct gamepad
, IGameController_outer
)
225 static HRESULT WINAPI
gamepad_get_Vibration( IGamepad
*iface
, struct GamepadVibration
*value
)
227 struct gamepad
*impl
= impl_from_IGamepad( iface
);
228 struct WineGameControllerVibration vibration
;
231 TRACE( "iface %p, value %p.\n", iface
, value
);
233 if (FAILED(hr
= IWineGameControllerProvider_get_Vibration( impl
->wine_provider
, &vibration
))) return hr
;
235 value
->LeftMotor
= vibration
.rumble
/ 65535.;
236 value
->RightMotor
= vibration
.buzz
/ 65535.;
237 value
->LeftTrigger
= vibration
.left
/ 65535.;
238 value
->RightTrigger
= vibration
.right
/ 65535.;
243 static HRESULT WINAPI
gamepad_put_Vibration( IGamepad
*iface
, struct GamepadVibration value
)
245 struct gamepad
*impl
= impl_from_IGamepad( iface
);
246 struct WineGameControllerVibration vibration
=
248 .rumble
= value
.LeftMotor
* 65535.,
249 .buzz
= value
.RightMotor
* 65535.,
250 .left
= value
.LeftTrigger
* 65535.,
251 .right
= value
.RightTrigger
* 65535.,
254 TRACE( "iface %p, value %p.\n", iface
, &value
);
256 return IWineGameControllerProvider_put_Vibration( impl
->wine_provider
, vibration
);
259 static HRESULT WINAPI
gamepad_GetCurrentReading( IGamepad
*iface
, struct GamepadReading
*value
)
261 struct gamepad
*impl
= impl_from_IGamepad( iface
);
262 struct WineGameControllerState state
;
265 TRACE( "iface %p, value %p.\n", iface
, value
);
267 if (FAILED(hr
= IWineGameControllerProvider_get_State( impl
->wine_provider
, &state
))) return hr
;
270 if (state
.buttons
[0]) value
->Buttons
|= GamepadButtons_A
;
271 if (state
.buttons
[1]) value
->Buttons
|= GamepadButtons_B
;
272 if (state
.buttons
[2]) value
->Buttons
|= GamepadButtons_X
;
273 if (state
.buttons
[3]) value
->Buttons
|= GamepadButtons_Y
;
274 if (state
.buttons
[4]) value
->Buttons
|= GamepadButtons_LeftShoulder
;
275 if (state
.buttons
[5]) value
->Buttons
|= GamepadButtons_RightShoulder
;
276 if (state
.buttons
[6]) value
->Buttons
|= GamepadButtons_View
;
277 if (state
.buttons
[7]) value
->Buttons
|= GamepadButtons_Menu
;
278 if (state
.buttons
[8]) value
->Buttons
|= GamepadButtons_LeftThumbstick
;
279 if (state
.buttons
[9]) value
->Buttons
|= GamepadButtons_RightThumbstick
;
281 switch (state
.switches
[0])
283 case GameControllerSwitchPosition_Up
:
284 case GameControllerSwitchPosition_UpRight
:
285 case GameControllerSwitchPosition_UpLeft
:
286 value
->Buttons
|= GamepadButtons_DPadUp
;
288 case GameControllerSwitchPosition_Down
:
289 case GameControllerSwitchPosition_DownRight
:
290 case GameControllerSwitchPosition_DownLeft
:
291 value
->Buttons
|= GamepadButtons_DPadDown
;
297 switch (state
.switches
[0])
299 case GameControllerSwitchPosition_Right
:
300 case GameControllerSwitchPosition_UpRight
:
301 case GameControllerSwitchPosition_DownRight
:
302 value
->Buttons
|= GamepadButtons_DPadRight
;
304 case GameControllerSwitchPosition_Left
:
305 case GameControllerSwitchPosition_UpLeft
:
306 case GameControllerSwitchPosition_DownLeft
:
307 value
->Buttons
|= GamepadButtons_DPadLeft
;
313 value
->LeftThumbstickX
= 2. * state
.axes
[0] - 1.;
314 value
->LeftThumbstickY
= 1. - 2. * state
.axes
[1];
315 value
->LeftTrigger
= state
.axes
[2];
316 value
->RightThumbstickX
= 2. * state
.axes
[3] - 1.;
317 value
->RightThumbstickY
= 1. - 2. * state
.axes
[4];
318 value
->RightTrigger
= state
.axes
[5];
320 value
->Timestamp
= state
.timestamp
;
325 static const struct IGamepadVtbl gamepad_vtbl
=
327 gamepad_QueryInterface
,
330 /* IInspectable methods */
332 gamepad_GetRuntimeClassName
,
333 gamepad_GetTrustLevel
,
334 /* IGamepad methods */
335 gamepad_get_Vibration
,
336 gamepad_put_Vibration
,
337 gamepad_GetCurrentReading
,
340 DEFINE_IINSPECTABLE_OUTER( gamepad2
, IGamepad2
, struct gamepad
, IGameController_outer
)
342 static HRESULT WINAPI
gamepad2_GetButtonLabel( IGamepad2
*iface
, GamepadButtons button
, GameControllerButtonLabel
*value
)
344 FIXME( "iface %p, button %#x, value %p stub!\n", iface
, button
, value
);
345 *value
= GameControllerButtonLabel_None
;
349 static const struct IGamepad2Vtbl gamepad2_vtbl
=
351 gamepad2_QueryInterface
,
354 /* IInspectable methods */
356 gamepad2_GetRuntimeClassName
,
357 gamepad2_GetTrustLevel
,
358 /* IGamepad2 methods */
359 gamepad2_GetButtonLabel
,
362 struct gamepad_statics
364 IActivationFactory IActivationFactory_iface
;
365 IGamepadStatics IGamepadStatics_iface
;
366 IGamepadStatics2 IGamepadStatics2_iface
;
367 ICustomGameControllerFactory ICustomGameControllerFactory_iface
;
371 static inline struct gamepad_statics
*impl_from_IActivationFactory( IActivationFactory
*iface
)
373 return CONTAINING_RECORD( iface
, struct gamepad_statics
, IActivationFactory_iface
);
376 static HRESULT WINAPI
factory_QueryInterface( IActivationFactory
*iface
, REFIID iid
, void **out
)
378 struct gamepad_statics
*impl
= impl_from_IActivationFactory( iface
);
380 TRACE( "iface %p, iid %s, out %p.\n", iface
, debugstr_guid( iid
), out
);
382 if (IsEqualGUID( iid
, &IID_IUnknown
) ||
383 IsEqualGUID( iid
, &IID_IInspectable
) ||
384 IsEqualGUID( iid
, &IID_IAgileObject
) ||
385 IsEqualGUID( iid
, &IID_IActivationFactory
))
387 IInspectable_AddRef( (*out
= &impl
->IActivationFactory_iface
) );
391 if (IsEqualGUID( iid
, &IID_IGamepadStatics
))
393 IInspectable_AddRef( (*out
= &impl
->IGamepadStatics_iface
) );
397 if (IsEqualGUID( iid
, &IID_IGamepadStatics2
))
399 IInspectable_AddRef( (*out
= &impl
->IGamepadStatics2_iface
) );
403 if (IsEqualGUID( iid
, &IID_ICustomGameControllerFactory
))
405 IInspectable_AddRef( (*out
= &impl
->ICustomGameControllerFactory_iface
) );
409 FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid
) );
411 return E_NOINTERFACE
;
414 static ULONG WINAPI
factory_AddRef( IActivationFactory
*iface
)
416 struct gamepad_statics
*impl
= impl_from_IActivationFactory( iface
);
417 ULONG ref
= InterlockedIncrement( &impl
->ref
);
418 TRACE( "iface %p increasing refcount to %lu.\n", iface
, ref
);
422 static ULONG WINAPI
factory_Release( IActivationFactory
*iface
)
424 struct gamepad_statics
*impl
= impl_from_IActivationFactory( iface
);
425 ULONG ref
= InterlockedDecrement( &impl
->ref
);
426 TRACE( "iface %p decreasing refcount to %lu.\n", iface
, ref
);
430 static HRESULT WINAPI
factory_GetIids( IActivationFactory
*iface
, ULONG
*iid_count
, IID
**iids
)
432 FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
436 static HRESULT WINAPI
factory_GetRuntimeClassName( IActivationFactory
*iface
, HSTRING
*class_name
)
438 FIXME( "iface %p, class_name %p stub!\n", iface
, class_name
);
442 static HRESULT WINAPI
factory_GetTrustLevel( IActivationFactory
*iface
, TrustLevel
*trust_level
)
444 FIXME( "iface %p, trust_level %p stub!\n", iface
, trust_level
);
448 static HRESULT WINAPI
factory_ActivateInstance( IActivationFactory
*iface
, IInspectable
**instance
)
450 FIXME( "iface %p, instance %p stub!\n", iface
, instance
);
454 static const struct IActivationFactoryVtbl factory_vtbl
=
456 factory_QueryInterface
,
459 /* IInspectable methods */
461 factory_GetRuntimeClassName
,
462 factory_GetTrustLevel
,
463 /* IActivationFactory methods */
464 factory_ActivateInstance
,
467 DEFINE_IINSPECTABLE( statics
, IGamepadStatics
, struct gamepad_statics
, IActivationFactory_iface
)
469 static HRESULT WINAPI
statics_add_GamepadAdded( IGamepadStatics
*iface
, IEventHandler_Gamepad
*handler
,
470 EventRegistrationToken
*token
)
472 TRACE( "iface %p, handler %p, token %p.\n", iface
, handler
, token
);
473 if (!handler
) return E_INVALIDARG
;
474 return event_handlers_append( &gamepad_added_handlers
, (IEventHandler_IInspectable
*)handler
, token
);
477 static HRESULT WINAPI
statics_remove_GamepadAdded( IGamepadStatics
*iface
, EventRegistrationToken token
)
479 TRACE( "iface %p, token %#I64x.\n", iface
, token
.value
);
480 return event_handlers_remove( &gamepad_added_handlers
, &token
);
483 static HRESULT WINAPI
statics_add_GamepadRemoved( IGamepadStatics
*iface
, IEventHandler_Gamepad
*handler
,
484 EventRegistrationToken
*token
)
486 TRACE( "iface %p, handler %p, token %p.\n", iface
, handler
, token
);
487 if (!handler
) return E_INVALIDARG
;
488 return event_handlers_append( &gamepad_removed_handlers
, (IEventHandler_IInspectable
*)handler
, token
);
491 static HRESULT WINAPI
statics_remove_GamepadRemoved( IGamepadStatics
*iface
, EventRegistrationToken token
)
493 TRACE( "iface %p, token %#I64x.\n", iface
, token
.value
);
494 return event_handlers_remove( &gamepad_removed_handlers
, &token
);
497 static HRESULT WINAPI
statics_get_Gamepads( IGamepadStatics
*iface
, IVectorView_Gamepad
**value
)
501 TRACE( "iface %p, value %p.\n", iface
, value
);
503 EnterCriticalSection( &gamepad_cs
);
504 if (SUCCEEDED(hr
= init_gamepads()))
505 hr
= IVector_Gamepad_GetView( gamepads
, value
);
506 LeaveCriticalSection( &gamepad_cs
);
511 static const struct IGamepadStaticsVtbl statics_vtbl
=
513 statics_QueryInterface
,
516 /* IInspectable methods */
518 statics_GetRuntimeClassName
,
519 statics_GetTrustLevel
,
520 /* IGamepadStatics methods */
521 statics_add_GamepadAdded
,
522 statics_remove_GamepadAdded
,
523 statics_add_GamepadRemoved
,
524 statics_remove_GamepadRemoved
,
525 statics_get_Gamepads
,
528 DEFINE_IINSPECTABLE( statics2
, IGamepadStatics2
, struct gamepad_statics
, IActivationFactory_iface
)
530 static HRESULT WINAPI
statics2_FromGameController( IGamepadStatics2
*iface
, IGameController
*game_controller
, IGamepad
**value
)
532 struct gamepad_statics
*impl
= impl_from_IGamepadStatics2( iface
);
533 IGameController
*controller
;
536 TRACE( "iface %p, game_controller %p, value %p.\n", iface
, game_controller
, value
);
539 hr
= IGameControllerFactoryManagerStatics2_TryGetFactoryControllerFromGameController( manager_factory
, &impl
->ICustomGameControllerFactory_iface
,
540 game_controller
, &controller
);
541 if (FAILED(hr
) || !controller
) return hr
;
543 hr
= IGameController_QueryInterface( controller
, &IID_IGamepad
, (void **)value
);
544 IGameController_Release( controller
);
548 static const struct IGamepadStatics2Vtbl statics2_vtbl
=
550 statics2_QueryInterface
,
553 /* IInspectable methods */
555 statics2_GetRuntimeClassName
,
556 statics2_GetTrustLevel
,
557 /* IGamepadStatics2 methods */
558 statics2_FromGameController
,
561 DEFINE_IINSPECTABLE( controller_factory
, ICustomGameControllerFactory
, struct gamepad_statics
, IActivationFactory_iface
)
563 static HRESULT WINAPI
controller_factory_CreateGameController( ICustomGameControllerFactory
*iface
, IGameControllerProvider
*provider
,
564 IInspectable
**value
)
566 struct gamepad
*impl
;
568 TRACE( "iface %p, provider %p, value %p.\n", iface
, provider
, value
);
570 if (!(impl
= calloc( 1, sizeof(*impl
) ))) return E_OUTOFMEMORY
;
571 impl
->IGameControllerImpl_iface
.lpVtbl
= &controller_vtbl
;
572 impl
->IGameControllerInputSink_iface
.lpVtbl
= &input_sink_vtbl
;
573 impl
->IGamepad_iface
.lpVtbl
= &gamepad_vtbl
;
574 impl
->IGamepad2_iface
.lpVtbl
= &gamepad2_vtbl
;
577 TRACE( "created Gamepad %p\n", impl
);
579 *value
= (IInspectable
*)&impl
->IGameControllerImpl_iface
;
583 static HRESULT WINAPI
controller_factory_OnGameControllerAdded( ICustomGameControllerFactory
*iface
, IGameController
*value
)
588 TRACE( "iface %p, value %p.\n", iface
, value
);
590 if (FAILED(hr
= IGameController_QueryInterface( value
, &IID_IGamepad
, (void **)&gamepad
)))
592 event_handlers_notify( &gamepad_added_handlers
, (IInspectable
*)gamepad
);
593 IGamepad_Release( gamepad
);
598 static HRESULT WINAPI
controller_factory_OnGameControllerRemoved( ICustomGameControllerFactory
*iface
, IGameController
*value
)
605 TRACE( "iface %p, value %p.\n", iface
, value
);
607 if (FAILED(hr
= IGameController_QueryInterface( value
, &IID_IGamepad
, (void **)&gamepad
)))
610 EnterCriticalSection( &gamepad_cs
);
611 if (SUCCEEDED(hr
= init_gamepads()))
613 if (FAILED(hr
= IVector_Gamepad_IndexOf( gamepads
, gamepad
, &index
, &found
)) || !found
)
614 WARN( "Could not find gamepad %p, hr %#lx!\n", gamepad
, hr
);
616 hr
= IVector_Gamepad_RemoveAt( gamepads
, index
);
618 LeaveCriticalSection( &gamepad_cs
);
621 WARN( "Failed to remove gamepad %p, hr %#lx!\n", gamepad
, hr
);
624 TRACE( "Removed gamepad %p.\n", gamepad
);
625 event_handlers_notify( &gamepad_removed_handlers
, (IInspectable
*)gamepad
);
627 IGamepad_Release( gamepad
);
632 static const struct ICustomGameControllerFactoryVtbl controller_factory_vtbl
=
634 controller_factory_QueryInterface
,
635 controller_factory_AddRef
,
636 controller_factory_Release
,
637 /* IInspectable methods */
638 controller_factory_GetIids
,
639 controller_factory_GetRuntimeClassName
,
640 controller_factory_GetTrustLevel
,
641 /* ICustomGameControllerFactory methods */
642 controller_factory_CreateGameController
,
643 controller_factory_OnGameControllerAdded
,
644 controller_factory_OnGameControllerRemoved
,
647 static struct gamepad_statics gamepad_statics
=
652 {&controller_factory_vtbl
},
656 ICustomGameControllerFactory
*gamepad_factory
= &gamepad_statics
.ICustomGameControllerFactory_iface
;