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
30 #include "ddk/hidclass.h"
31 #include "ddk/hidsdi.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(input
);
41 HINSTANCE windows_gaming_input
;
43 DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT
,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x47,0x67,0x50,0xc5,0xe1,0xa6 );
45 static LRESULT CALLBACK
devnotify_wndproc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
47 DEV_BROADCAST_DEVICEINTERFACE_W
*iface
;
49 TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd
, msg
, wparam
, lparam
);
51 if (msg
== WM_DEVICECHANGE
)
55 case DBT_DEVICEARRIVAL
:
56 iface
= (DEV_BROADCAST_DEVICEINTERFACE_W
*)lparam
;
57 provider_create( iface
->dbcc_name
);
59 case DBT_DEVICEREMOVECOMPLETE
:
60 iface
= (DEV_BROADCAST_DEVICEINTERFACE_W
*)lparam
;
61 provider_remove( iface
->dbcc_name
);
67 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
70 static void initialize_providers( void )
72 char buffer
[offsetof( SP_DEVICE_INTERFACE_DETAIL_DATA_W
, DevicePath
[MAX_PATH
] )];
73 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*detail
= (void *)buffer
;
74 SP_DEVICE_INTERFACE_DATA iface
= {sizeof(iface
)};
75 GUID guid
= GUID_DEVINTERFACE_WINEXINPUT
;
79 set
= SetupDiGetClassDevsW( NULL
, NULL
, NULL
, DIGCF_ALLCLASSES
| DIGCF_DEVICEINTERFACE
| DIGCF_PRESENT
);
81 while (SetupDiEnumDeviceInterfaces( set
, NULL
, &guid
, i
++, &iface
))
83 detail
->cbSize
= sizeof(*detail
);
84 if (!SetupDiGetDeviceInterfaceDetailW( set
, &iface
, detail
, sizeof(buffer
), NULL
, NULL
)) continue;
85 provider_create( detail
->DevicePath
);
88 HidD_GetHidGuid( &guid
);
90 while (SetupDiEnumDeviceInterfaces( set
, NULL
, &guid
, i
++, &iface
))
92 detail
->cbSize
= sizeof(*detail
);
93 if (!SetupDiGetDeviceInterfaceDetailW( set
, &iface
, detail
, sizeof(buffer
), NULL
, NULL
)) continue;
94 provider_create( detail
->DevicePath
);
97 SetupDiDestroyDeviceInfoList( set
);
100 static DWORD WINAPI
monitor_thread_proc( void *param
)
102 DEV_BROADCAST_DEVICEINTERFACE_W filter
=
104 .dbcc_size
= sizeof(DEV_BROADCAST_DEVICEINTERFACE_W
),
105 .dbcc_devicetype
= DBT_DEVTYP_DEVICEINTERFACE
,
107 WNDCLASSEXW wndclass
=
109 .cbSize
= sizeof(WNDCLASSEXW
),
110 .lpszClassName
= L
"__wine_gaming_input_devnotify",
111 .lpfnWndProc
= devnotify_wndproc
,
113 HANDLE start_event
= param
;
114 HDEVNOTIFY devnotify
;
119 SetThreadDescription( GetCurrentThread(), L
"wine_wginput_worker" );
121 GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
, (void *)windows_gaming_input
, &module
);
122 RegisterClassExW( &wndclass
);
123 hwnd
= CreateWindowExW( 0, wndclass
.lpszClassName
, NULL
, 0, 0, 0, 0, 0, HWND_MESSAGE
, NULL
, NULL
, NULL
);
124 devnotify
= RegisterDeviceNotificationW( hwnd
, &filter
, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
);
125 initialize_providers();
126 SetEvent( start_event
);
130 while (PeekMessageW( &msg
, hwnd
, 0, 0, PM_REMOVE
))
132 TranslateMessage( &msg
);
133 DispatchMessageW( &msg
);
135 } while (!MsgWaitForMultipleObjectsEx( 0, NULL
, INFINITE
, QS_ALLINPUT
, MWMO_ALERTABLE
));
137 UnregisterDeviceNotification( devnotify
);
138 DestroyWindow( hwnd
);
139 UnregisterClassW( wndclass
.lpszClassName
, NULL
);
141 FreeLibraryAndExitThread( module
, 0 );
145 static BOOL WINAPI
start_monitor_thread( INIT_ONCE
*once
, void *param
, void **context
)
147 HANDLE thread
, start_event
;
149 start_event
= CreateEventA( NULL
, FALSE
, FALSE
, NULL
);
150 if (!start_event
) ERR( "Failed to create start event, error %lu\n", GetLastError() );
152 thread
= CreateThread( NULL
, 0, monitor_thread_proc
, start_event
, 0, NULL
);
153 if (!thread
) ERR( "Failed to create monitor thread, error %lu\n", GetLastError() );
156 WaitForSingleObject( start_event
, INFINITE
);
157 CloseHandle( thread
);
160 CloseHandle( start_event
);
164 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
166 FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
167 return CLASS_E_CLASSNOTAVAILABLE
;
170 HRESULT WINAPI
DllGetActivationFactory( HSTRING class_str
, IActivationFactory
**factory
)
172 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
173 const WCHAR
*buffer
= WindowsGetStringRawBuffer( class_str
, NULL
);
175 TRACE( "class %s, factory %p.\n", debugstr_w(buffer
), factory
);
177 InitOnceExecuteOnce( &init_once
, start_monitor_thread
, NULL
, NULL
);
181 if (!wcscmp( buffer
, RuntimeClass_Windows_Gaming_Input_RawGameController
))
182 ICustomGameControllerFactory_QueryInterface( controller_factory
, &IID_IActivationFactory
, (void **)factory
);
183 if (!wcscmp( buffer
, RuntimeClass_Windows_Gaming_Input_Gamepad
))
184 ICustomGameControllerFactory_QueryInterface( gamepad_factory
, &IID_IActivationFactory
, (void **)factory
);
185 if (!wcscmp( buffer
, RuntimeClass_Windows_Gaming_Input_RacingWheel
))
186 ICustomGameControllerFactory_QueryInterface( racing_wheel_factory
, &IID_IActivationFactory
, (void **)factory
);
187 if (!wcscmp( buffer
, RuntimeClass_Windows_Gaming_Input_Custom_GameControllerFactoryManager
))
188 IGameControllerFactoryManagerStatics2_QueryInterface( manager_factory
, &IID_IActivationFactory
, (void **)factory
);
190 if (!wcscmp( buffer
, RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConstantForceEffect
))
191 IInspectable_QueryInterface( constant_effect_factory
, &IID_IActivationFactory
, (void **)factory
);
192 if (!wcscmp( buffer
, RuntimeClass_Windows_Gaming_Input_ForceFeedback_RampForceEffect
))
193 IInspectable_QueryInterface( ramp_effect_factory
, &IID_IActivationFactory
, (void **)factory
);
194 if (!wcscmp( buffer
, RuntimeClass_Windows_Gaming_Input_ForceFeedback_PeriodicForceEffect
))
195 IInspectable_QueryInterface( periodic_effect_factory
, &IID_IActivationFactory
, (void **)factory
);
196 if (!wcscmp( buffer
, RuntimeClass_Windows_Gaming_Input_ForceFeedback_ConditionForceEffect
))
197 IInspectable_QueryInterface( condition_effect_factory
, &IID_IActivationFactory
, (void **)factory
);
199 if (*factory
) return S_OK
;
200 return CLASS_E_CLASSNOTAVAILABLE
;
203 BOOL WINAPI
DllMain( HINSTANCE instance
, DWORD reason
, void *reserved
)
205 TRACE( "instance %p, reason %lu, reserved %p.\n", instance
, reason
, reserved
);
209 case DLL_PROCESS_ATTACH
:
210 DisableThreadLibraryCalls( instance
);
211 windows_gaming_input
= instance
;