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