dinput: SetActionMap setting the device buffer.
[wine] / dlls / dinput / dinput_main.c
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 "config.h"
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <string.h>
37
38 #define COBJMACROS
39 #define NONAMELESSUNION
40
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winuser.h"
46 #include "winerror.h"
47 #include "objbase.h"
48 #include "rpcproxy.h"
49 #include "dinput_private.h"
50 #include "device_private.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
53
54 static const IDirectInput7AVtbl ddi7avt;
55 static const IDirectInput7WVtbl ddi7wvt;
56 static const IDirectInput8AVtbl ddi8avt;
57 static const IDirectInput8WVtbl ddi8wvt;
58
59 static inline IDirectInputImpl *impl_from_IDirectInput7A( IDirectInput7A *iface )
60 {
61     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7A_iface );
62 }
63
64 static inline IDirectInputImpl *impl_from_IDirectInput7W( IDirectInput7W *iface )
65 {
66     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7W_iface );
67 }
68
69 static inline IDirectInputImpl *impl_from_IDirectInput8A( IDirectInput8A *iface )
70 {
71     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8A_iface );
72 }
73
74 static inline IDirectInputImpl *impl_from_IDirectInput8W( IDirectInput8W *iface )
75 {
76     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8W_iface );
77 }
78
79 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
80 {
81     return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface);
82 }
83 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
84 {
85     return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface);
86 }
87
88 static const struct dinput_device *dinput_devices[] =
89 {
90     &mouse_device,
91     &keyboard_device,
92     &joystick_linuxinput_device,
93     &joystick_linux_device,
94     &joystick_osx_device
95 };
96 #define NB_DINPUT_DEVICES (sizeof(dinput_devices)/sizeof(dinput_devices[0]))
97
98 static HINSTANCE DINPUT_instance = NULL;
99
100 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv)
101 {
102     switch(reason)
103     {
104       case DLL_PROCESS_ATTACH:
105         DisableThreadLibraryCalls(inst);
106         DINPUT_instance = inst;
107         break;
108       case DLL_PROCESS_DETACH:
109         break;
110     }
111     return TRUE;
112 }
113
114 static BOOL check_hook_thread(void);
115 static CRITICAL_SECTION dinput_hook_crit;
116 static struct list direct_input_list = LIST_INIT( direct_input_list );
117
118 /******************************************************************************
119  *      DirectInputCreateEx (DINPUT.@)
120  */
121 HRESULT WINAPI DirectInputCreateEx(
122         HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI,
123         LPUNKNOWN punkOuter) 
124 {
125     IDirectInputImpl* This;
126
127     TRACE("(%p,%04x,%s,%p,%p)\n", hinst, dwVersion, debugstr_guid(riid), ppDI, punkOuter);
128
129     if (IsEqualGUID( &IID_IUnknown,       riid ) ||
130         IsEqualGUID( &IID_IDirectInputA,  riid ) ||
131         IsEqualGUID( &IID_IDirectInput2A, riid ) ||
132         IsEqualGUID( &IID_IDirectInput7A, riid ) ||
133         IsEqualGUID( &IID_IDirectInputW,  riid ) ||
134         IsEqualGUID( &IID_IDirectInput2W, riid ) ||
135         IsEqualGUID( &IID_IDirectInput7W, riid ) ||
136         IsEqualGUID( &IID_IDirectInput8A, riid ) ||
137         IsEqualGUID( &IID_IDirectInput8W, riid ))
138     {
139         if (!(This = HeapAlloc( GetProcessHeap(), 0, sizeof(IDirectInputImpl) )))
140             return DIERR_OUTOFMEMORY;
141     }
142     else
143         return DIERR_OLDDIRECTINPUTVERSION;
144
145     This->IDirectInput7A_iface.lpVtbl = &ddi7avt;
146     This->IDirectInput7W_iface.lpVtbl = &ddi7wvt;
147     This->IDirectInput8A_iface.lpVtbl = &ddi8avt;
148     This->IDirectInput8W_iface.lpVtbl = &ddi8wvt;
149     This->ref         = 0;
150     This->dwVersion   = dwVersion;
151     This->evsequence  = 1;
152
153     InitializeCriticalSection(&This->crit);
154     This->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectInputImpl*->crit");
155
156     list_init( &This->devices_list );
157
158     /* Add self to the list of the IDirectInputs */
159     EnterCriticalSection( &dinput_hook_crit );
160     list_add_head( &direct_input_list, &This->entry );
161     LeaveCriticalSection( &dinput_hook_crit );
162
163     if (!check_hook_thread())
164     {
165         IUnknown_Release( &This->IDirectInput7A_iface );
166         return DIERR_GENERIC;
167     }
168
169     IDirectInput_QueryInterface( &This->IDirectInput7A_iface, riid, ppDI );
170     return DI_OK;
171 }
172
173 /******************************************************************************
174  *      DirectInputCreateA (DINPUT.@)
175  */
176 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
177 {
178     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7A, (LPVOID *)ppDI, punkOuter);
179 }
180
181 /******************************************************************************
182  *      DirectInputCreateW (DINPUT.@)
183  */
184 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter)
185 {
186     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7W, (LPVOID *)ppDI, punkOuter);
187 }
188
189 static const char *_dump_DIDEVTYPE_value(DWORD dwDevType) {
190     switch (dwDevType) {
191         case 0: return "All devices";
192         case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE";
193         case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD";
194         case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK";
195         case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE";
196         default: return "Unknown";
197     }
198 }
199
200 static void _dump_EnumDevices_dwFlags(DWORD dwFlags) {
201     if (TRACE_ON(dinput)) {
202         unsigned int   i;
203         static const struct {
204             DWORD       mask;
205             const char  *name;
206         } flags[] = {
207 #define FE(x) { x, #x}
208             FE(DIEDFL_ALLDEVICES),
209             FE(DIEDFL_ATTACHEDONLY),
210             FE(DIEDFL_FORCEFEEDBACK),
211             FE(DIEDFL_INCLUDEALIASES),
212             FE(DIEDFL_INCLUDEPHANTOMS)
213 #undef FE
214         };
215         TRACE(" flags: ");
216         if (dwFlags == 0) {
217             TRACE("DIEDFL_ALLDEVICES\n");
218             return;
219         }
220         for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
221             if (flags[i].mask & dwFlags)
222                 TRACE("%s ",flags[i].name);
223     }
224     TRACE("\n");
225 }
226
227 void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat) {
228     unsigned int i;
229
230     FIXME("diaf.dwSize = %d\n", lpdiActionFormat->dwSize);
231     FIXME("diaf.dwActionSize = %d\n", lpdiActionFormat->dwActionSize);
232     FIXME("diaf.dwDataSize = %d\n", lpdiActionFormat->dwDataSize);
233     FIXME("diaf.dwNumActions = %d\n", lpdiActionFormat->dwNumActions);
234     FIXME("diaf.rgoAction = %p\n", lpdiActionFormat->rgoAction);
235     FIXME("diaf.guidActionMap = %s\n", debugstr_guid(&lpdiActionFormat->guidActionMap));
236     FIXME("diaf.dwGenre = 0x%08x\n", lpdiActionFormat->dwGenre);
237     FIXME("diaf.dwBufferSize = %d\n", lpdiActionFormat->dwBufferSize);
238     FIXME("diaf.lAxisMin = %d\n", lpdiActionFormat->lAxisMin);
239     FIXME("diaf.lAxisMax = %d\n", lpdiActionFormat->lAxisMax);
240     FIXME("diaf.hInstString = %p\n", lpdiActionFormat->hInstString);
241     FIXME("diaf.ftTimeStamp ...\n");
242     FIXME("diaf.dwCRC = 0x%x\n", lpdiActionFormat->dwCRC);
243     FIXME("diaf.tszActionMap = %s\n", debugstr_a(lpdiActionFormat->tszActionMap));
244     for (i = 0; i < lpdiActionFormat->dwNumActions; i++)
245     {
246         FIXME("diaf.rgoAction[%u]:\n", i);
247         FIXME("\tuAppData=0x%lx\n", lpdiActionFormat->rgoAction[i].uAppData);
248         FIXME("\tdwSemantic=0x%08x\n", lpdiActionFormat->rgoAction[i].dwSemantic);
249         FIXME("\tdwFlags=0x%x\n", lpdiActionFormat->rgoAction[i].dwFlags);
250         FIXME("\tszActionName=%s\n", debugstr_a(lpdiActionFormat->rgoAction[i].u.lptszActionName));
251         FIXME("\tguidInstance=%s\n", debugstr_guid(&lpdiActionFormat->rgoAction[i].guidInstance));
252         FIXME("\tdwObjID=0x%x\n", lpdiActionFormat->rgoAction[i].dwObjID);
253         FIXME("\tdwHow=0x%x\n", lpdiActionFormat->rgoAction[i].dwHow);
254     }
255 }
256
257 void _copy_diactionformatAtoW(LPDIACTIONFORMATW to, LPDIACTIONFORMATA from)
258 {
259     int i;
260
261     to->dwSize = sizeof(DIACTIONFORMATW);
262     to->dwActionSize = sizeof(DIACTIONW);
263     to->dwDataSize = from->dwDataSize;
264     to->dwNumActions = from->dwNumActions;
265     to->guidActionMap = from->guidActionMap;
266     to->dwGenre = from->dwGenre;
267     to->dwBufferSize = from->dwBufferSize;
268     to->lAxisMin = from->lAxisMin;
269     to->lAxisMax = from->lAxisMax;
270     to->dwCRC = from->dwCRC;
271     to->ftTimeStamp = from->ftTimeStamp;
272
273     for (i=0; i < to->dwNumActions; i++)
274     {
275         to->rgoAction[i].uAppData = from->rgoAction[i].uAppData;
276         to->rgoAction[i].dwSemantic = from->rgoAction[i].dwSemantic;
277         to->rgoAction[i].dwFlags = from->rgoAction[i].dwFlags;
278         to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance;
279         to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID;
280         to->rgoAction[i].dwHow = from->rgoAction[i].dwHow;
281     }
282 }
283
284 void _copy_diactionformatWtoA(LPDIACTIONFORMATA to, LPDIACTIONFORMATW from)
285 {
286     int i;
287
288     to->dwSize = sizeof(DIACTIONFORMATA);
289     to->dwActionSize = sizeof(DIACTIONA);
290     to->dwDataSize = from->dwDataSize;
291     to->dwNumActions = from->dwNumActions;
292     to->guidActionMap = from->guidActionMap;
293     to->dwGenre = from->dwGenre;
294     to->dwBufferSize = from->dwBufferSize;
295     to->lAxisMin = from->lAxisMin;
296     to->lAxisMax = from->lAxisMax;
297     to->dwCRC = from->dwCRC;
298     to->ftTimeStamp = from->ftTimeStamp;
299
300     for (i=0; i < to->dwNumActions; i++)
301     {
302         to->rgoAction[i].uAppData = from->rgoAction[i].uAppData;
303         to->rgoAction[i].dwSemantic = from->rgoAction[i].dwSemantic;
304         to->rgoAction[i].dwFlags = from->rgoAction[i].dwFlags;
305         to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance;
306         to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID;
307         to->rgoAction[i].dwHow = from->rgoAction[i].dwHow;
308     }
309 }
310
311 /******************************************************************************
312  *      IDirectInputA_EnumDevices
313  */
314 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
315         LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
316         LPVOID pvRef, DWORD dwFlags)
317 {
318     IDirectInputImpl *This = impl_from_IDirectInput7A(iface);
319     DIDEVICEINSTANCEA devInstance;
320     unsigned int i;
321     int j, r;
322
323     TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
324           This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
325           lpCallback, pvRef, dwFlags);
326     _dump_EnumDevices_dwFlags(dwFlags);
327
328     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
329         if (!dinput_devices[i]->enum_deviceA) continue;
330         for (j = 0, r = -1; r != 0; j++) {
331             devInstance.dwSize = sizeof(devInstance);
332             TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
333             if ((r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
334                 if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
335                     return 0;
336             }
337         }
338     }
339     
340     return 0;
341 }
342 /******************************************************************************
343  *      IDirectInputW_EnumDevices
344  */
345 static HRESULT WINAPI IDirectInputWImpl_EnumDevices(
346         LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
347         LPVOID pvRef, DWORD dwFlags) 
348 {
349     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
350     DIDEVICEINSTANCEW devInstance;
351     unsigned int i;
352     int j, r;
353
354     TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
355           This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
356           lpCallback, pvRef, dwFlags);
357     _dump_EnumDevices_dwFlags(dwFlags);
358
359     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
360         if (!dinput_devices[i]->enum_deviceW) continue;
361         for (j = 0, r = -1; r != 0; j++) {
362             devInstance.dwSize = sizeof(devInstance);
363             TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
364             if ((r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
365                 if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
366                     return 0;
367             }
368         }
369     }
370     
371     return 0;
372 }
373
374 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)
375 {
376     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
377     ULONG ref = InterlockedIncrement(&This->ref);
378
379     TRACE( "(%p) incrementing from %d\n", This, ref - 1);
380     return ref;
381 }
382
383 static ULONG WINAPI IDirectInputWImpl_AddRef(LPDIRECTINPUT7W iface)
384 {
385     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
386     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
387 }
388
389 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)
390 {
391     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
392     ULONG ref = InterlockedDecrement( &This->ref );
393
394     TRACE( "(%p) releasing from %d\n", This, ref + 1 );
395
396     if (ref) return ref;
397
398     /* Remove self from the list of the IDirectInputs */
399     EnterCriticalSection( &dinput_hook_crit );
400     list_remove( &This->entry );
401     LeaveCriticalSection( &dinput_hook_crit );
402
403     check_hook_thread();
404
405     This->crit.DebugInfo->Spare[0] = 0;
406     DeleteCriticalSection( &This->crit );
407     HeapFree( GetProcessHeap(), 0, This );
408
409     return 0;
410 }
411
412 static ULONG WINAPI IDirectInputWImpl_Release(LPDIRECTINPUT7W iface)
413 {
414     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
415     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
416 }
417
418 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj)
419 {
420     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
421
422     TRACE( "(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj );
423
424     if (IsEqualGUID( &IID_IUnknown, riid ) ||
425         IsEqualGUID( &IID_IDirectInputA,  riid ) ||
426         IsEqualGUID( &IID_IDirectInput2A, riid ) ||
427         IsEqualGUID( &IID_IDirectInput7A, riid ))
428     {
429         *ppobj = &This->IDirectInput7A_iface;
430         IUnknown_AddRef( (IUnknown*)*ppobj );
431
432         return DI_OK;
433     }
434
435     if (IsEqualGUID( &IID_IDirectInputW,  riid ) ||
436         IsEqualGUID( &IID_IDirectInput2W, riid ) ||
437         IsEqualGUID( &IID_IDirectInput7W, riid ))
438     {
439         *ppobj = &This->IDirectInput7W_iface;
440         IUnknown_AddRef( (IUnknown*)*ppobj );
441
442         return DI_OK;
443     }
444
445     if (IsEqualGUID( &IID_IDirectInput8A, riid ))
446     {
447         *ppobj = &This->IDirectInput8A_iface;
448         IUnknown_AddRef( (IUnknown*)*ppobj );
449
450         return DI_OK;
451     }
452
453     if (IsEqualGUID( &IID_IDirectInput8W, riid ))
454     {
455         *ppobj = &This->IDirectInput8W_iface;
456         IUnknown_AddRef( (IUnknown*)*ppobj );
457
458         return DI_OK;
459     }
460
461     FIXME( "Unsupported interface: %s\n", debugstr_guid(riid));
462     return E_FAIL;
463 }
464
465 static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj)
466 {
467     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
468     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
469 }
470
471 static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD x) {
472         TRACE("(this=%p,%p,%x)\n",iface, hinst, x);
473         
474         /* Initialize can return: DIERR_BETADIRECTINPUTVERSION, DIERR_OLDDIRECTINPUTVERSION and DI_OK.
475          * Since we already initialized the device, return DI_OK. In the past we returned DIERR_ALREADYINITIALIZED
476          * which broke applications like Tomb Raider Legend because it isn't a legal return value.
477          */
478         return DI_OK;
479 }
480
481 static HRESULT WINAPI IDirectInputWImpl_Initialize(LPDIRECTINPUT7W iface, HINSTANCE hinst, DWORD x)
482 {
483     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
484     return IDirectInputAImpl_Initialize( &This->IDirectInput7A_iface, hinst, x );
485 }
486
487 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, REFGUID rguid)
488 {
489     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
490     HRESULT hr;
491     LPDIRECTINPUTDEVICEA device;
492
493     TRACE( "(%p)->(%s)\n", This, debugstr_guid(rguid) );
494
495     hr = IDirectInput_CreateDevice( iface, rguid, &device, NULL );
496     if (hr != DI_OK) return DI_NOTATTACHED;
497
498     IUnknown_Release( device );
499
500     return DI_OK;
501 }
502
503 static HRESULT WINAPI IDirectInputWImpl_GetDeviceStatus(LPDIRECTINPUT7W iface, REFGUID rguid)
504 {
505     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
506     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
507 }
508
509 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface,
510                                                         HWND hwndOwner,
511                                                         DWORD dwFlags)
512 {
513     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
514
515     FIXME( "(%p)->(%p,%08x): stub\n", This, hwndOwner, dwFlags );
516
517     return DI_OK;
518 }
519
520 static HRESULT WINAPI IDirectInputWImpl_RunControlPanel(LPDIRECTINPUT7W iface, HWND hwndOwner, DWORD dwFlags)
521 {
522     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
523     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
524 }
525
526 static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
527                                                     LPCSTR pszName, LPGUID pguidInstance)
528 {
529     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
530
531     FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance );
532
533     return DI_OK;
534 }
535
536 static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
537                                                     LPCWSTR pszName, LPGUID pguidInstance)
538 {
539     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
540
541     FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance );
542
543     return DI_OK;
544 }
545
546 static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid,
547                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
548 {
549   IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
550   HRESULT ret_value = DIERR_DEVICENOTREG;
551   unsigned int i;
552
553   TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
554
555   if (!rguid || !pvOut) return E_POINTER;
556
557   /* Loop on all the devices to see if anyone matches the given GUID */
558   for (i = 0; i < NB_DINPUT_DEVICES; i++) {
559     HRESULT ret;
560
561     if (!dinput_devices[i]->create_device) continue;
562     if ((ret = dinput_devices[i]->create_device(This, rguid, riid, pvOut, 0)) == DI_OK)
563       return DI_OK;
564
565     if (ret == DIERR_NOINTERFACE)
566       ret_value = DIERR_NOINTERFACE;
567   }
568
569   if (ret_value == DIERR_NOINTERFACE)
570   {
571     WARN("invalid device GUID %s\n", debugstr_guid(rguid));
572   }
573
574   return ret_value;
575 }
576
577 static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid,
578                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
579 {
580   IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
581   HRESULT ret_value = DIERR_DEVICENOTREG;
582   unsigned int i;
583
584   TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
585
586   if (!rguid || !pvOut) return E_POINTER;
587
588   /* Loop on all the devices to see if anyone matches the given GUID */
589   for (i = 0; i < NB_DINPUT_DEVICES; i++) {
590     HRESULT ret;
591
592     if (!dinput_devices[i]->create_device) continue;
593     if ((ret = dinput_devices[i]->create_device(This, rguid, riid, pvOut, 1)) == DI_OK)
594       return DI_OK;
595
596     if (ret == DIERR_NOINTERFACE)
597       ret_value = DIERR_NOINTERFACE;
598   }
599
600   return ret_value;
601 }
602
603 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
604                                                      LPDIRECTINPUTDEVICEA* pdev, LPUNKNOWN punk)
605 {
606     return IDirectInput7AImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
607 }
608
609 static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
610                                                      LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk)
611 {
612     return IDirectInput7WImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
613 }
614
615 /*******************************************************************************
616  *      DirectInput8
617  */
618
619 static ULONG WINAPI IDirectInput8AImpl_AddRef(LPDIRECTINPUT8A iface)
620 {
621     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
622     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
623 }
624
625 static ULONG WINAPI IDirectInput8WImpl_AddRef(LPDIRECTINPUT8W iface)
626 {
627     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
628     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
629 }
630
631 static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj)
632 {
633     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
634     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
635 }
636
637 static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj)
638 {
639     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
640     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
641 }
642
643 static ULONG WINAPI IDirectInput8AImpl_Release(LPDIRECTINPUT8A iface)
644 {
645     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
646     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
647 }
648
649 static ULONG WINAPI IDirectInput8WImpl_Release(LPDIRECTINPUT8W iface)
650 {
651     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
652     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
653 }
654
655 static HRESULT WINAPI IDirectInput8AImpl_CreateDevice(LPDIRECTINPUT8A iface, REFGUID rguid,
656                                                       LPDIRECTINPUTDEVICE8A* pdev, LPUNKNOWN punk)
657 {
658     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
659     return IDirectInput7AImpl_CreateDeviceEx( &This->IDirectInput7A_iface, rguid, NULL, (LPVOID*)pdev, punk );
660 }
661
662 static HRESULT WINAPI IDirectInput8WImpl_CreateDevice(LPDIRECTINPUT8W iface, REFGUID rguid,
663                                                       LPDIRECTINPUTDEVICE8W* pdev, LPUNKNOWN punk)
664 {
665     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
666     return IDirectInput7WImpl_CreateDeviceEx( &This->IDirectInput7W_iface, rguid, NULL, (LPVOID*)pdev, punk );
667 }
668
669 static HRESULT WINAPI IDirectInput8AImpl_EnumDevices(LPDIRECTINPUT8A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
670                                                      LPVOID pvRef, DWORD dwFlags)
671 {
672     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
673     return IDirectInputAImpl_EnumDevices( &This->IDirectInput7A_iface, dwDevType, lpCallback, pvRef, dwFlags );
674 }
675
676 static HRESULT WINAPI IDirectInput8WImpl_EnumDevices(LPDIRECTINPUT8W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
677                                                      LPVOID pvRef, DWORD dwFlags)
678 {
679     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
680     return IDirectInputWImpl_EnumDevices( &This->IDirectInput7W_iface, dwDevType, lpCallback, pvRef, dwFlags );
681 }
682
683 static HRESULT WINAPI IDirectInput8AImpl_GetDeviceStatus(LPDIRECTINPUT8A iface, REFGUID rguid)
684 {
685     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
686     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
687 }
688
689 static HRESULT WINAPI IDirectInput8WImpl_GetDeviceStatus(LPDIRECTINPUT8W iface, REFGUID rguid)
690 {
691     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
692     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
693 }
694
695 static HRESULT WINAPI IDirectInput8AImpl_RunControlPanel(LPDIRECTINPUT8A iface, HWND hwndOwner, DWORD dwFlags)
696 {
697     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
698     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
699 }
700
701 static HRESULT WINAPI IDirectInput8WImpl_RunControlPanel(LPDIRECTINPUT8W iface, HWND hwndOwner, DWORD dwFlags)
702 {
703     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
704     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
705 }
706
707 static HRESULT WINAPI IDirectInput8AImpl_Initialize(LPDIRECTINPUT8A iface, HINSTANCE hinst, DWORD x)
708 {
709     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
710     return IDirectInputAImpl_Initialize( &This->IDirectInput7A_iface, hinst, x );
711 }
712
713 static HRESULT WINAPI IDirectInput8WImpl_Initialize(LPDIRECTINPUT8W iface, HINSTANCE hinst, DWORD x)
714 {
715     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
716     return IDirectInputAImpl_Initialize( &This->IDirectInput7A_iface, hinst, x );
717 }
718
719 static HRESULT WINAPI IDirectInput8AImpl_FindDevice(LPDIRECTINPUT8A iface, REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance)
720 {
721     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
722     return IDirectInput2AImpl_FindDevice( &This->IDirectInput7A_iface, rguid, pszName, pguidInstance );
723 }
724
725 static HRESULT WINAPI IDirectInput8WImpl_FindDevice(LPDIRECTINPUT8W iface, REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance)
726 {
727     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
728     return IDirectInput2WImpl_FindDevice( &This->IDirectInput7W_iface, rguid, pszName, pguidInstance );
729 }
730
731 static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
732       LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat,
733       LPDIENUMDEVICESBYSEMANTICSCBA lpCallback,
734       LPVOID pvRef, DWORD dwFlags
735 )
736 {
737     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
738     DIDEVICEINSTANCEA didevi;
739     LPDIRECTINPUTDEVICE8A lpdid;
740     BOOL ret;
741     DWORD callbackFlags = 0;
742     int i;
743
744     FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, ptszUserName, lpdiActionFormat,
745           lpCallback, pvRef, dwFlags);
746 #define X(x) if (dwFlags & x) FIXME("\tdwFlags |= "#x"\n");
747         X(DIEDBSFL_ATTACHEDONLY)
748         X(DIEDBSFL_THISUSER)
749         X(DIEDBSFL_FORCEFEEDBACK)
750         X(DIEDBSFL_AVAILABLEDEVICES)
751         X(DIEDBSFL_MULTIMICEKEYBOARDS)
752         X(DIEDBSFL_NONGAMINGDEVICES)
753 #undef X
754
755     _dump_diactionformatA(lpdiActionFormat);
756
757     didevi.dwSize = sizeof(didevi);
758
759     /* enum the keyboard first */
760     IDirectInput_CreateDevice(iface, &GUID_SysKeyboard, &lpdid, NULL);
761     IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
762     /* if there's any DIKEYBOARD action, keyboard is priority 1*/
763     for(i=0; i < lpdiActionFormat->dwActionSize; i++)
764         if ((lpdiActionFormat->rgoAction[i].dwSemantic & DIKEYBOARD_MASK) == DIKEYBOARD_MASK)
765             callbackFlags |= DIEDBS_MAPPEDPRI1;
766
767     ret = lpCallback(&didevi, lpdid, callbackFlags, 1, pvRef);
768
769     if (ret == DIENUM_STOP) return DI_OK;
770
771     callbackFlags = 0;
772
773     /* and then the mouse */
774     IDirectInput_CreateDevice(iface, &GUID_SysMouse, &lpdid, NULL);
775     IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
776     /* same as above, but for the mouse */
777     for(i=0; i < lpdiActionFormat->dwActionSize; i++)
778         if ((lpdiActionFormat->rgoAction[i].dwSemantic & DIMOUSE_MASK) == DIMOUSE_MASK)
779             callbackFlags |= DIEDBS_MAPPEDPRI1;
780
781     lpCallback(&didevi, lpdid, callbackFlags, 0, pvRef);
782
783     return DI_OK;
784 }
785
786 static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
787       LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat,
788       LPDIENUMDEVICESBYSEMANTICSCBW lpCallback,
789       LPVOID pvRef, DWORD dwFlags
790 )
791 {
792     IDirectInputImpl *This = impl_from_IDirectInput8W(iface);
793     DIDEVICEINSTANCEW didevi;
794     LPDIRECTINPUTDEVICE8W lpdid;
795     BOOL ret;
796     DWORD callbackFlags = 0;
797     int i;
798
799     FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat,
800           lpCallback, pvRef, dwFlags);
801
802     didevi.dwSize = sizeof(didevi);
803
804     /* enum the keyboard first */
805     IDirectInput_CreateDevice(iface, &GUID_SysKeyboard, &lpdid, NULL);
806     IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
807     /* if there's any DIKEYBOARD action, keyboard is priority 1*/
808     for(i=0; i < lpdiActionFormat->dwActionSize; i++)
809         if ((lpdiActionFormat->rgoAction[i].dwSemantic & DIKEYBOARD_MASK) == DIKEYBOARD_MASK)
810             callbackFlags |= DIEDBS_MAPPEDPRI1;
811
812     ret = lpCallback(&didevi, lpdid, callbackFlags, 1, pvRef);
813
814     if (ret == DIENUM_STOP) return DI_OK;
815
816     callbackFlags = 0;
817
818     /* and then the mouse */
819     IDirectInput_CreateDevice(iface, &GUID_SysMouse, &lpdid, NULL);
820     IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
821     /* same as above, but for the mouse */
822     for(i=0; i < lpdiActionFormat->dwActionSize; i++)
823         if ((lpdiActionFormat->rgoAction[i].dwSemantic & DIMOUSE_MASK) == DIMOUSE_MASK)
824             callbackFlags |= DIEDBS_MAPPEDPRI1;
825
826     lpCallback(&didevi, lpdid, callbackFlags, 0, pvRef);
827
828     return DI_OK;
829 }
830
831 static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
832       LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
833       LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
834 )
835 {
836       IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
837
838       FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams,
839             dwFlags, pvRefData);
840       return 0;
841 }
842
843 static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices(
844       LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
845       LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
846 )
847 {
848       IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
849
850       FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams,
851             dwFlags, pvRefData);
852       return 0;
853 }
854
855 static const IDirectInput7AVtbl ddi7avt = {
856     IDirectInputAImpl_QueryInterface,
857     IDirectInputAImpl_AddRef,
858     IDirectInputAImpl_Release,
859     IDirectInputAImpl_CreateDevice,
860     IDirectInputAImpl_EnumDevices,
861     IDirectInputAImpl_GetDeviceStatus,
862     IDirectInputAImpl_RunControlPanel,
863     IDirectInputAImpl_Initialize,
864     IDirectInput2AImpl_FindDevice,
865     IDirectInput7AImpl_CreateDeviceEx
866 };
867
868 static const IDirectInput7WVtbl ddi7wvt = {
869     IDirectInputWImpl_QueryInterface,
870     IDirectInputWImpl_AddRef,
871     IDirectInputWImpl_Release,
872     IDirectInputWImpl_CreateDevice,
873     IDirectInputWImpl_EnumDevices,
874     IDirectInputWImpl_GetDeviceStatus,
875     IDirectInputWImpl_RunControlPanel,
876     IDirectInputWImpl_Initialize,
877     IDirectInput2WImpl_FindDevice,
878     IDirectInput7WImpl_CreateDeviceEx
879 };
880
881 static const IDirectInput8AVtbl ddi8avt = {
882     IDirectInput8AImpl_QueryInterface,
883     IDirectInput8AImpl_AddRef,
884     IDirectInput8AImpl_Release,
885     IDirectInput8AImpl_CreateDevice,
886     IDirectInput8AImpl_EnumDevices,
887     IDirectInput8AImpl_GetDeviceStatus,
888     IDirectInput8AImpl_RunControlPanel,
889     IDirectInput8AImpl_Initialize,
890     IDirectInput8AImpl_FindDevice,
891     IDirectInput8AImpl_EnumDevicesBySemantics,
892     IDirectInput8AImpl_ConfigureDevices
893 };
894
895 static const IDirectInput8WVtbl ddi8wvt = {
896     IDirectInput8WImpl_QueryInterface,
897     IDirectInput8WImpl_AddRef,
898     IDirectInput8WImpl_Release,
899     IDirectInput8WImpl_CreateDevice,
900     IDirectInput8WImpl_EnumDevices,
901     IDirectInput8WImpl_GetDeviceStatus,
902     IDirectInput8WImpl_RunControlPanel,
903     IDirectInput8WImpl_Initialize,
904     IDirectInput8WImpl_FindDevice,
905     IDirectInput8WImpl_EnumDevicesBySemantics,
906     IDirectInput8WImpl_ConfigureDevices
907 };
908
909 /*******************************************************************************
910  * DirectInput ClassFactory
911  */
912 typedef struct
913 {
914     /* IUnknown fields */
915     IClassFactory IClassFactory_iface;
916     LONG          ref;
917 } IClassFactoryImpl;
918
919 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
920 {
921         return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
922 }
923
924 static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
925         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
926
927         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
928         return E_NOINTERFACE;
929 }
930
931 static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) {
932         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
933         return InterlockedIncrement(&(This->ref));
934 }
935
936 static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) {
937         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
938         /* static class, won't be  freed */
939         return InterlockedDecrement(&(This->ref));
940 }
941
942 static HRESULT WINAPI DICF_CreateInstance(
943         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
944 ) {
945         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
946
947         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
948         if ( IsEqualGUID( &IID_IUnknown, riid ) ||
949              IsEqualGUID( &IID_IDirectInputA, riid ) ||
950              IsEqualGUID( &IID_IDirectInputW, riid ) ||
951              IsEqualGUID( &IID_IDirectInput2A, riid ) ||
952              IsEqualGUID( &IID_IDirectInput2W, riid ) ||
953              IsEqualGUID( &IID_IDirectInput7A, riid ) ||
954              IsEqualGUID( &IID_IDirectInput7W, riid ) ||
955              IsEqualGUID( &IID_IDirectInput8A, riid ) ||
956              IsEqualGUID( &IID_IDirectInput8W, riid ) ) {
957                 /* FIXME: reuse already created dinput if present? */
958                 return DirectInputCreateEx(0,0,riid,ppobj,pOuter);
959         }
960
961         FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);    
962         return E_NOINTERFACE;
963 }
964
965 static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
966         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
967         FIXME("(%p)->(%d),stub!\n",This,dolock);
968         return S_OK;
969 }
970
971 static const IClassFactoryVtbl DICF_Vtbl = {
972         DICF_QueryInterface,
973         DICF_AddRef,
974         DICF_Release,
975         DICF_CreateInstance,
976         DICF_LockServer
977 };
978 static IClassFactoryImpl DINPUT_CF = {{&DICF_Vtbl}, 1 };
979
980 /***********************************************************************
981  *              DllCanUnloadNow (DINPUT.@)
982  */
983 HRESULT WINAPI DllCanUnloadNow(void)
984 {
985     return S_FALSE;
986 }
987
988 /***********************************************************************
989  *              DllGetClassObject (DINPUT.@)
990  */
991 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
992 {
993     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
994     if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
995         *ppv = &DINPUT_CF;
996         IClassFactory_AddRef((IClassFactory*)*ppv);
997     return S_OK;
998     }
999
1000     FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1001     return CLASS_E_CLASSNOTAVAILABLE;
1002 }
1003
1004 /***********************************************************************
1005  *              DllRegisterServer (DINPUT.@)
1006  */
1007 HRESULT WINAPI DllRegisterServer(void)
1008 {
1009     return __wine_register_resources( DINPUT_instance, NULL );
1010 }
1011
1012 /***********************************************************************
1013  *              DllUnregisterServer (DINPUT.@)
1014  */
1015 HRESULT WINAPI DllUnregisterServer(void)
1016 {
1017     return __wine_unregister_resources( DINPUT_instance, NULL );
1018 }
1019
1020 /******************************************************************************
1021  *      DInput hook thread
1022  */
1023
1024 static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam )
1025 {
1026     IDirectInputImpl *dinput;
1027     int skip = 0;
1028
1029     if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam );
1030
1031     EnterCriticalSection( &dinput_hook_crit );
1032     LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1033     {
1034         IDirectInputDeviceImpl *dev;
1035
1036         EnterCriticalSection( &dinput->crit );
1037         LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1038             if (dev->acquired && dev->event_proc)
1039             {
1040                 TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam);
1041                 skip |= dev->event_proc( &dev->IDirectInputDevice8A_iface, wparam, lparam );
1042             }
1043         LeaveCriticalSection( &dinput->crit );
1044     }
1045     LeaveCriticalSection( &dinput_hook_crit );
1046
1047     return skip ? 1 : CallNextHookEx( 0, code, wparam, lparam );
1048 }
1049
1050 static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam )
1051 {
1052     CWPSTRUCT *msg = (CWPSTRUCT *)lparam;
1053     IDirectInputImpl *dinput;
1054     HWND foreground;
1055
1056     if (code != HC_ACTION || (msg->message != WM_KILLFOCUS &&
1057         msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE))
1058         return CallNextHookEx( 0, code, wparam, lparam );
1059
1060     foreground = GetForegroundWindow();
1061
1062     EnterCriticalSection( &dinput_hook_crit );
1063
1064     LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1065     {
1066         IDirectInputDeviceImpl *dev;
1067
1068         EnterCriticalSection( &dinput->crit );
1069         LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1070         {
1071             if (!dev->acquired) continue;
1072
1073             if (msg->hwnd == dev->win && msg->hwnd != foreground)
1074             {
1075                 TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev );
1076                 IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8A_iface );
1077             }
1078         }
1079         LeaveCriticalSection( &dinput->crit );
1080     }
1081     LeaveCriticalSection( &dinput_hook_crit );
1082
1083     return CallNextHookEx( 0, code, wparam, lparam );
1084 }
1085
1086 static DWORD WINAPI hook_thread_proc(void *param)
1087 {
1088     static HHOOK kbd_hook, mouse_hook;
1089     MSG msg;
1090
1091     /* Force creation of the message queue */
1092     PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE );
1093     SetEvent(*(LPHANDLE)param);
1094
1095     while (GetMessageW( &msg, 0, 0, 0 ))
1096     {
1097         UINT kbd_cnt = 0, mice_cnt = 0;
1098
1099         if (msg.message == WM_USER+0x10)
1100         {
1101             IDirectInputImpl *dinput;
1102
1103             TRACE( "Processing hook change notification lp:%ld\n", msg.lParam );
1104
1105             if (!msg.wParam && !msg.lParam)
1106             {
1107                 if (kbd_hook) UnhookWindowsHookEx( kbd_hook );
1108                 if (mouse_hook) UnhookWindowsHookEx( mouse_hook );
1109                 kbd_hook = mouse_hook = NULL;
1110                 break;
1111             }
1112
1113             EnterCriticalSection( &dinput_hook_crit );
1114
1115             /* Count acquired keyboards and mice*/
1116             LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1117             {
1118                 IDirectInputDeviceImpl *dev;
1119
1120                 EnterCriticalSection( &dinput->crit );
1121                 LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1122                 {
1123                     if (!dev->acquired || !dev->event_proc) continue;
1124
1125                     if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard ) ||
1126                         IsEqualGUID( &dev->guid, &DInput_Wine_Keyboard_GUID ))
1127                         kbd_cnt++;
1128                     else
1129                         if (IsEqualGUID( &dev->guid, &GUID_SysMouse ) ||
1130                             IsEqualGUID( &dev->guid, &DInput_Wine_Mouse_GUID ))
1131                             mice_cnt++;
1132                 }
1133                 LeaveCriticalSection( &dinput->crit );
1134             }
1135             LeaveCriticalSection( &dinput_hook_crit );
1136
1137             if (kbd_cnt && !kbd_hook)
1138                 kbd_hook = SetWindowsHookExW( WH_KEYBOARD_LL, LL_hook_proc, DINPUT_instance, 0 );
1139             else if (!kbd_cnt && kbd_hook)
1140             {
1141                 UnhookWindowsHookEx( kbd_hook );
1142                 kbd_hook = NULL;
1143             }
1144
1145             if (mice_cnt && !mouse_hook)
1146                 mouse_hook = SetWindowsHookExW( WH_MOUSE_LL, LL_hook_proc, DINPUT_instance, 0 );
1147             else if (!mice_cnt && mouse_hook)
1148             {
1149                 UnhookWindowsHookEx( mouse_hook );
1150                 mouse_hook = NULL;
1151             }
1152         }
1153         TranslateMessage(&msg);
1154         DispatchMessageW(&msg);
1155     }
1156
1157     return 0;
1158 }
1159
1160 static DWORD hook_thread_id;
1161
1162 static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
1163 {
1164     0, 0, &dinput_hook_crit,
1165     { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
1166       0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
1167 };
1168 static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
1169
1170 static BOOL check_hook_thread(void)
1171 {
1172     static HANDLE hook_thread;
1173
1174     EnterCriticalSection(&dinput_hook_crit);
1175
1176     TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list));
1177     if (!list_empty(&direct_input_list) && !hook_thread)
1178     {
1179         HANDLE event;
1180
1181         event = CreateEventW(NULL, FALSE, FALSE, NULL);
1182         hook_thread = CreateThread(NULL, 0, hook_thread_proc, &event, 0, &hook_thread_id);
1183         if (event && hook_thread)
1184         {
1185             HANDLE handles[2];
1186             handles[0] = event;
1187             handles[1] = hook_thread;
1188             WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1189         }
1190         LeaveCriticalSection(&dinput_hook_crit);
1191         CloseHandle(event);
1192     }
1193     else if (list_empty(&direct_input_list) && hook_thread)
1194     {
1195         DWORD tid = hook_thread_id;
1196
1197         hook_thread_id = 0;
1198         PostThreadMessageW(tid, WM_USER+0x10, 0, 0);
1199         LeaveCriticalSection(&dinput_hook_crit);
1200
1201         /* wait for hook thread to exit */
1202         WaitForSingleObject(hook_thread, INFINITE);
1203         CloseHandle(hook_thread);
1204         hook_thread = NULL;
1205     }
1206     else
1207         LeaveCriticalSection(&dinput_hook_crit);
1208
1209     return hook_thread_id != 0;
1210 }
1211
1212 void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface)
1213 {
1214     static HHOOK callwndproc_hook;
1215     static ULONG foreground_cnt;
1216     IDirectInputDeviceImpl *dev = impl_from_IDirectInputDevice8W(iface);
1217
1218     EnterCriticalSection(&dinput_hook_crit);
1219
1220     if (dev->dwCoopLevel & DISCL_FOREGROUND)
1221     {
1222         if (dev->acquired)
1223             foreground_cnt++;
1224         else
1225             foreground_cnt--;
1226     }
1227
1228     if (foreground_cnt && !callwndproc_hook)
1229         callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc,
1230                                               DINPUT_instance, GetCurrentThreadId() );
1231     else if (!foreground_cnt && callwndproc_hook)
1232     {
1233         UnhookWindowsHookEx( callwndproc_hook );
1234         callwndproc_hook = NULL;
1235     }
1236
1237     PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 );
1238
1239     LeaveCriticalSection(&dinput_hook_crit);
1240 }