widl: Properly align name table entries.
[wine.git] / dlls / windows.gaming.input / gamepad.c
blob0d7cd690821bed1fb452e913c0c95179f8f5e158
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
20 #include "private.h"
21 #include "provider.h"
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 =
30 0, 0, &gamepad_cs,
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,
49 HRESULT hr;
51 EnterCriticalSection( &gamepad_cs );
52 if (gamepads) hr = S_OK;
53 else hr = vector_create( &iids, (void **)&gamepads );
54 LeaveCriticalSection( &gamepad_cs );
56 return hr;
59 struct gamepad
61 IGameControllerImpl IGameControllerImpl_iface;
62 IGameControllerInputSink IGameControllerInputSink_iface;
63 IGamepad IGamepad_iface;
64 IGamepad2 IGamepad2_iface;
65 IGameController *IGameController_outer;
66 LONG ref;
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) );
88 return S_OK;
91 if (IsEqualGUID( iid, &IID_IGameControllerInputSink ))
93 IInspectable_AddRef( (*out = &impl->IGameControllerInputSink_iface) );
94 return S_OK;
97 if (IsEqualGUID( iid, &IID_IGamepad ))
99 IInspectable_AddRef( (*out = &impl->IGamepad_iface) );
100 return S_OK;
103 if (IsEqualGUID( iid, &IID_IGamepad2 ))
105 IInspectable_AddRef( (*out = &impl->IGamepad2_iface) );
106 return S_OK;
109 FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
110 *out = NULL;
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 );
119 return 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 );
129 if (!ref)
131 if (impl->wine_provider)
132 IWineGameControllerProvider_Release( impl->wine_provider );
133 IGameControllerProvider_Release( impl->provider );
134 free( impl );
137 return ref;
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 );
143 return E_NOTIMPL;
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),
150 class_name );
153 static HRESULT WINAPI controller_GetTrustLevel( IGameControllerImpl *iface, TrustLevel *trust_level )
155 FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
156 return E_NOTIMPL;
159 static HRESULT WINAPI controller_Initialize( IGameControllerImpl *iface, IGameController *outer,
160 IGameControllerProvider *provider )
162 struct gamepad *impl = impl_from_IGameControllerImpl( iface );
163 HRESULT hr;
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 );
179 return hr;
182 static const struct IGameControllerImplVtbl controller_vtbl =
184 controller_QueryInterface,
185 controller_AddRef,
186 controller_Release,
187 /* IInspectable methods */
188 controller_GetIids,
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 );
200 return E_NOTIMPL;
203 static HRESULT WINAPI input_sink_OnInputSuspended( IGameControllerInputSink *iface, UINT64 timestamp )
205 FIXME( "iface %p, timestamp %I64u stub!\n", iface, timestamp );
206 return E_NOTIMPL;
209 static const struct IGameControllerInputSinkVtbl input_sink_vtbl =
211 input_sink_QueryInterface,
212 input_sink_AddRef,
213 input_sink_Release,
214 /* IInspectable methods */
215 input_sink_GetIids,
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;
229 HRESULT hr;
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.;
240 return S_OK;
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;
263 HRESULT hr;
265 TRACE( "iface %p, value %p.\n", iface, value );
267 if (FAILED(hr = IWineGameControllerProvider_get_State( impl->wine_provider, &state ))) return hr;
269 value->Buttons = 0;
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;
287 break;
288 case GameControllerSwitchPosition_Down:
289 case GameControllerSwitchPosition_DownRight:
290 case GameControllerSwitchPosition_DownLeft:
291 value->Buttons |= GamepadButtons_DPadDown;
292 break;
293 default:
294 break;
297 switch (state.switches[0])
299 case GameControllerSwitchPosition_Right:
300 case GameControllerSwitchPosition_UpRight:
301 case GameControllerSwitchPosition_DownRight:
302 value->Buttons |= GamepadButtons_DPadRight;
303 break;
304 case GameControllerSwitchPosition_Left:
305 case GameControllerSwitchPosition_UpLeft:
306 case GameControllerSwitchPosition_DownLeft:
307 value->Buttons |= GamepadButtons_DPadLeft;
308 break;
309 default:
310 break;
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;
322 return hr;
325 static const struct IGamepadVtbl gamepad_vtbl =
327 gamepad_QueryInterface,
328 gamepad_AddRef,
329 gamepad_Release,
330 /* IInspectable methods */
331 gamepad_GetIids,
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;
346 return S_OK;
349 static const struct IGamepad2Vtbl gamepad2_vtbl =
351 gamepad2_QueryInterface,
352 gamepad2_AddRef,
353 gamepad2_Release,
354 /* IInspectable methods */
355 gamepad2_GetIids,
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;
368 LONG ref;
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) );
388 return S_OK;
391 if (IsEqualGUID( iid, &IID_IGamepadStatics ))
393 IInspectable_AddRef( (*out = &impl->IGamepadStatics_iface) );
394 return S_OK;
397 if (IsEqualGUID( iid, &IID_IGamepadStatics2 ))
399 IInspectable_AddRef( (*out = &impl->IGamepadStatics2_iface) );
400 return S_OK;
403 if (IsEqualGUID( iid, &IID_ICustomGameControllerFactory ))
405 IInspectable_AddRef( (*out = &impl->ICustomGameControllerFactory_iface) );
406 return S_OK;
409 FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
410 *out = NULL;
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 );
419 return 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 );
427 return 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 );
433 return E_NOTIMPL;
436 static HRESULT WINAPI factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name )
438 FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
439 return E_NOTIMPL;
442 static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level )
444 FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
445 return E_NOTIMPL;
448 static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
450 FIXME( "iface %p, instance %p stub!\n", iface, instance );
451 return E_NOTIMPL;
454 static const struct IActivationFactoryVtbl factory_vtbl =
456 factory_QueryInterface,
457 factory_AddRef,
458 factory_Release,
459 /* IInspectable methods */
460 factory_GetIids,
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 )
499 HRESULT hr;
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 );
508 return hr;
511 static const struct IGamepadStaticsVtbl statics_vtbl =
513 statics_QueryInterface,
514 statics_AddRef,
515 statics_Release,
516 /* IInspectable methods */
517 statics_GetIids,
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;
534 HRESULT hr;
536 TRACE( "iface %p, game_controller %p, value %p.\n", iface, game_controller, value );
538 *value = NULL;
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 );
545 return hr;
548 static const struct IGamepadStatics2Vtbl statics2_vtbl =
550 statics2_QueryInterface,
551 statics2_AddRef,
552 statics2_Release,
553 /* IInspectable methods */
554 statics2_GetIids,
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;
575 impl->ref = 1;
577 TRACE( "created Gamepad %p\n", impl );
579 *value = (IInspectable *)&impl->IGameControllerImpl_iface;
580 return S_OK;
583 static HRESULT WINAPI controller_factory_OnGameControllerAdded( ICustomGameControllerFactory *iface, IGameController *value )
585 IGamepad *gamepad;
586 HRESULT hr;
588 TRACE( "iface %p, value %p.\n", iface, value );
590 if (FAILED(hr = IGameController_QueryInterface( value, &IID_IGamepad, (void **)&gamepad )))
591 return hr;
592 event_handlers_notify( &gamepad_added_handlers, (IInspectable *)gamepad );
593 IGamepad_Release( gamepad );
595 return S_OK;
598 static HRESULT WINAPI controller_factory_OnGameControllerRemoved( ICustomGameControllerFactory *iface, IGameController *value )
600 IGamepad *gamepad;
601 BOOLEAN found;
602 UINT32 index;
603 HRESULT hr;
605 TRACE( "iface %p, value %p.\n", iface, value );
607 if (FAILED(hr = IGameController_QueryInterface( value, &IID_IGamepad, (void **)&gamepad )))
608 return hr;
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 );
615 else
616 hr = IVector_Gamepad_RemoveAt( gamepads, index );
618 LeaveCriticalSection( &gamepad_cs );
620 if (FAILED(hr))
621 WARN( "Failed to remove gamepad %p, hr %#lx!\n", gamepad, hr );
622 else if (found)
624 TRACE( "Removed gamepad %p.\n", gamepad );
625 event_handlers_notify( &gamepad_removed_handlers, (IInspectable *)gamepad );
627 IGamepad_Release( gamepad );
629 return S_OK;
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 =
649 {&factory_vtbl},
650 {&statics_vtbl},
651 {&statics2_vtbl},
652 {&controller_factory_vtbl},
656 ICustomGameControllerFactory *gamepad_factory = &gamepad_statics.ICustomGameControllerFactory_iface;