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