xref: /reactos/dll/directx/wine/dinput/dinput_main.c (revision 41c8c312)
1 /*		DirectInput
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2002 TransGaming Technologies Inc.
6  * Copyright 2007 Vitaliy Margolen
7  *
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 /* Status:
24  *
25  * - Tomb Raider 2 Demo:
26  *   Playable using keyboard only.
27  * - WingCommander Prophecy Demo:
28  *   Doesn't get Input Focus.
29  *
30  * - Fallout : works great in X and DGA mode
31  */
32 
33 #include <assert.h>
34 #include <stdarg.h>
35 #include <string.h>
36 
37 #define COBJMACROS
38 #define NONAMELESSUNION
39 
40 #include "wine/debug.h"
41 #include "wine/heap.h"
42 #include "wine/unicode.h"
43 #include "wine/asm.h"
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winuser.h"
47 #include "winerror.h"
48 #include "objbase.h"
49 #include "rpcproxy.h"
50 #include "initguid.h"
51 #include "devguid.h"
52 #include "dinput_private.h"
53 #include "device_private.h"
54 #include "dinputd.h"
55 
56 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
57 
58 static const IDirectInput7AVtbl ddi7avt;
59 static const IDirectInput7WVtbl ddi7wvt;
60 static const IDirectInput8AVtbl ddi8avt;
61 static const IDirectInput8WVtbl ddi8wvt;
62 static const IDirectInputJoyConfig8Vtbl JoyConfig8vt;
63 
impl_from_IDirectInput7A(IDirectInput7A * iface)64 static inline IDirectInputImpl *impl_from_IDirectInput7A( IDirectInput7A *iface )
65 {
66     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7A_iface );
67 }
68 
impl_from_IDirectInput7W(IDirectInput7W * iface)69 static inline IDirectInputImpl *impl_from_IDirectInput7W( IDirectInput7W *iface )
70 {
71     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7W_iface );
72 }
73 
impl_from_IDirectInput8A(IDirectInput8A * iface)74 static inline IDirectInputImpl *impl_from_IDirectInput8A( IDirectInput8A *iface )
75 {
76     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8A_iface );
77 }
78 
impl_from_IDirectInput8W(IDirectInput8W * iface)79 static inline IDirectInputImpl *impl_from_IDirectInput8W( IDirectInput8W *iface )
80 {
81     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8W_iface );
82 }
83 
impl_from_IDirectInputDevice8W(IDirectInputDevice8W * iface)84 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
85 {
86     return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface);
87 }
88 
89 static const struct dinput_device *dinput_devices[] =
90 {
91     &mouse_device,
92     &keyboard_device,
93     &joystick_linuxinput_device,
94     &joystick_linux_device,
95     &joystick_osx_device
96 };
97 
98 HINSTANCE DINPUT_instance;
99 
100 static BOOL check_hook_thread(void);
101 static CRITICAL_SECTION dinput_hook_crit;
102 static struct list direct_input_list = LIST_INIT( direct_input_list );
103 
104 static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion);
105 static void uninitialize_directinput_instance(IDirectInputImpl *This);
106 
create_directinput_instance(REFIID riid,LPVOID * ppDI,IDirectInputImpl ** out)107 static HRESULT create_directinput_instance(REFIID riid, LPVOID *ppDI, IDirectInputImpl **out)
108 {
109     IDirectInputImpl *This = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectInputImpl) );
110     HRESULT hr;
111 
112     if (!This)
113         return E_OUTOFMEMORY;
114 
115     This->IDirectInput7A_iface.lpVtbl = &ddi7avt;
116     This->IDirectInput7W_iface.lpVtbl = &ddi7wvt;
117     This->IDirectInput8A_iface.lpVtbl = &ddi8avt;
118     This->IDirectInput8W_iface.lpVtbl = &ddi8wvt;
119     This->IDirectInputJoyConfig8_iface.lpVtbl = &JoyConfig8vt;
120 
121     hr = IDirectInput_QueryInterface( &This->IDirectInput7A_iface, riid, ppDI );
122     if (FAILED(hr))
123     {
124         HeapFree( GetProcessHeap(), 0, This );
125         return hr;
126     }
127 
128     if (out) *out = This;
129     return DI_OK;
130 }
131 
132 /******************************************************************************
133  *	DirectInputCreateEx (DINPUT.@)
134  */
DirectInputCreateEx(HINSTANCE hinst,DWORD dwVersion,REFIID riid,LPVOID * ppDI,LPUNKNOWN punkOuter)135 HRESULT WINAPI DirectInputCreateEx(
136 	HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI,
137 	LPUNKNOWN punkOuter)
138 {
139     IDirectInputImpl *This;
140     HRESULT hr;
141 
142     TRACE("(%p,%04x,%s,%p,%p)\n", hinst, dwVersion, debugstr_guid(riid), ppDI, punkOuter);
143 
144     if (IsEqualGUID( &IID_IDirectInputA,  riid ) ||
145         IsEqualGUID( &IID_IDirectInput2A, riid ) ||
146         IsEqualGUID( &IID_IDirectInput7A, riid ) ||
147         IsEqualGUID( &IID_IDirectInputW,  riid ) ||
148         IsEqualGUID( &IID_IDirectInput2W, riid ) ||
149         IsEqualGUID( &IID_IDirectInput7W, riid ))
150     {
151         hr = create_directinput_instance(riid, ppDI, &This);
152         if (FAILED(hr))
153             return hr;
154     }
155     else
156         return DIERR_NOINTERFACE;
157 
158     hr = IDirectInput_Initialize( &This->IDirectInput7A_iface, hinst, dwVersion );
159     if (FAILED(hr))
160     {
161         IDirectInput_Release( &This->IDirectInput7A_iface );
162         *ppDI = NULL;
163         return hr;
164     }
165 
166     return DI_OK;
167 }
168 
169 /******************************************************************************
170  *	DirectInput8Create (DINPUT8.@)
171  */
DirectInput8Create(HINSTANCE hinst,DWORD version,REFIID iid,void ** out,IUnknown * outer)172 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInput8Create(HINSTANCE hinst,
173     DWORD version, REFIID iid, void **out, IUnknown *outer)
174 {
175     IDirectInputImpl *This;
176     HRESULT hr;
177 
178     TRACE("hinst %p, version %#x, iid %s, out %p, outer %p.\n",
179         hinst, version, debugstr_guid(iid), out, outer);
180 
181     if (!out)
182         return E_POINTER;
183 
184     if (!IsEqualGUID(&IID_IDirectInput8A, iid) &&
185         !IsEqualGUID(&IID_IDirectInput8W, iid) &&
186         !IsEqualGUID(&IID_IUnknown, iid))
187     {
188         *out = NULL;
189         return DIERR_NOINTERFACE;
190     }
191 
192     hr = create_directinput_instance(iid, out, &This);
193 
194     if (FAILED(hr))
195     {
196         ERR("Failed to create DirectInput, hr %#x.\n", hr);
197         return hr;
198     }
199 
200     /* When aggregation is used, the application needs to manually call Initialize(). */
201     if (!outer && IsEqualGUID(&IID_IDirectInput8A, iid))
202     {
203         hr = IDirectInput8_Initialize(&This->IDirectInput8A_iface, hinst, version);
204         if (FAILED(hr))
205         {
206             IDirectInput8_Release(&This->IDirectInput8A_iface);
207             *out = NULL;
208             return hr;
209         }
210     }
211 
212     if (!outer && IsEqualGUID(&IID_IDirectInput8W, iid))
213     {
214         hr = IDirectInput8_Initialize(&This->IDirectInput8W_iface, hinst, version);
215         if (FAILED(hr))
216         {
217             IDirectInput8_Release(&This->IDirectInput8W_iface);
218             *out = NULL;
219             return hr;
220         }
221     }
222 
223     return S_OK;
224 }
225 
226 /******************************************************************************
227  *	DirectInputCreateA (DINPUT.@)
228  */
DirectInputCreateA(HINSTANCE hinst,DWORD dwVersion,LPDIRECTINPUTA * ppDI,LPUNKNOWN punkOuter)229 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
230 {
231     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7A, (LPVOID *)ppDI, punkOuter);
232 }
233 
234 /******************************************************************************
235  *	DirectInputCreateW (DINPUT.@)
236  */
DirectInputCreateW(HINSTANCE hinst,DWORD dwVersion,LPDIRECTINPUTW * ppDI,LPUNKNOWN punkOuter)237 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter)
238 {
239     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7W, (LPVOID *)ppDI, punkOuter);
240 }
241 
_dump_DIDEVTYPE_value(DWORD dwDevType,DWORD dwVersion)242 static const char *_dump_DIDEVTYPE_value(DWORD dwDevType, DWORD dwVersion)
243 {
244     if (dwVersion < 0x0800) {
245         switch (dwDevType) {
246             case 0: return "All devices";
247             case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE";
248             case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD";
249             case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK";
250             case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE";
251             default: return "Unknown";
252         }
253     } else {
254         switch (dwDevType) {
255             case DI8DEVCLASS_ALL: return "All devices";
256             case DI8DEVCLASS_POINTER: return "DI8DEVCLASS_POINTER";
257             case DI8DEVCLASS_KEYBOARD: return "DI8DEVCLASS_KEYBOARD";
258             case DI8DEVCLASS_DEVICE: return "DI8DEVCLASS_DEVICE";
259             case DI8DEVCLASS_GAMECTRL: return "DI8DEVCLASS_GAMECTRL";
260             default: return "Unknown";
261         }
262     }
263 }
264 
_dump_EnumDevices_dwFlags(DWORD dwFlags)265 static void _dump_EnumDevices_dwFlags(DWORD dwFlags)
266 {
267     if (TRACE_ON(dinput)) {
268 	unsigned int   i;
269 	static const struct {
270 	    DWORD       mask;
271 	    const char  *name;
272 	} flags[] = {
273 #define FE(x) { x, #x}
274 	    FE(DIEDFL_ALLDEVICES),
275 	    FE(DIEDFL_ATTACHEDONLY),
276 	    FE(DIEDFL_FORCEFEEDBACK),
277 	    FE(DIEDFL_INCLUDEALIASES),
278             FE(DIEDFL_INCLUDEPHANTOMS),
279             FE(DIEDFL_INCLUDEHIDDEN)
280 #undef FE
281 	};
282 	TRACE(" flags: ");
283 	if (dwFlags == 0) {
284 	    TRACE("DIEDFL_ALLDEVICES\n");
285 	    return;
286 	}
287 	for (i = 0; i < ARRAY_SIZE(flags); i++)
288 	    if (flags[i].mask & dwFlags)
289 		TRACE("%s ",flags[i].name);
290     }
291     TRACE("\n");
292 }
293 
dump_semantic(DWORD semantic)294 static const char *dump_semantic(DWORD semantic)
295 {
296     if((semantic & 0xff000000) == 0xff000000)
297         return "Any AXIS";
298     else if((semantic & 0x82000000) == 0x82000000)
299         return "Mouse";
300     else if((semantic & 0x81000000) == 0x81000000)
301         return "Keybaord";
302     else if((semantic & DIVIRTUAL_FLYING_HELICOPTER) == DIVIRTUAL_FLYING_HELICOPTER)
303         return "Helicopter";
304 
305     return "Unknown";
306 }
307 
_dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat)308 static void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat)
309 {
310     unsigned int i;
311 
312     TRACE("diaf.dwSize = %d\n", lpdiActionFormat->dwSize);
313     TRACE("diaf.dwActionSize = %d\n", lpdiActionFormat->dwActionSize);
314     TRACE("diaf.dwDataSize = %d\n", lpdiActionFormat->dwDataSize);
315     TRACE("diaf.dwNumActions = %d\n", lpdiActionFormat->dwNumActions);
316     TRACE("diaf.rgoAction = %p\n", lpdiActionFormat->rgoAction);
317     TRACE("diaf.guidActionMap = %s\n", debugstr_guid(&lpdiActionFormat->guidActionMap));
318     TRACE("diaf.dwGenre = 0x%08x\n", lpdiActionFormat->dwGenre);
319     TRACE("diaf.dwBufferSize = %d\n", lpdiActionFormat->dwBufferSize);
320     TRACE("diaf.lAxisMin = %d\n", lpdiActionFormat->lAxisMin);
321     TRACE("diaf.lAxisMax = %d\n", lpdiActionFormat->lAxisMax);
322     TRACE("diaf.hInstString = %p\n", lpdiActionFormat->hInstString);
323     TRACE("diaf.ftTimeStamp ...\n");
324     TRACE("diaf.dwCRC = 0x%x\n", lpdiActionFormat->dwCRC);
325     TRACE("diaf.tszActionMap = %s\n", debugstr_a(lpdiActionFormat->tszActionMap));
326     for (i = 0; i < lpdiActionFormat->dwNumActions; i++)
327     {
328         TRACE("diaf.rgoAction[%u]:\n", i);
329         TRACE("\tuAppData=0x%lx\n", lpdiActionFormat->rgoAction[i].uAppData);
330         TRACE("\tdwSemantic=0x%08x (%s)\n", lpdiActionFormat->rgoAction[i].dwSemantic, dump_semantic(lpdiActionFormat->rgoAction[i].dwSemantic));
331         TRACE("\tdwFlags=0x%x\n", lpdiActionFormat->rgoAction[i].dwFlags);
332         TRACE("\tszActionName=%s\n", debugstr_a(lpdiActionFormat->rgoAction[i].u.lptszActionName));
333         TRACE("\tguidInstance=%s\n", debugstr_guid(&lpdiActionFormat->rgoAction[i].guidInstance));
334         TRACE("\tdwObjID=0x%x\n", lpdiActionFormat->rgoAction[i].dwObjID);
335         TRACE("\tdwHow=0x%x\n", lpdiActionFormat->rgoAction[i].dwHow);
336     }
337 }
338 
_copy_diactionformatAtoW(LPDIACTIONFORMATW to,LPDIACTIONFORMATA from)339 void _copy_diactionformatAtoW(LPDIACTIONFORMATW to, LPDIACTIONFORMATA from)
340 {
341     int i;
342 
343     to->dwSize = sizeof(DIACTIONFORMATW);
344     to->dwActionSize = sizeof(DIACTIONW);
345     to->dwDataSize = from->dwDataSize;
346     to->dwNumActions = from->dwNumActions;
347     to->guidActionMap = from->guidActionMap;
348     to->dwGenre = from->dwGenre;
349     to->dwBufferSize = from->dwBufferSize;
350     to->lAxisMin = from->lAxisMin;
351     to->lAxisMax = from->lAxisMax;
352     to->dwCRC = from->dwCRC;
353     to->ftTimeStamp = from->ftTimeStamp;
354 
355     for (i=0; i < to->dwNumActions; i++)
356     {
357         to->rgoAction[i].uAppData = from->rgoAction[i].uAppData;
358         to->rgoAction[i].dwSemantic = from->rgoAction[i].dwSemantic;
359         to->rgoAction[i].dwFlags = from->rgoAction[i].dwFlags;
360         to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance;
361         to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID;
362         to->rgoAction[i].dwHow = from->rgoAction[i].dwHow;
363     }
364 }
365 
_copy_diactionformatWtoA(LPDIACTIONFORMATA to,LPDIACTIONFORMATW from)366 void _copy_diactionformatWtoA(LPDIACTIONFORMATA to, LPDIACTIONFORMATW from)
367 {
368     int i;
369 
370     to->dwSize = sizeof(DIACTIONFORMATA);
371     to->dwActionSize = sizeof(DIACTIONA);
372     to->dwDataSize = from->dwDataSize;
373     to->dwNumActions = from->dwNumActions;
374     to->guidActionMap = from->guidActionMap;
375     to->dwGenre = from->dwGenre;
376     to->dwBufferSize = from->dwBufferSize;
377     to->lAxisMin = from->lAxisMin;
378     to->lAxisMax = from->lAxisMax;
379     to->dwCRC = from->dwCRC;
380     to->ftTimeStamp = from->ftTimeStamp;
381 
382     for (i=0; i < to->dwNumActions; i++)
383     {
384         to->rgoAction[i].uAppData = from->rgoAction[i].uAppData;
385         to->rgoAction[i].dwSemantic = from->rgoAction[i].dwSemantic;
386         to->rgoAction[i].dwFlags = from->rgoAction[i].dwFlags;
387         to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance;
388         to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID;
389         to->rgoAction[i].dwHow = from->rgoAction[i].dwHow;
390     }
391 }
392 
393 /* diactionformat_priority
394  *
395  *  Given a DIACTIONFORMAT structure and a DI genre, returns the enumeration
396  *  priority. Joysticks should pass the game genre, and mouse or keyboard their
397  *  respective DI*_MASK
398  */
diactionformat_priorityA(LPDIACTIONFORMATA lpdiaf,DWORD genre)399 static DWORD diactionformat_priorityA(LPDIACTIONFORMATA lpdiaf, DWORD genre)
400 {
401     int i;
402     DWORD priorityFlags = 0;
403 
404     /* If there's at least one action for the device it's priority 1 */
405     for(i=0; i < lpdiaf->dwNumActions; i++)
406         if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre)
407             priorityFlags |= DIEDBS_MAPPEDPRI1;
408 
409     return priorityFlags;
410 }
411 
diactionformat_priorityW(LPDIACTIONFORMATW lpdiaf,DWORD genre)412 static DWORD diactionformat_priorityW(LPDIACTIONFORMATW lpdiaf, DWORD genre)
413 {
414     int i;
415     DWORD priorityFlags = 0;
416 
417     /* If there's at least one action for the device it's priority 1 */
418     for(i=0; i < lpdiaf->dwNumActions; i++)
419         if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre)
420             priorityFlags |= DIEDBS_MAPPEDPRI1;
421 
422     return priorityFlags;
423 }
424 
425 #if defined __i386__ && defined _MSC_VER
enum_callback_wrapper(void * callback,const void * instance,void * ref)426 __declspec(naked) BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref)
427 {
428     __asm
429     {
430         push ebp
431         mov ebp, esp
432         push [ebp+16]
433         push [ebp+12]
434         call [ebp+8]
435         leave
436         ret
437     }
438 }
439 #elif defined __i386__ && defined __GNUC__
440 extern BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref);
441 __ASM_GLOBAL_FUNC( enum_callback_wrapper,
442     "pushl %ebp\n\t"
443     __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
444     __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
445     "movl %esp,%ebp\n\t"
446     __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
447     "pushl 16(%ebp)\n\t"
448     "pushl 12(%ebp)\n\t"
449     "call *8(%ebp)\n\t"
450     "leave\n\t"
451     __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
452     __ASM_CFI(".cfi_same_value %ebp\n\t")
453     "ret" )
454 #else
455 #define enum_callback_wrapper(callback, instance, ref) (callback)((instance), (ref))
456 #endif
457 
458 /******************************************************************************
459  *	IDirectInputA_EnumDevices
460  */
IDirectInputAImpl_EnumDevices(LPDIRECTINPUT7A iface,DWORD dwDevType,LPDIENUMDEVICESCALLBACKA lpCallback,LPVOID pvRef,DWORD dwFlags)461 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
462 	LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
463 	LPVOID pvRef, DWORD dwFlags)
464 {
465     IDirectInputImpl *This = impl_from_IDirectInput7A(iface);
466     DIDEVICEINSTANCEA devInstance;
467     unsigned int i;
468     int j;
469     HRESULT r;
470 
471     TRACE("(this=%p,0x%04x '%s',%p,%p,0x%04x)\n",
472 	  This, dwDevType, _dump_DIDEVTYPE_value(dwDevType, This->dwVersion),
473 	  lpCallback, pvRef, dwFlags);
474     _dump_EnumDevices_dwFlags(dwFlags);
475 
476     if (!lpCallback ||
477         dwFlags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN) ||
478         (dwDevType > DI8DEVCLASS_GAMECTRL && dwDevType < DI8DEVTYPE_DEVICE) || dwDevType > DI8DEVTYPE_SUPPLEMENTAL)
479         return DIERR_INVALIDPARAM;
480 
481     if (!This->initialized)
482         return DIERR_NOTINITIALIZED;
483 
484     for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) {
485         if (!dinput_devices[i]->enum_deviceA) continue;
486 
487         TRACE(" Checking device %u ('%s')\n", i, dinput_devices[i]->name);
488         for (j = 0, r = S_OK; SUCCEEDED(r); j++) {
489             devInstance.dwSize = sizeof(devInstance);
490             r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j);
491             if (r == S_OK)
492                 if (enum_callback_wrapper(lpCallback, &devInstance, pvRef) == DIENUM_STOP)
493                     return S_OK;
494         }
495     }
496 
497     return S_OK;
498 }
499 /******************************************************************************
500  *	IDirectInputW_EnumDevices
501  */
IDirectInputWImpl_EnumDevices(LPDIRECTINPUT7W iface,DWORD dwDevType,LPDIENUMDEVICESCALLBACKW lpCallback,LPVOID pvRef,DWORD dwFlags)502 static HRESULT WINAPI IDirectInputWImpl_EnumDevices(
503 	LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
504 	LPVOID pvRef, DWORD dwFlags)
505 {
506     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
507     DIDEVICEINSTANCEW devInstance;
508     unsigned int i;
509     int j;
510     HRESULT r;
511 
512     TRACE("(this=%p,0x%04x '%s',%p,%p,0x%04x)\n",
513 	  This, dwDevType, _dump_DIDEVTYPE_value(dwDevType, This->dwVersion),
514 	  lpCallback, pvRef, dwFlags);
515     _dump_EnumDevices_dwFlags(dwFlags);
516 
517     if (!lpCallback ||
518         dwFlags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN) ||
519         (dwDevType > DI8DEVCLASS_GAMECTRL && dwDevType < DI8DEVTYPE_DEVICE) || dwDevType > DI8DEVTYPE_SUPPLEMENTAL)
520         return DIERR_INVALIDPARAM;
521 
522     if (!This->initialized)
523         return DIERR_NOTINITIALIZED;
524 
525     for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) {
526         if (!dinput_devices[i]->enum_deviceW) continue;
527         for (j = 0, r = S_OK; SUCCEEDED(r); j++) {
528             devInstance.dwSize = sizeof(devInstance);
529             TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
530             r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j);
531             if (r == S_OK)
532                 if (enum_callback_wrapper(lpCallback, &devInstance, pvRef) == DIENUM_STOP)
533                     return S_OK;
534         }
535     }
536 
537     return S_OK;
538 }
539 
IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)540 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)
541 {
542     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
543     ULONG ref = InterlockedIncrement(&This->ref);
544 
545     TRACE( "(%p) ref %d\n", This, ref );
546     return ref;
547 }
548 
IDirectInputWImpl_AddRef(LPDIRECTINPUT7W iface)549 static ULONG WINAPI IDirectInputWImpl_AddRef(LPDIRECTINPUT7W iface)
550 {
551     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
552     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
553 }
554 
IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)555 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)
556 {
557     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
558     ULONG ref = InterlockedDecrement( &This->ref );
559 
560     TRACE( "(%p) ref %d\n", This, ref );
561 
562     if (ref == 0)
563     {
564         uninitialize_directinput_instance( This );
565         HeapFree( GetProcessHeap(), 0, This );
566     }
567 
568     return ref;
569 }
570 
IDirectInputWImpl_Release(LPDIRECTINPUT7W iface)571 static ULONG WINAPI IDirectInputWImpl_Release(LPDIRECTINPUT7W iface)
572 {
573     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
574     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
575 }
576 
IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface,REFIID riid,LPVOID * ppobj)577 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj)
578 {
579     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
580 
581     TRACE( "(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj );
582 
583     if (!riid || !ppobj)
584         return E_POINTER;
585 
586     *ppobj = NULL;
587 
588 #if DIRECTINPUT_VERSION == 0x0700
589     if (IsEqualGUID( &IID_IUnknown, riid ) ||
590          IsEqualGUID( &IID_IDirectInputA,  riid ) ||
591          IsEqualGUID( &IID_IDirectInput2A, riid ) ||
592          IsEqualGUID( &IID_IDirectInput7A, riid ))
593         *ppobj = &This->IDirectInput7A_iface;
594     else if (IsEqualGUID( &IID_IDirectInputW,  riid ) ||
595              IsEqualGUID( &IID_IDirectInput2W, riid ) ||
596              IsEqualGUID( &IID_IDirectInput7W, riid ))
597         *ppobj = &This->IDirectInput7W_iface;
598 
599 #else
600     if (IsEqualGUID( &IID_IUnknown, riid ) ||
601         IsEqualGUID( &IID_IDirectInput8A, riid ))
602         *ppobj = &This->IDirectInput8A_iface;
603 
604     else if (IsEqualGUID( &IID_IDirectInput8W, riid ))
605         *ppobj = &This->IDirectInput8W_iface;
606 
607 #endif
608 
609     if (IsEqualGUID( &IID_IDirectInputJoyConfig8, riid ))
610         *ppobj = &This->IDirectInputJoyConfig8_iface;
611 
612     if(*ppobj)
613     {
614         IUnknown_AddRef( (IUnknown*)*ppobj );
615         return DI_OK;
616     }
617 
618     WARN( "Unsupported interface: %s\n", debugstr_guid(riid));
619     return E_NOINTERFACE;
620 }
621 
IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface,REFIID riid,LPVOID * ppobj)622 static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj)
623 {
624     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
625     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
626 }
627 
initialize_directinput_instance(IDirectInputImpl * This,DWORD dwVersion)628 static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion)
629 {
630     if (!This->initialized)
631     {
632         This->dwVersion = dwVersion;
633         This->evsequence = 1;
634 
635         InitializeCriticalSection( &This->crit );
636         This->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectInputImpl*->crit");
637 
638         list_init( &This->devices_list );
639         list_init( &This->device_players );
640 
641         /* Add self to the list of the IDirectInputs */
642         EnterCriticalSection( &dinput_hook_crit );
643         list_add_head( &direct_input_list, &This->entry );
644         LeaveCriticalSection( &dinput_hook_crit );
645 
646         This->initialized = TRUE;
647 
648         if (!check_hook_thread())
649         {
650             uninitialize_directinput_instance( This );
651             return DIERR_GENERIC;
652         }
653     }
654 
655     return DI_OK;
656 }
657 
uninitialize_directinput_instance(IDirectInputImpl * This)658 static void uninitialize_directinput_instance(IDirectInputImpl *This)
659 {
660     if (This->initialized)
661     {
662         struct DevicePlayer *device_player, *device_player2;
663         /* Remove self from the list of the IDirectInputs */
664         EnterCriticalSection( &dinput_hook_crit );
665         list_remove( &This->entry );
666         LeaveCriticalSection( &dinput_hook_crit );
667 
668         LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2,
669                 &This->device_players, struct DevicePlayer, entry )
670             HeapFree(GetProcessHeap(), 0, device_player);
671 
672         check_hook_thread();
673 
674         This->crit.DebugInfo->Spare[0] = 0;
675         DeleteCriticalSection( &This->crit );
676 
677         This->initialized = FALSE;
678     }
679 }
680 
681 enum directinput_versions
682 {
683     DIRECTINPUT_VERSION_300 = 0x0300,
684     DIRECTINPUT_VERSION_500 = 0x0500,
685     DIRECTINPUT_VERSION_50A = 0x050A,
686     DIRECTINPUT_VERSION_5B2 = 0x05B2,
687     DIRECTINPUT_VERSION_602 = 0x0602,
688     DIRECTINPUT_VERSION_61A = 0x061A,
689     DIRECTINPUT_VERSION_700 = 0x0700,
690 };
691 
IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface,HINSTANCE hinst,DWORD version)692 static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD version)
693 {
694     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
695 
696     TRACE("(%p)->(%p, 0x%04x)\n", This, hinst, version);
697 
698     if (!hinst)
699         return DIERR_INVALIDPARAM;
700     else if (version == 0)
701         return DIERR_NOTINITIALIZED;
702     else if (version > DIRECTINPUT_VERSION_700)
703         return DIERR_OLDDIRECTINPUTVERSION;
704     else if (version != DIRECTINPUT_VERSION_300 && version != DIRECTINPUT_VERSION_500 &&
705              version != DIRECTINPUT_VERSION_50A && version != DIRECTINPUT_VERSION_5B2 &&
706              version != DIRECTINPUT_VERSION_602 && version != DIRECTINPUT_VERSION_61A &&
707              version != DIRECTINPUT_VERSION_700 && version != DIRECTINPUT_VERSION)
708         return DIERR_BETADIRECTINPUTVERSION;
709 
710     return initialize_directinput_instance(This, version);
711 }
712 
IDirectInputWImpl_Initialize(LPDIRECTINPUT7W iface,HINSTANCE hinst,DWORD x)713 static HRESULT WINAPI IDirectInputWImpl_Initialize(LPDIRECTINPUT7W iface, HINSTANCE hinst, DWORD x)
714 {
715     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
716     return IDirectInputAImpl_Initialize( &This->IDirectInput7A_iface, hinst, x );
717 }
718 
IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface,REFGUID rguid)719 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, REFGUID rguid)
720 {
721     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
722     HRESULT hr;
723     LPDIRECTINPUTDEVICEA device;
724 
725     TRACE( "(%p)->(%s)\n", This, debugstr_guid(rguid) );
726 
727     if (!rguid) return E_POINTER;
728     if (!This->initialized)
729         return DIERR_NOTINITIALIZED;
730 
731     hr = IDirectInput_CreateDevice( iface, rguid, &device, NULL );
732     if (hr != DI_OK) return DI_NOTATTACHED;
733 
734     IUnknown_Release( device );
735 
736     return DI_OK;
737 }
738 
IDirectInputWImpl_GetDeviceStatus(LPDIRECTINPUT7W iface,REFGUID rguid)739 static HRESULT WINAPI IDirectInputWImpl_GetDeviceStatus(LPDIRECTINPUT7W iface, REFGUID rguid)
740 {
741     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
742     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
743 }
744 
IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface,HWND hwndOwner,DWORD dwFlags)745 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface,
746 							HWND hwndOwner,
747 							DWORD dwFlags)
748 {
749     WCHAR control_exeW[] = {'c','o','n','t','r','o','l','.','e','x','e',0};
750     STARTUPINFOW si = {0};
751     PROCESS_INFORMATION pi;
752 
753     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
754 
755     TRACE( "(%p)->(%p, %08x)\n", This, hwndOwner, dwFlags );
756 
757     if (hwndOwner && !IsWindow(hwndOwner))
758         return E_HANDLE;
759 
760     if (dwFlags)
761         return DIERR_INVALIDPARAM;
762 
763     if (!This->initialized)
764         return DIERR_NOTINITIALIZED;
765 
766     if (!CreateProcessW(NULL, control_exeW, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
767         return HRESULT_FROM_WIN32(GetLastError());
768 
769     return DI_OK;
770 }
771 
IDirectInputWImpl_RunControlPanel(LPDIRECTINPUT7W iface,HWND hwndOwner,DWORD dwFlags)772 static HRESULT WINAPI IDirectInputWImpl_RunControlPanel(LPDIRECTINPUT7W iface, HWND hwndOwner, DWORD dwFlags)
773 {
774     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
775     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
776 }
777 
IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface,REFGUID rguid,LPCSTR pszName,LPGUID pguidInstance)778 static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
779 						    LPCSTR pszName, LPGUID pguidInstance)
780 {
781     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
782 
783     FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance );
784 
785     return DI_OK;
786 }
787 
IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface,REFGUID rguid,LPCWSTR pszName,LPGUID pguidInstance)788 static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
789 						    LPCWSTR pszName, LPGUID pguidInstance)
790 {
791     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
792 
793     FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance );
794 
795     return DI_OK;
796 }
797 
create_device(IDirectInputImpl * This,REFGUID rguid,REFIID riid,LPVOID * pvOut,BOOL unicode)798 static HRESULT create_device(IDirectInputImpl *This, REFGUID rguid, REFIID riid, LPVOID *pvOut, BOOL unicode)
799 {
800     unsigned int i;
801 
802     if (pvOut)
803         *pvOut = NULL;
804 
805     if (!rguid || !pvOut)
806         return E_POINTER;
807 
808     if (!This->initialized)
809         return DIERR_NOTINITIALIZED;
810 
811     /* Loop on all the devices to see if anyone matches the given GUID */
812     for (i = 0; i < ARRAY_SIZE(dinput_devices); i++)
813     {
814         HRESULT ret;
815 
816         if (!dinput_devices[i]->create_device) continue;
817         if ((ret = dinput_devices[i]->create_device(This, rguid, riid, pvOut, unicode)) == DI_OK)
818             return DI_OK;
819     }
820 
821     WARN("invalid device GUID %s\n", debugstr_guid(rguid));
822     return DIERR_DEVICENOTREG;
823 }
824 
IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface,REFGUID rguid,REFIID riid,LPVOID * pvOut,LPUNKNOWN lpUnknownOuter)825 static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid,
826                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
827 {
828     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
829 
830     TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
831 
832     return create_device(This, rguid, riid, pvOut, FALSE);
833 }
834 
IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface,REFGUID rguid,REFIID riid,LPVOID * pvOut,LPUNKNOWN lpUnknownOuter)835 static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid,
836                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
837 {
838     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
839 
840     TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
841 
842     return create_device(This, rguid, riid, pvOut, TRUE);
843 }
844 
IDirectInputAImpl_CreateDevice(LPDIRECTINPUT7A iface,REFGUID rguid,LPDIRECTINPUTDEVICEA * pdev,LPUNKNOWN punk)845 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
846                                                      LPDIRECTINPUTDEVICEA* pdev, LPUNKNOWN punk)
847 {
848     return IDirectInput7AImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
849 }
850 
IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7W iface,REFGUID rguid,LPDIRECTINPUTDEVICEW * pdev,LPUNKNOWN punk)851 static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
852                                                      LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk)
853 {
854     return IDirectInput7WImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
855 }
856 
857 /*******************************************************************************
858  *      DirectInput8
859  */
860 
IDirectInput8AImpl_AddRef(LPDIRECTINPUT8A iface)861 static ULONG WINAPI IDirectInput8AImpl_AddRef(LPDIRECTINPUT8A iface)
862 {
863     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
864     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
865 }
866 
IDirectInput8WImpl_AddRef(LPDIRECTINPUT8W iface)867 static ULONG WINAPI IDirectInput8WImpl_AddRef(LPDIRECTINPUT8W iface)
868 {
869     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
870     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
871 }
872 
IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface,REFIID riid,LPVOID * ppobj)873 static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj)
874 {
875     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
876     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
877 }
878 
IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface,REFIID riid,LPVOID * ppobj)879 static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj)
880 {
881     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
882     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
883 }
884 
IDirectInput8AImpl_Release(LPDIRECTINPUT8A iface)885 static ULONG WINAPI IDirectInput8AImpl_Release(LPDIRECTINPUT8A iface)
886 {
887     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
888     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
889 }
890 
IDirectInput8WImpl_Release(LPDIRECTINPUT8W iface)891 static ULONG WINAPI IDirectInput8WImpl_Release(LPDIRECTINPUT8W iface)
892 {
893     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
894     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
895 }
896 
IDirectInput8AImpl_CreateDevice(LPDIRECTINPUT8A iface,REFGUID rguid,LPDIRECTINPUTDEVICE8A * pdev,LPUNKNOWN punk)897 static HRESULT WINAPI IDirectInput8AImpl_CreateDevice(LPDIRECTINPUT8A iface, REFGUID rguid,
898                                                       LPDIRECTINPUTDEVICE8A* pdev, LPUNKNOWN punk)
899 {
900     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
901     return IDirectInput7AImpl_CreateDeviceEx( &This->IDirectInput7A_iface, rguid, NULL, (LPVOID*)pdev, punk );
902 }
903 
IDirectInput8WImpl_CreateDevice(LPDIRECTINPUT8W iface,REFGUID rguid,LPDIRECTINPUTDEVICE8W * pdev,LPUNKNOWN punk)904 static HRESULT WINAPI IDirectInput8WImpl_CreateDevice(LPDIRECTINPUT8W iface, REFGUID rguid,
905                                                       LPDIRECTINPUTDEVICE8W* pdev, LPUNKNOWN punk)
906 {
907     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
908     return IDirectInput7WImpl_CreateDeviceEx( &This->IDirectInput7W_iface, rguid, NULL, (LPVOID*)pdev, punk );
909 }
910 
IDirectInput8AImpl_EnumDevices(LPDIRECTINPUT8A iface,DWORD dwDevType,LPDIENUMDEVICESCALLBACKA lpCallback,LPVOID pvRef,DWORD dwFlags)911 static HRESULT WINAPI IDirectInput8AImpl_EnumDevices(LPDIRECTINPUT8A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
912                                                      LPVOID pvRef, DWORD dwFlags)
913 {
914     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
915     return IDirectInputAImpl_EnumDevices( &This->IDirectInput7A_iface, dwDevType, lpCallback, pvRef, dwFlags );
916 }
917 
IDirectInput8WImpl_EnumDevices(LPDIRECTINPUT8W iface,DWORD dwDevType,LPDIENUMDEVICESCALLBACKW lpCallback,LPVOID pvRef,DWORD dwFlags)918 static HRESULT WINAPI IDirectInput8WImpl_EnumDevices(LPDIRECTINPUT8W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
919                                                      LPVOID pvRef, DWORD dwFlags)
920 {
921     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
922     return IDirectInputWImpl_EnumDevices( &This->IDirectInput7W_iface, dwDevType, lpCallback, pvRef, dwFlags );
923 }
924 
IDirectInput8AImpl_GetDeviceStatus(LPDIRECTINPUT8A iface,REFGUID rguid)925 static HRESULT WINAPI IDirectInput8AImpl_GetDeviceStatus(LPDIRECTINPUT8A iface, REFGUID rguid)
926 {
927     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
928     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
929 }
930 
IDirectInput8WImpl_GetDeviceStatus(LPDIRECTINPUT8W iface,REFGUID rguid)931 static HRESULT WINAPI IDirectInput8WImpl_GetDeviceStatus(LPDIRECTINPUT8W iface, REFGUID rguid)
932 {
933     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
934     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
935 }
936 
IDirectInput8AImpl_RunControlPanel(LPDIRECTINPUT8A iface,HWND hwndOwner,DWORD dwFlags)937 static HRESULT WINAPI IDirectInput8AImpl_RunControlPanel(LPDIRECTINPUT8A iface, HWND hwndOwner, DWORD dwFlags)
938 {
939     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
940     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
941 }
942 
IDirectInput8WImpl_RunControlPanel(LPDIRECTINPUT8W iface,HWND hwndOwner,DWORD dwFlags)943 static HRESULT WINAPI IDirectInput8WImpl_RunControlPanel(LPDIRECTINPUT8W iface, HWND hwndOwner, DWORD dwFlags)
944 {
945     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
946     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
947 }
948 
IDirectInput8AImpl_Initialize(LPDIRECTINPUT8A iface,HINSTANCE hinst,DWORD version)949 static HRESULT WINAPI IDirectInput8AImpl_Initialize(LPDIRECTINPUT8A iface, HINSTANCE hinst, DWORD version)
950 {
951     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
952 
953     TRACE("(%p)->(%p, 0x%04x)\n", This, hinst, version);
954 
955     if (!hinst)
956         return DIERR_INVALIDPARAM;
957     else if (version == 0)
958         return DIERR_NOTINITIALIZED;
959     else if (version < DIRECTINPUT_VERSION)
960         return DIERR_BETADIRECTINPUTVERSION;
961     else if (version > DIRECTINPUT_VERSION)
962         return DIERR_OLDDIRECTINPUTVERSION;
963 
964     return initialize_directinput_instance(This, version);
965 }
966 
IDirectInput8WImpl_Initialize(LPDIRECTINPUT8W iface,HINSTANCE hinst,DWORD version)967 static HRESULT WINAPI IDirectInput8WImpl_Initialize(LPDIRECTINPUT8W iface, HINSTANCE hinst, DWORD version)
968 {
969     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
970     return IDirectInput8AImpl_Initialize( &This->IDirectInput8A_iface, hinst, version );
971 }
972 
IDirectInput8AImpl_FindDevice(LPDIRECTINPUT8A iface,REFGUID rguid,LPCSTR pszName,LPGUID pguidInstance)973 static HRESULT WINAPI IDirectInput8AImpl_FindDevice(LPDIRECTINPUT8A iface, REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance)
974 {
975     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
976     return IDirectInput2AImpl_FindDevice( &This->IDirectInput7A_iface, rguid, pszName, pguidInstance );
977 }
978 
IDirectInput8WImpl_FindDevice(LPDIRECTINPUT8W iface,REFGUID rguid,LPCWSTR pszName,LPGUID pguidInstance)979 static HRESULT WINAPI IDirectInput8WImpl_FindDevice(LPDIRECTINPUT8W iface, REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance)
980 {
981     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
982     return IDirectInput2WImpl_FindDevice( &This->IDirectInput7W_iface, rguid, pszName, pguidInstance );
983 }
984 
should_enumerate_device(const WCHAR * username,DWORD dwFlags,struct list * device_players,REFGUID guid)985 static BOOL should_enumerate_device(const WCHAR *username, DWORD dwFlags,
986     struct list *device_players, REFGUID guid)
987 {
988     BOOL should_enumerate = TRUE;
989     struct DevicePlayer *device_player;
990 
991     /* Check if user owns this device */
992     if (dwFlags & DIEDBSFL_THISUSER && username && *username)
993     {
994         should_enumerate = FALSE;
995         LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry)
996         {
997             if (IsEqualGUID(&device_player->instance_guid, guid))
998             {
999                 if (*device_player->username && !lstrcmpW(username, device_player->username))
1000                     return TRUE; /* Device username matches */
1001                 break;
1002             }
1003         }
1004     }
1005 
1006     /* Check if this device is not owned by anyone */
1007     if (dwFlags & DIEDBSFL_AVAILABLEDEVICES) {
1008         BOOL found = FALSE;
1009         should_enumerate = FALSE;
1010         LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry)
1011         {
1012             if (IsEqualGUID(&device_player->instance_guid, guid))
1013             {
1014                 if (*device_player->username)
1015                     found = TRUE;
1016                 break;
1017             }
1018         }
1019         if (!found)
1020             return TRUE; /* Device does not have a username */
1021     }
1022 
1023     return should_enumerate;
1024 }
1025 
IDirectInput8AImpl_EnumDevicesBySemantics(LPDIRECTINPUT8A iface,LPCSTR ptszUserName,LPDIACTIONFORMATA lpdiActionFormat,LPDIENUMDEVICESBYSEMANTICSCBA lpCallback,LPVOID pvRef,DWORD dwFlags)1026 static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
1027       LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat,
1028       LPDIENUMDEVICESBYSEMANTICSCBA lpCallback,
1029       LPVOID pvRef, DWORD dwFlags
1030 )
1031 {
1032     static REFGUID guids[2] = { &GUID_SysKeyboard, &GUID_SysMouse };
1033     static const DWORD actionMasks[] = { DIKEYBOARD_MASK, DIMOUSE_MASK };
1034     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
1035     DIDEVICEINSTANCEA didevi;
1036     LPDIRECTINPUTDEVICE8A lpdid;
1037     DWORD callbackFlags;
1038     int i, j;
1039     int device_count = 0;
1040     int remain;
1041     DIDEVICEINSTANCEA *didevis = 0;
1042     WCHAR *username_w = 0;
1043 
1044     FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, debugstr_a(ptszUserName), lpdiActionFormat,
1045           lpCallback, pvRef, dwFlags);
1046 #define X(x) if (dwFlags & x) FIXME("\tdwFlags |= "#x"\n");
1047 	X(DIEDBSFL_ATTACHEDONLY)
1048 	X(DIEDBSFL_THISUSER)
1049 	X(DIEDBSFL_FORCEFEEDBACK)
1050 	X(DIEDBSFL_AVAILABLEDEVICES)
1051 	X(DIEDBSFL_MULTIMICEKEYBOARDS)
1052 	X(DIEDBSFL_NONGAMINGDEVICES)
1053 #undef X
1054 
1055     _dump_diactionformatA(lpdiActionFormat);
1056 
1057     didevi.dwSize = sizeof(didevi);
1058 
1059     if (ptszUserName)
1060     {
1061         int len = MultiByteToWideChar(CP_ACP, 0, ptszUserName, -1, 0, 0);
1062 
1063         username_w = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
1064         MultiByteToWideChar(CP_ACP, 0, ptszUserName, -1, username_w, len);
1065     }
1066 
1067     /* Enumerate all the joysticks */
1068     for (i = 0; i < ARRAY_SIZE(dinput_devices); i++)
1069     {
1070         HRESULT enumSuccess;
1071 
1072         if (!dinput_devices[i]->enum_deviceA) continue;
1073 
1074         for (j = 0, enumSuccess = S_OK; SUCCEEDED(enumSuccess); j++)
1075         {
1076             TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name);
1077 
1078             /* Default behavior is to enumerate attached game controllers */
1079             enumSuccess = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j);
1080             if (enumSuccess == S_OK &&
1081                 should_enumerate_device(username_w, dwFlags, &This->device_players, &didevi.guidInstance))
1082             {
1083                 if (device_count++)
1084                     didevis = HeapReAlloc(GetProcessHeap(), 0, didevis, sizeof(DIDEVICEINSTANCEA)*device_count);
1085                 else
1086                     didevis = HeapAlloc(GetProcessHeap(), 0, sizeof(DIDEVICEINSTANCEA)*device_count);
1087                 didevis[device_count-1] = didevi;
1088             }
1089         }
1090     }
1091 
1092     remain = device_count;
1093     /* Add keyboard and mouse to remaining device count */
1094     if (!(dwFlags & DIEDBSFL_FORCEFEEDBACK))
1095     {
1096         for (i = 0; i < ARRAY_SIZE(guids); i++)
1097         {
1098             if (should_enumerate_device(username_w, dwFlags, &This->device_players, guids[i]))
1099                 remain++;
1100         }
1101     }
1102 
1103     for (i = 0; i < device_count; i++)
1104     {
1105         callbackFlags = diactionformat_priorityA(lpdiActionFormat, lpdiActionFormat->dwGenre);
1106         IDirectInput_CreateDevice(iface, &didevis[i].guidInstance, &lpdid, NULL);
1107 
1108         if (lpCallback(&didevis[i], lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
1109         {
1110             IDirectInputDevice_Release(lpdid);
1111             HeapFree(GetProcessHeap(), 0, didevis);
1112             HeapFree(GetProcessHeap(), 0, username_w);
1113             return DI_OK;
1114         }
1115         IDirectInputDevice_Release(lpdid);
1116     }
1117 
1118     HeapFree(GetProcessHeap(), 0, didevis);
1119 
1120     if (dwFlags & DIEDBSFL_FORCEFEEDBACK)
1121     {
1122         HeapFree(GetProcessHeap(), 0, username_w);
1123         return DI_OK;
1124     }
1125 
1126     /* Enumerate keyboard and mouse */
1127     for (i = 0; i < ARRAY_SIZE(guids); i++)
1128     {
1129         if (should_enumerate_device(username_w, dwFlags, &This->device_players, guids[i]))
1130         {
1131             callbackFlags = diactionformat_priorityA(lpdiActionFormat, actionMasks[i]);
1132 
1133             IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL);
1134             IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
1135 
1136             if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
1137             {
1138                 IDirectInputDevice_Release(lpdid);
1139                 HeapFree(GetProcessHeap(), 0, username_w);
1140                 return DI_OK;
1141             }
1142             IDirectInputDevice_Release(lpdid);
1143         }
1144     }
1145 
1146     HeapFree(GetProcessHeap(), 0, username_w);
1147     return DI_OK;
1148 }
1149 
IDirectInput8WImpl_EnumDevicesBySemantics(LPDIRECTINPUT8W iface,LPCWSTR ptszUserName,LPDIACTIONFORMATW lpdiActionFormat,LPDIENUMDEVICESBYSEMANTICSCBW lpCallback,LPVOID pvRef,DWORD dwFlags)1150 static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
1151       LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat,
1152       LPDIENUMDEVICESBYSEMANTICSCBW lpCallback,
1153       LPVOID pvRef, DWORD dwFlags
1154 )
1155 {
1156     static REFGUID guids[2] = { &GUID_SysKeyboard, &GUID_SysMouse };
1157     static const DWORD actionMasks[] = { DIKEYBOARD_MASK, DIMOUSE_MASK };
1158     IDirectInputImpl *This = impl_from_IDirectInput8W(iface);
1159     DIDEVICEINSTANCEW didevi;
1160     LPDIRECTINPUTDEVICE8W lpdid;
1161     DWORD callbackFlags;
1162     int i, j;
1163     int device_count = 0;
1164     int remain;
1165     DIDEVICEINSTANCEW *didevis = 0;
1166 
1167     FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat,
1168           lpCallback, pvRef, dwFlags);
1169 
1170     didevi.dwSize = sizeof(didevi);
1171 
1172     /* Enumerate all the joysticks */
1173     for (i = 0; i < ARRAY_SIZE(dinput_devices); i++)
1174     {
1175         HRESULT enumSuccess;
1176 
1177         if (!dinput_devices[i]->enum_deviceW) continue;
1178 
1179         for (j = 0, enumSuccess = S_OK; SUCCEEDED(enumSuccess); j++)
1180         {
1181             TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name);
1182 
1183             /* Default behavior is to enumerate attached game controllers */
1184             enumSuccess = dinput_devices[i]->enum_deviceW(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j);
1185             if (enumSuccess == S_OK &&
1186                 should_enumerate_device(ptszUserName, dwFlags, &This->device_players, &didevi.guidInstance))
1187             {
1188                 if (device_count++)
1189                     didevis = HeapReAlloc(GetProcessHeap(), 0, didevis, sizeof(DIDEVICEINSTANCEW)*device_count);
1190                 else
1191                     didevis = HeapAlloc(GetProcessHeap(), 0, sizeof(DIDEVICEINSTANCEW)*device_count);
1192                 didevis[device_count-1] = didevi;
1193             }
1194         }
1195     }
1196 
1197     remain = device_count;
1198     /* Add keyboard and mouse to remaining device count */
1199     if (!(dwFlags & DIEDBSFL_FORCEFEEDBACK))
1200     {
1201         for (i = 0; i < ARRAY_SIZE(guids); i++)
1202         {
1203             if (should_enumerate_device(ptszUserName, dwFlags, &This->device_players, guids[i]))
1204                 remain++;
1205         }
1206     }
1207 
1208     for (i = 0; i < device_count; i++)
1209     {
1210         callbackFlags = diactionformat_priorityW(lpdiActionFormat, lpdiActionFormat->dwGenre);
1211         IDirectInput_CreateDevice(iface, &didevis[i].guidInstance, &lpdid, NULL);
1212 
1213         if (lpCallback(&didevis[i], lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
1214         {
1215             HeapFree(GetProcessHeap(), 0, didevis);
1216             return DI_OK;
1217         }
1218     }
1219 
1220     HeapFree(GetProcessHeap(), 0, didevis);
1221 
1222     if (dwFlags & DIEDBSFL_FORCEFEEDBACK) return DI_OK;
1223 
1224     /* Enumerate keyboard and mouse */
1225     for (i = 0; i < ARRAY_SIZE(guids); i++)
1226     {
1227         if (should_enumerate_device(ptszUserName, dwFlags, &This->device_players, guids[i]))
1228         {
1229             callbackFlags = diactionformat_priorityW(lpdiActionFormat, actionMasks[i]);
1230 
1231             IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL);
1232             IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
1233 
1234             if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
1235                 return DI_OK;
1236         }
1237     }
1238 
1239     return DI_OK;
1240 }
1241 
IDirectInput8WImpl_ConfigureDevices(LPDIRECTINPUT8W iface,LPDICONFIGUREDEVICESCALLBACK lpdiCallback,LPDICONFIGUREDEVICESPARAMSW lpdiCDParams,DWORD dwFlags,LPVOID pvRefData)1242 static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices(
1243       LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
1244       LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
1245 )
1246 {
1247     IDirectInputImpl *This = impl_from_IDirectInput8W(iface);
1248 
1249     FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams, dwFlags, pvRefData);
1250 
1251     /* Call helper function in config.c to do the real work */
1252     return _configure_devices(iface, lpdiCallback, lpdiCDParams, dwFlags, pvRefData);
1253 }
1254 
IDirectInput8AImpl_ConfigureDevices(LPDIRECTINPUT8A iface,LPDICONFIGUREDEVICESCALLBACK lpdiCallback,LPDICONFIGUREDEVICESPARAMSA lpdiCDParams,DWORD dwFlags,LPVOID pvRefData)1255 static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
1256       LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
1257       LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
1258 )
1259 {
1260     IDirectInputImpl *This = impl_from_IDirectInput8A(iface);
1261     DIACTIONFORMATW diafW;
1262     DICONFIGUREDEVICESPARAMSW diCDParamsW;
1263     HRESULT hr;
1264     int i;
1265 
1266      FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams, dwFlags, pvRefData);
1267 
1268     /* Copy parameters */
1269     diCDParamsW.dwSize = sizeof(DICONFIGUREDEVICESPARAMSW);
1270     diCDParamsW.dwcUsers = lpdiCDParams->dwcUsers;
1271     diCDParamsW.dwcFormats = lpdiCDParams->dwcFormats;
1272     diCDParamsW.lprgFormats = &diafW;
1273     diCDParamsW.hwnd = lpdiCDParams->hwnd;
1274     diCDParamsW.lptszUserNames = NULL;
1275 
1276     if (lpdiCDParams->lptszUserNames) {
1277         char *start = lpdiCDParams->lptszUserNames;
1278         WCHAR *to = NULL;
1279         int total_len = 0;
1280         for (i = 0; i < lpdiCDParams->dwcUsers; i++)
1281         {
1282             char *end = start + 1;
1283             int len;
1284             while (*(end++));
1285             len = MultiByteToWideChar(CP_ACP, 0, start, end - start, NULL, 0);
1286             total_len += len + 2; /* length of string and two null char */
1287             if (to)
1288                 to = HeapReAlloc(GetProcessHeap(), 0, to, sizeof(WCHAR) * total_len);
1289             else
1290                 to = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * total_len);
1291 
1292             MultiByteToWideChar(CP_ACP, 0, start, end - start, to + (total_len - len - 2), len);
1293             to[total_len] = 0;
1294             to[total_len - 1] = 0;
1295         }
1296         diCDParamsW.lptszUserNames = to;
1297     }
1298 
1299     diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiCDParams->lprgFormats->dwNumActions);
1300     _copy_diactionformatAtoW(&diafW, lpdiCDParams->lprgFormats);
1301 
1302     /* Copy action names */
1303     for (i=0; i < diafW.dwNumActions; i++)
1304     {
1305         const char* from = lpdiCDParams->lprgFormats->rgoAction[i].u.lptszActionName;
1306         int len = MultiByteToWideChar(CP_ACP, 0, from , -1, NULL , 0);
1307         WCHAR *to = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
1308 
1309         MultiByteToWideChar(CP_ACP, 0, from , -1, to , len);
1310         diafW.rgoAction[i].u.lptszActionName = to;
1311     }
1312 
1313     hr = IDirectInput8WImpl_ConfigureDevices(&This->IDirectInput8W_iface, lpdiCallback, &diCDParamsW, dwFlags, pvRefData);
1314 
1315     /* Copy back configuration */
1316     if (SUCCEEDED(hr))
1317         _copy_diactionformatWtoA(lpdiCDParams->lprgFormats, &diafW);
1318 
1319     /* Free memory */
1320     for (i=0; i < diafW.dwNumActions; i++)
1321         HeapFree(GetProcessHeap(), 0, (void*) diafW.rgoAction[i].u.lptszActionName);
1322 
1323     HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
1324 
1325     heap_free((void*) diCDParamsW.lptszUserNames);
1326 
1327     return hr;
1328 }
1329 
1330 /*****************************************************************************
1331  * IDirectInputJoyConfig8 interface
1332  */
1333 
impl_from_IDirectInputJoyConfig8(IDirectInputJoyConfig8 * iface)1334 static inline IDirectInputImpl *impl_from_IDirectInputJoyConfig8(IDirectInputJoyConfig8 *iface)
1335 {
1336     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInputJoyConfig8_iface );
1337 }
1338 
JoyConfig8Impl_QueryInterface(IDirectInputJoyConfig8 * iface,REFIID riid,void ** ppobj)1339 static HRESULT WINAPI JoyConfig8Impl_QueryInterface(IDirectInputJoyConfig8 *iface, REFIID riid, void** ppobj)
1340 {
1341     IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface );
1342     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
1343 }
1344 
JoyConfig8Impl_AddRef(IDirectInputJoyConfig8 * iface)1345 static ULONG WINAPI JoyConfig8Impl_AddRef(IDirectInputJoyConfig8 *iface)
1346 {
1347     IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface );
1348     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
1349 }
1350 
JoyConfig8Impl_Release(IDirectInputJoyConfig8 * iface)1351 static ULONG WINAPI JoyConfig8Impl_Release(IDirectInputJoyConfig8 *iface)
1352 {
1353     IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface );
1354     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
1355 }
1356 
JoyConfig8Impl_Acquire(IDirectInputJoyConfig8 * iface)1357 static HRESULT WINAPI JoyConfig8Impl_Acquire(IDirectInputJoyConfig8 *iface)
1358 {
1359     FIXME( "(%p): stub!\n", iface );
1360     return E_NOTIMPL;
1361 }
1362 
JoyConfig8Impl_Unacquire(IDirectInputJoyConfig8 * iface)1363 static HRESULT WINAPI JoyConfig8Impl_Unacquire(IDirectInputJoyConfig8 *iface)
1364 {
1365     FIXME( "(%p): stub!\n", iface );
1366     return E_NOTIMPL;
1367 }
1368 
JoyConfig8Impl_SetCooperativeLevel(IDirectInputJoyConfig8 * iface,HWND hwnd,DWORD flags)1369 static HRESULT WINAPI JoyConfig8Impl_SetCooperativeLevel(IDirectInputJoyConfig8 *iface, HWND hwnd, DWORD flags)
1370 {
1371     FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, hwnd, flags );
1372     return E_NOTIMPL;
1373 }
1374 
JoyConfig8Impl_SendNotify(IDirectInputJoyConfig8 * iface)1375 static HRESULT WINAPI JoyConfig8Impl_SendNotify(IDirectInputJoyConfig8 *iface)
1376 {
1377     FIXME( "(%p): stub!\n", iface );
1378     return E_NOTIMPL;
1379 }
1380 
JoyConfig8Impl_EnumTypes(IDirectInputJoyConfig8 * iface,LPDIJOYTYPECALLBACK cb,void * ref)1381 static HRESULT WINAPI JoyConfig8Impl_EnumTypes(IDirectInputJoyConfig8 *iface, LPDIJOYTYPECALLBACK cb, void *ref)
1382 {
1383     FIXME( "(%p)->(%p, %p): stub!\n", iface, cb, ref );
1384     return E_NOTIMPL;
1385 }
1386 
JoyConfig8Impl_GetTypeInfo(IDirectInputJoyConfig8 * iface,LPCWSTR name,LPDIJOYTYPEINFO info,DWORD flags)1387 static HRESULT WINAPI JoyConfig8Impl_GetTypeInfo(IDirectInputJoyConfig8 *iface, LPCWSTR name, LPDIJOYTYPEINFO info, DWORD flags)
1388 {
1389     FIXME( "(%p)->(%s, %p, 0x%08x): stub!\n", iface, debugstr_w(name), info, flags );
1390     return E_NOTIMPL;
1391 }
1392 
JoyConfig8Impl_SetTypeInfo(IDirectInputJoyConfig8 * iface,LPCWSTR name,LPCDIJOYTYPEINFO info,DWORD flags,LPWSTR new_name)1393 static HRESULT WINAPI JoyConfig8Impl_SetTypeInfo(IDirectInputJoyConfig8 *iface, LPCWSTR name, LPCDIJOYTYPEINFO info, DWORD flags,
1394                                                  LPWSTR new_name)
1395 {
1396     FIXME( "(%p)->(%s, %p, 0x%08x, %s): stub!\n", iface, debugstr_w(name), info, flags, debugstr_w(new_name) );
1397     return E_NOTIMPL;
1398 }
1399 
JoyConfig8Impl_DeleteType(IDirectInputJoyConfig8 * iface,LPCWSTR name)1400 static HRESULT WINAPI JoyConfig8Impl_DeleteType(IDirectInputJoyConfig8 *iface, LPCWSTR name)
1401 {
1402     FIXME( "(%p)->(%s): stub!\n", iface, debugstr_w(name) );
1403     return E_NOTIMPL;
1404 }
1405 
JoyConfig8Impl_GetConfig(IDirectInputJoyConfig8 * iface,UINT id,LPDIJOYCONFIG info,DWORD flags)1406 static HRESULT WINAPI JoyConfig8Impl_GetConfig(IDirectInputJoyConfig8 *iface, UINT id, LPDIJOYCONFIG info, DWORD flags)
1407 {
1408     IDirectInputImpl *di = impl_from_IDirectInputJoyConfig8(iface);
1409     UINT found = 0;
1410     int i, j;
1411     HRESULT r;
1412 
1413     FIXME("(%p)->(%d, %p, 0x%08x): semi-stub!\n", iface, id, info, flags);
1414 
1415 #define X(x) if (flags & x) FIXME("\tflags |= "#x"\n");
1416     X(DIJC_GUIDINSTANCE)
1417     X(DIJC_REGHWCONFIGTYPE)
1418     X(DIJC_GAIN)
1419     X(DIJC_CALLOUT)
1420 #undef X
1421 
1422     /* Enumerate all joysticks in order */
1423     for (i = 0; i < ARRAY_SIZE(dinput_devices); i++)
1424     {
1425         if (!dinput_devices[i]->enum_deviceA) continue;
1426 
1427         for (j = 0, r = S_OK; SUCCEEDED(r); j++)
1428         {
1429             DIDEVICEINSTANCEA dev;
1430             dev.dwSize = sizeof(dev);
1431             if ((r = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, 0, &dev, di->dwVersion, j)) == S_OK)
1432             {
1433                 /* Only take into account the chosen id */
1434                 if (found == id)
1435                 {
1436                     if (flags & DIJC_GUIDINSTANCE)
1437                         info->guidInstance = dev.guidInstance;
1438 
1439                     return DI_OK;
1440                 }
1441                 found += 1;
1442             }
1443         }
1444     }
1445 
1446     return DIERR_NOMOREITEMS;
1447 }
1448 
JoyConfig8Impl_SetConfig(IDirectInputJoyConfig8 * iface,UINT id,LPCDIJOYCONFIG info,DWORD flags)1449 static HRESULT WINAPI JoyConfig8Impl_SetConfig(IDirectInputJoyConfig8 *iface, UINT id, LPCDIJOYCONFIG info, DWORD flags)
1450 {
1451     FIXME( "(%p)->(%d, %p, 0x%08x): stub!\n", iface, id, info, flags );
1452     return E_NOTIMPL;
1453 }
1454 
JoyConfig8Impl_DeleteConfig(IDirectInputJoyConfig8 * iface,UINT id)1455 static HRESULT WINAPI JoyConfig8Impl_DeleteConfig(IDirectInputJoyConfig8 *iface, UINT id)
1456 {
1457     FIXME( "(%p)->(%d): stub!\n", iface, id );
1458     return E_NOTIMPL;
1459 }
1460 
JoyConfig8Impl_GetUserValues(IDirectInputJoyConfig8 * iface,LPDIJOYUSERVALUES info,DWORD flags)1461 static HRESULT WINAPI JoyConfig8Impl_GetUserValues(IDirectInputJoyConfig8 *iface, LPDIJOYUSERVALUES info, DWORD flags)
1462 {
1463     FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, info, flags );
1464     return E_NOTIMPL;
1465 }
1466 
JoyConfig8Impl_SetUserValues(IDirectInputJoyConfig8 * iface,LPCDIJOYUSERVALUES info,DWORD flags)1467 static HRESULT WINAPI JoyConfig8Impl_SetUserValues(IDirectInputJoyConfig8 *iface, LPCDIJOYUSERVALUES info, DWORD flags)
1468 {
1469     FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, info, flags );
1470     return E_NOTIMPL;
1471 }
1472 
JoyConfig8Impl_AddNewHardware(IDirectInputJoyConfig8 * iface,HWND hwnd,REFGUID guid)1473 static HRESULT WINAPI JoyConfig8Impl_AddNewHardware(IDirectInputJoyConfig8 *iface, HWND hwnd, REFGUID guid)
1474 {
1475     FIXME( "(%p)->(%p, %s): stub!\n", iface, hwnd, debugstr_guid(guid) );
1476     return E_NOTIMPL;
1477 }
1478 
JoyConfig8Impl_OpenTypeKey(IDirectInputJoyConfig8 * iface,LPCWSTR name,DWORD security,PHKEY key)1479 static HRESULT WINAPI JoyConfig8Impl_OpenTypeKey(IDirectInputJoyConfig8 *iface, LPCWSTR name, DWORD security, PHKEY key)
1480 {
1481     FIXME( "(%p)->(%s, 0x%08x, %p): stub!\n", iface, debugstr_w(name), security, key );
1482     return E_NOTIMPL;
1483 }
1484 
JoyConfig8Impl_OpenAppStatusKey(IDirectInputJoyConfig8 * iface,PHKEY key)1485 static HRESULT WINAPI JoyConfig8Impl_OpenAppStatusKey(IDirectInputJoyConfig8 *iface, PHKEY key)
1486 {
1487     FIXME( "(%p)->(%p): stub!\n", iface, key );
1488     return E_NOTIMPL;
1489 }
1490 
1491 static const IDirectInput7AVtbl ddi7avt = {
1492     IDirectInputAImpl_QueryInterface,
1493     IDirectInputAImpl_AddRef,
1494     IDirectInputAImpl_Release,
1495     IDirectInputAImpl_CreateDevice,
1496     IDirectInputAImpl_EnumDevices,
1497     IDirectInputAImpl_GetDeviceStatus,
1498     IDirectInputAImpl_RunControlPanel,
1499     IDirectInputAImpl_Initialize,
1500     IDirectInput2AImpl_FindDevice,
1501     IDirectInput7AImpl_CreateDeviceEx
1502 };
1503 
1504 static const IDirectInput7WVtbl ddi7wvt = {
1505     IDirectInputWImpl_QueryInterface,
1506     IDirectInputWImpl_AddRef,
1507     IDirectInputWImpl_Release,
1508     IDirectInputWImpl_CreateDevice,
1509     IDirectInputWImpl_EnumDevices,
1510     IDirectInputWImpl_GetDeviceStatus,
1511     IDirectInputWImpl_RunControlPanel,
1512     IDirectInputWImpl_Initialize,
1513     IDirectInput2WImpl_FindDevice,
1514     IDirectInput7WImpl_CreateDeviceEx
1515 };
1516 
1517 static const IDirectInput8AVtbl ddi8avt = {
1518     IDirectInput8AImpl_QueryInterface,
1519     IDirectInput8AImpl_AddRef,
1520     IDirectInput8AImpl_Release,
1521     IDirectInput8AImpl_CreateDevice,
1522     IDirectInput8AImpl_EnumDevices,
1523     IDirectInput8AImpl_GetDeviceStatus,
1524     IDirectInput8AImpl_RunControlPanel,
1525     IDirectInput8AImpl_Initialize,
1526     IDirectInput8AImpl_FindDevice,
1527     IDirectInput8AImpl_EnumDevicesBySemantics,
1528     IDirectInput8AImpl_ConfigureDevices
1529 };
1530 
1531 static const IDirectInput8WVtbl ddi8wvt = {
1532     IDirectInput8WImpl_QueryInterface,
1533     IDirectInput8WImpl_AddRef,
1534     IDirectInput8WImpl_Release,
1535     IDirectInput8WImpl_CreateDevice,
1536     IDirectInput8WImpl_EnumDevices,
1537     IDirectInput8WImpl_GetDeviceStatus,
1538     IDirectInput8WImpl_RunControlPanel,
1539     IDirectInput8WImpl_Initialize,
1540     IDirectInput8WImpl_FindDevice,
1541     IDirectInput8WImpl_EnumDevicesBySemantics,
1542     IDirectInput8WImpl_ConfigureDevices
1543 };
1544 
1545 static const IDirectInputJoyConfig8Vtbl JoyConfig8vt =
1546 {
1547     JoyConfig8Impl_QueryInterface,
1548     JoyConfig8Impl_AddRef,
1549     JoyConfig8Impl_Release,
1550     JoyConfig8Impl_Acquire,
1551     JoyConfig8Impl_Unacquire,
1552     JoyConfig8Impl_SetCooperativeLevel,
1553     JoyConfig8Impl_SendNotify,
1554     JoyConfig8Impl_EnumTypes,
1555     JoyConfig8Impl_GetTypeInfo,
1556     JoyConfig8Impl_SetTypeInfo,
1557     JoyConfig8Impl_DeleteType,
1558     JoyConfig8Impl_GetConfig,
1559     JoyConfig8Impl_SetConfig,
1560     JoyConfig8Impl_DeleteConfig,
1561     JoyConfig8Impl_GetUserValues,
1562     JoyConfig8Impl_SetUserValues,
1563     JoyConfig8Impl_AddNewHardware,
1564     JoyConfig8Impl_OpenTypeKey,
1565     JoyConfig8Impl_OpenAppStatusKey
1566 };
1567 
1568 /*******************************************************************************
1569  * DirectInput ClassFactory
1570  */
1571 typedef struct
1572 {
1573     /* IUnknown fields */
1574     IClassFactory IClassFactory_iface;
1575     LONG          ref;
1576 } IClassFactoryImpl;
1577 
impl_from_IClassFactory(IClassFactory * iface)1578 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1579 {
1580         return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
1581 }
1582 
DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID * ppobj)1583 static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1584 	IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1585 
1586 	FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1587 	return E_NOINTERFACE;
1588 }
1589 
DICF_AddRef(LPCLASSFACTORY iface)1590 static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) {
1591 	IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1592 	return InterlockedIncrement(&(This->ref));
1593 }
1594 
DICF_Release(LPCLASSFACTORY iface)1595 static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) {
1596 	IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1597 	/* static class, won't be  freed */
1598 	return InterlockedDecrement(&(This->ref));
1599 }
1600 
DICF_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID * ppobj)1601 static HRESULT WINAPI DICF_CreateInstance(
1602 	LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
1603 ) {
1604 	IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1605 
1606 	TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1607         if ( IsEqualGUID( &IID_IUnknown, riid ) ||
1608              IsEqualGUID( &IID_IDirectInputA, riid ) ||
1609 	     IsEqualGUID( &IID_IDirectInputW, riid ) ||
1610 	     IsEqualGUID( &IID_IDirectInput2A, riid ) ||
1611 	     IsEqualGUID( &IID_IDirectInput2W, riid ) ||
1612 	     IsEqualGUID( &IID_IDirectInput7A, riid ) ||
1613             IsEqualGUID( &IID_IDirectInput7W, riid ) ||
1614             IsEqualGUID( &IID_IDirectInput8A, riid ) ||
1615 	     IsEqualGUID( &IID_IDirectInput8W, riid ) )
1616         {
1617 		return create_directinput_instance(riid, ppobj, NULL);
1618 	}
1619 
1620 	FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
1621 	return E_NOINTERFACE;
1622 }
1623 
DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock)1624 static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1625 	IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1626 	FIXME("(%p)->(%d),stub!\n",This,dolock);
1627 	return S_OK;
1628 }
1629 
1630 static const IClassFactoryVtbl DICF_Vtbl = {
1631 	DICF_QueryInterface,
1632 	DICF_AddRef,
1633 	DICF_Release,
1634 	DICF_CreateInstance,
1635 	DICF_LockServer
1636 };
1637 static IClassFactoryImpl DINPUT_CF = {{&DICF_Vtbl}, 1 };
1638 
1639 /***********************************************************************
1640  *		DllCanUnloadNow (DINPUT.@)
1641  */
DllCanUnloadNow(void)1642 HRESULT WINAPI DllCanUnloadNow(void)
1643 {
1644     return S_FALSE;
1645 }
1646 
1647 /***********************************************************************
1648  *		DllGetClassObject (DINPUT.@)
1649  */
DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID * ppv)1650 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1651 {
1652     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1653     if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1654         *ppv = &DINPUT_CF;
1655 	IClassFactory_AddRef((IClassFactory*)*ppv);
1656     return S_OK;
1657     }
1658 
1659     FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1660     return CLASS_E_CLASSNOTAVAILABLE;
1661 }
1662 
1663 /***********************************************************************
1664  *		DllRegisterServer (DINPUT.@)
1665  */
DllRegisterServer(void)1666 HRESULT WINAPI DllRegisterServer(void)
1667 {
1668     return __wine_register_resources( DINPUT_instance );
1669 }
1670 
1671 /***********************************************************************
1672  *		DllUnregisterServer (DINPUT.@)
1673  */
DllUnregisterServer(void)1674 HRESULT WINAPI DllUnregisterServer(void)
1675 {
1676     return __wine_unregister_resources( DINPUT_instance );
1677 }
1678 
1679 /******************************************************************************
1680  *	DInput hook thread
1681  */
1682 
LL_hook_proc(int code,WPARAM wparam,LPARAM lparam)1683 static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam )
1684 {
1685     IDirectInputImpl *dinput;
1686     int skip = 0;
1687 
1688     if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam );
1689 
1690     EnterCriticalSection( &dinput_hook_crit );
1691     LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1692     {
1693         IDirectInputDeviceImpl *dev;
1694 
1695         EnterCriticalSection( &dinput->crit );
1696         LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1697             if (dev->acquired && dev->event_proc)
1698             {
1699                 TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam);
1700                 skip |= dev->event_proc( &dev->IDirectInputDevice8A_iface, wparam, lparam );
1701             }
1702         LeaveCriticalSection( &dinput->crit );
1703     }
1704     LeaveCriticalSection( &dinput_hook_crit );
1705 
1706     return skip ? 1 : CallNextHookEx( 0, code, wparam, lparam );
1707 }
1708 
callwndproc_proc(int code,WPARAM wparam,LPARAM lparam)1709 static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam )
1710 {
1711     CWPSTRUCT *msg = (CWPSTRUCT *)lparam;
1712     IDirectInputImpl *dinput;
1713     HWND foreground;
1714 
1715     if (code != HC_ACTION || (msg->message != WM_KILLFOCUS &&
1716         msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE))
1717         return CallNextHookEx( 0, code, wparam, lparam );
1718 
1719     foreground = GetForegroundWindow();
1720 
1721     EnterCriticalSection( &dinput_hook_crit );
1722 
1723     LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1724     {
1725         IDirectInputDeviceImpl *dev;
1726 
1727         EnterCriticalSection( &dinput->crit );
1728         LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1729         {
1730             if (!dev->acquired) continue;
1731 
1732             if (msg->hwnd == dev->win && msg->hwnd != foreground)
1733             {
1734                 TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev );
1735                 IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8A_iface );
1736             }
1737         }
1738         LeaveCriticalSection( &dinput->crit );
1739     }
1740     LeaveCriticalSection( &dinput_hook_crit );
1741 
1742     return CallNextHookEx( 0, code, wparam, lparam );
1743 }
1744 
hook_thread_proc(void * param)1745 static DWORD WINAPI hook_thread_proc(void *param)
1746 {
1747     static HHOOK kbd_hook, mouse_hook;
1748     MSG msg;
1749 
1750     /* Force creation of the message queue */
1751     PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE );
1752     SetEvent(param);
1753 
1754     while (GetMessageW( &msg, 0, 0, 0 ))
1755     {
1756         UINT kbd_cnt = 0, mice_cnt = 0;
1757 
1758         if (msg.message == WM_USER+0x10)
1759         {
1760             IDirectInputImpl *dinput;
1761 
1762             TRACE( "Processing hook change notification lp:%ld\n", msg.lParam );
1763 
1764             if (!msg.wParam && !msg.lParam)
1765             {
1766                 if (kbd_hook) UnhookWindowsHookEx( kbd_hook );
1767                 if (mouse_hook) UnhookWindowsHookEx( mouse_hook );
1768                 kbd_hook = mouse_hook = NULL;
1769                 break;
1770             }
1771 
1772             EnterCriticalSection( &dinput_hook_crit );
1773 
1774             /* Count acquired keyboards and mice*/
1775             LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1776             {
1777                 IDirectInputDeviceImpl *dev;
1778 
1779                 EnterCriticalSection( &dinput->crit );
1780                 LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1781                 {
1782                     if (!dev->acquired || !dev->event_proc) continue;
1783 
1784                     if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard ))
1785                         kbd_cnt++;
1786                     else
1787                         if (IsEqualGUID( &dev->guid, &GUID_SysMouse ))
1788                             mice_cnt++;
1789                 }
1790                 LeaveCriticalSection( &dinput->crit );
1791             }
1792             LeaveCriticalSection( &dinput_hook_crit );
1793 
1794             if (kbd_cnt && !kbd_hook)
1795                 kbd_hook = SetWindowsHookExW( WH_KEYBOARD_LL, LL_hook_proc, DINPUT_instance, 0 );
1796             else if (!kbd_cnt && kbd_hook)
1797             {
1798                 UnhookWindowsHookEx( kbd_hook );
1799                 kbd_hook = NULL;
1800             }
1801 
1802             if (mice_cnt && !mouse_hook)
1803                 mouse_hook = SetWindowsHookExW( WH_MOUSE_LL, LL_hook_proc, DINPUT_instance, 0 );
1804             else if (!mice_cnt && mouse_hook)
1805             {
1806                 UnhookWindowsHookEx( mouse_hook );
1807                 mouse_hook = NULL;
1808             }
1809         }
1810         TranslateMessage(&msg);
1811         DispatchMessageW(&msg);
1812     }
1813 
1814     FreeLibraryAndExitThread(DINPUT_instance, 0);
1815 }
1816 
1817 static DWORD hook_thread_id;
1818 static HANDLE hook_thread_event;
1819 
1820 static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
1821 {
1822     0, 0, &dinput_hook_crit,
1823     { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
1824       0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
1825 };
1826 static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
1827 
check_hook_thread(void)1828 static BOOL check_hook_thread(void)
1829 {
1830     static HANDLE hook_thread;
1831     HMODULE module;
1832 
1833     EnterCriticalSection(&dinput_hook_crit);
1834 
1835     TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list));
1836     if (!list_empty(&direct_input_list) && !hook_thread)
1837     {
1838         GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)DINPUT_instance, &module);
1839         hook_thread_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1840         hook_thread = CreateThread(NULL, 0, hook_thread_proc, hook_thread_event, 0, &hook_thread_id);
1841     }
1842     else if (list_empty(&direct_input_list) && hook_thread)
1843     {
1844         DWORD tid = hook_thread_id;
1845 
1846         if (hook_thread_event) /* if thread is not started yet */
1847         {
1848             WaitForSingleObject(hook_thread_event, INFINITE);
1849             CloseHandle(hook_thread_event);
1850             hook_thread_event = NULL;
1851         }
1852 
1853         hook_thread_id = 0;
1854         PostThreadMessageW(tid, WM_USER+0x10, 0, 0);
1855         CloseHandle(hook_thread);
1856         hook_thread = NULL;
1857     }
1858 
1859     LeaveCriticalSection(&dinput_hook_crit);
1860     return hook_thread_id != 0;
1861 }
1862 
check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface,BOOL acquired)1863 void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired)
1864 {
1865     static HHOOK callwndproc_hook;
1866     static ULONG foreground_cnt;
1867     IDirectInputDeviceImpl *dev = impl_from_IDirectInputDevice8W(iface);
1868 
1869     EnterCriticalSection(&dinput_hook_crit);
1870 
1871     if (dev->dwCoopLevel & DISCL_FOREGROUND)
1872     {
1873         if (acquired)
1874             foreground_cnt++;
1875         else
1876             foreground_cnt--;
1877     }
1878 
1879     if (foreground_cnt && !callwndproc_hook)
1880         callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc,
1881                                               DINPUT_instance, GetCurrentThreadId() );
1882     else if (!foreground_cnt && callwndproc_hook)
1883     {
1884         UnhookWindowsHookEx( callwndproc_hook );
1885         callwndproc_hook = NULL;
1886     }
1887 
1888     if (hook_thread_event) /* if thread is not started yet */
1889     {
1890         WaitForSingleObject(hook_thread_event, INFINITE);
1891         CloseHandle(hook_thread_event);
1892         hook_thread_event = NULL;
1893     }
1894 
1895     PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 );
1896 
1897     LeaveCriticalSection(&dinput_hook_crit);
1898 }
1899 
check_dinput_events(void)1900 void check_dinput_events(void)
1901 {
1902     /* Windows does not do that, but our current implementation of winex11
1903      * requires periodic event polling to forward events to the wineserver.
1904      *
1905      * We have to call this function from multiple places, because:
1906      * - some games do not explicitly poll for mouse events
1907      *   (for example Culpa Innata)
1908      * - some games only poll the device, and neither keyboard nor mouse
1909      *   (for example Civilization: Call to Power 2)
1910      */
1911 #ifndef __REACTOS__
1912     MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0);
1913 #endif
1914 }
1915 
DllMain(HINSTANCE inst,DWORD reason,LPVOID reserved)1916 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved)
1917 {
1918     switch(reason)
1919     {
1920       case DLL_PROCESS_ATTACH:
1921         DisableThreadLibraryCalls(inst);
1922         DINPUT_instance = inst;
1923         break;
1924       case DLL_PROCESS_DETACH:
1925         if (reserved) break;
1926         DeleteCriticalSection(&dinput_hook_crit);
1927         break;
1928     }
1929     return TRUE;
1930 }
1931