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