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