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