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