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