msctf: Maintain context reference in ranges.
[wine.git] / dlls / dinput / dinput_main.c
blobc7b932aca449d0709858f0c6734ab09270cdea48
1 /* DirectInput
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2002 TransGaming Technologies Inc.
6 * Copyright 2007 Vitaliy Margolen
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.
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.
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
23 /* Status:
25 * - Tomb Raider 2 Demo:
26 * Playable using keyboard only.
27 * - WingCommander Prophecy Demo:
28 * Doesn't get Input Focus.
30 * - Fallout : works great in X and DGA mode
33 #include "config.h"
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <string.h>
38 #define COBJMACROS
39 #define NONAMELESSUNION
41 #include "wine/debug.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"
56 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
58 static const IDirectInput7WVtbl ddi7wvt;
59 static const IDirectInput8WVtbl ddi8wvt;
60 static const IDirectInputJoyConfig8Vtbl JoyConfig8vt;
62 static inline IDirectInputImpl *impl_from_IDirectInput7W( IDirectInput7W *iface )
64 return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7W_iface );
67 static inline IDirectInputImpl *impl_from_IDirectInput8W( IDirectInput8W *iface )
69 return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8W_iface );
72 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
74 return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface);
77 static const struct dinput_device *dinput_devices[] =
79 &mouse_device,
80 &keyboard_device,
81 &joystick_linuxinput_device,
82 &joystick_linux_device,
83 &joystick_osx_device
86 HINSTANCE DINPUT_instance;
88 static const WCHAR di_em_win_w[] = {'D','I','E','m','W','i','n',0};
89 static HWND di_em_win;
91 static BOOL check_hook_thread(void);
92 static CRITICAL_SECTION dinput_hook_crit;
93 static struct list direct_input_list = LIST_INIT( direct_input_list );
94 static struct list acquired_mouse_list = LIST_INIT( acquired_mouse_list );
95 static struct list acquired_rawmouse_list = LIST_INIT( acquired_rawmouse_list );
96 static struct list acquired_keyboard_list = LIST_INIT( acquired_keyboard_list );
97 static struct list acquired_device_list = LIST_INIT( acquired_device_list );
99 static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion);
100 static void uninitialize_directinput_instance(IDirectInputImpl *This);
102 void dinput_hooks_acquire_device(LPDIRECTINPUTDEVICE8W iface)
104 IDirectInputDeviceImpl *dev = impl_from_IDirectInputDevice8W(iface);
106 EnterCriticalSection( &dinput_hook_crit );
107 if (IsEqualGUID( &dev->guid, &GUID_SysMouse ))
108 list_add_tail( dev->use_raw_input ? &acquired_rawmouse_list : &acquired_mouse_list, &dev->entry );
109 else if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard ))
110 list_add_tail( &acquired_keyboard_list, &dev->entry );
111 else
112 list_add_tail( &acquired_device_list, &dev->entry );
113 LeaveCriticalSection( &dinput_hook_crit );
116 void dinput_hooks_unacquire_device(LPDIRECTINPUTDEVICE8W iface)
118 IDirectInputDeviceImpl *dev = impl_from_IDirectInputDevice8W(iface);
120 EnterCriticalSection( &dinput_hook_crit );
121 list_remove( &dev->entry );
122 LeaveCriticalSection( &dinput_hook_crit );
125 static HRESULT create_directinput_instance(REFIID riid, LPVOID *ppDI, IDirectInputImpl **out)
127 IDirectInputImpl *This = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectInputImpl) );
128 HRESULT hr;
130 if (!This)
131 return E_OUTOFMEMORY;
133 This->IDirectInput7A_iface.lpVtbl = &dinput7_a_vtbl;
134 This->IDirectInput7W_iface.lpVtbl = &ddi7wvt;
135 This->IDirectInput8A_iface.lpVtbl = &dinput8_a_vtbl;
136 This->IDirectInput8W_iface.lpVtbl = &ddi8wvt;
137 This->IDirectInputJoyConfig8_iface.lpVtbl = &JoyConfig8vt;
139 hr = IDirectInput_QueryInterface( &This->IDirectInput7A_iface, riid, ppDI );
140 if (FAILED(hr))
142 HeapFree( GetProcessHeap(), 0, This );
143 return hr;
146 if (out) *out = This;
147 return DI_OK;
150 /******************************************************************************
151 * DirectInputCreateEx (DINPUT.@)
153 HRESULT WINAPI DirectInputCreateEx(
154 HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI,
155 LPUNKNOWN punkOuter)
157 IDirectInputImpl *This;
158 HRESULT hr;
160 TRACE("(%p,%04x,%s,%p,%p)\n", hinst, dwVersion, debugstr_guid(riid), ppDI, punkOuter);
162 if (IsEqualGUID( &IID_IDirectInputA, riid ) ||
163 IsEqualGUID( &IID_IDirectInput2A, riid ) ||
164 IsEqualGUID( &IID_IDirectInput7A, riid ) ||
165 IsEqualGUID( &IID_IDirectInputW, riid ) ||
166 IsEqualGUID( &IID_IDirectInput2W, riid ) ||
167 IsEqualGUID( &IID_IDirectInput7W, riid ))
169 hr = create_directinput_instance(riid, ppDI, &This);
170 if (FAILED(hr))
171 return hr;
173 else
174 return DIERR_NOINTERFACE;
176 hr = IDirectInput_Initialize( &This->IDirectInput7A_iface, hinst, dwVersion );
177 if (FAILED(hr))
179 IDirectInput_Release( &This->IDirectInput7A_iface );
180 *ppDI = NULL;
181 return hr;
184 return DI_OK;
187 /******************************************************************************
188 * DirectInput8Create (DINPUT8.@)
190 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInput8Create(HINSTANCE hinst,
191 DWORD version, REFIID iid, void **out, IUnknown *outer)
193 IDirectInputImpl *This;
194 HRESULT hr;
196 TRACE("hinst %p, version %#x, iid %s, out %p, outer %p.\n",
197 hinst, version, debugstr_guid(iid), out, outer);
199 if (!out)
200 return E_POINTER;
202 if (!IsEqualGUID(&IID_IDirectInput8A, iid) &&
203 !IsEqualGUID(&IID_IDirectInput8W, iid) &&
204 !IsEqualGUID(&IID_IUnknown, iid))
206 *out = NULL;
207 return DIERR_NOINTERFACE;
210 hr = create_directinput_instance(iid, out, &This);
212 if (FAILED(hr))
214 ERR("Failed to create DirectInput, hr %#x.\n", hr);
215 return hr;
218 /* When aggregation is used, the application needs to manually call Initialize(). */
219 if (!outer && IsEqualGUID(&IID_IDirectInput8A, iid))
221 hr = IDirectInput8_Initialize(&This->IDirectInput8A_iface, hinst, version);
222 if (FAILED(hr))
224 IDirectInput8_Release(&This->IDirectInput8A_iface);
225 *out = NULL;
226 return hr;
230 if (!outer && IsEqualGUID(&IID_IDirectInput8W, iid))
232 hr = IDirectInput8_Initialize(&This->IDirectInput8W_iface, hinst, version);
233 if (FAILED(hr))
235 IDirectInput8_Release(&This->IDirectInput8W_iface);
236 *out = NULL;
237 return hr;
241 return S_OK;
244 /******************************************************************************
245 * DirectInputCreateA (DINPUT.@)
247 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
249 return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7A, (LPVOID *)ppDI, punkOuter);
252 /******************************************************************************
253 * DirectInputCreateW (DINPUT.@)
255 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter)
257 return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7W, (LPVOID *)ppDI, punkOuter);
260 static const char *_dump_DIDEVTYPE_value(DWORD dwDevType, DWORD dwVersion)
262 if (dwVersion < 0x0800) {
263 switch (dwDevType) {
264 case 0: return "All devices";
265 case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE";
266 case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD";
267 case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK";
268 case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE";
269 default: return "Unknown";
271 } else {
272 switch (dwDevType) {
273 case DI8DEVCLASS_ALL: return "All devices";
274 case DI8DEVCLASS_POINTER: return "DI8DEVCLASS_POINTER";
275 case DI8DEVCLASS_KEYBOARD: return "DI8DEVCLASS_KEYBOARD";
276 case DI8DEVCLASS_DEVICE: return "DI8DEVCLASS_DEVICE";
277 case DI8DEVCLASS_GAMECTRL: return "DI8DEVCLASS_GAMECTRL";
278 default: return "Unknown";
283 static void _dump_EnumDevices_dwFlags(DWORD dwFlags)
285 if (TRACE_ON(dinput)) {
286 unsigned int i;
287 static const struct {
288 DWORD mask;
289 const char *name;
290 } flags[] = {
291 #define FE(x) { x, #x}
292 FE(DIEDFL_ALLDEVICES),
293 FE(DIEDFL_ATTACHEDONLY),
294 FE(DIEDFL_FORCEFEEDBACK),
295 FE(DIEDFL_INCLUDEALIASES),
296 FE(DIEDFL_INCLUDEPHANTOMS),
297 FE(DIEDFL_INCLUDEHIDDEN)
298 #undef FE
300 TRACE(" flags: ");
301 if (dwFlags == 0) {
302 TRACE("DIEDFL_ALLDEVICES\n");
303 return;
305 for (i = 0; i < ARRAY_SIZE(flags); i++)
306 if (flags[i].mask & dwFlags)
307 TRACE("%s ",flags[i].name);
309 TRACE("\n");
312 static DWORD diactionformat_priorityW(LPDIACTIONFORMATW lpdiaf, DWORD genre)
314 int i;
315 DWORD priorityFlags = 0;
317 /* If there's at least one action for the device it's priority 1 */
318 for(i=0; i < lpdiaf->dwNumActions; i++)
319 if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre)
320 priorityFlags |= DIEDBS_MAPPEDPRI1;
322 return priorityFlags;
325 #if defined __i386__ && defined _MSC_VER
326 __declspec(naked) BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref)
328 __asm
330 push ebp
331 mov ebp, esp
332 push [ebp+16]
333 push [ebp+12]
334 call [ebp+8]
335 leave
339 #elif defined __i386__ && defined __GNUC__
340 extern BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref);
341 __ASM_GLOBAL_FUNC( enum_callback_wrapper,
342 "pushl %ebp\n\t"
343 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
344 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
345 "movl %esp,%ebp\n\t"
346 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
347 "pushl 16(%ebp)\n\t"
348 "pushl 12(%ebp)\n\t"
349 "call *8(%ebp)\n\t"
350 "leave\n\t"
351 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
352 __ASM_CFI(".cfi_same_value %ebp\n\t")
353 "ret" )
354 #else
355 #define enum_callback_wrapper(callback, instance, ref) (callback)((instance), (ref))
356 #endif
358 /******************************************************************************
359 * IDirectInputW_EnumDevices
361 static HRESULT WINAPI IDirectInputWImpl_EnumDevices(
362 LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
363 LPVOID pvRef, DWORD dwFlags)
365 IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
366 DIDEVICEINSTANCEW devInstance;
367 unsigned int i;
368 int j;
369 HRESULT r;
371 TRACE("(this=%p,0x%04x '%s',%p,%p,0x%04x)\n",
372 This, dwDevType, _dump_DIDEVTYPE_value(dwDevType, This->dwVersion),
373 lpCallback, pvRef, dwFlags);
374 _dump_EnumDevices_dwFlags(dwFlags);
376 if (!lpCallback ||
377 dwFlags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN) ||
378 (dwDevType > DI8DEVCLASS_GAMECTRL && dwDevType < DI8DEVTYPE_DEVICE) || dwDevType > DI8DEVTYPE_SUPPLEMENTAL)
379 return DIERR_INVALIDPARAM;
381 if (!This->initialized)
382 return DIERR_NOTINITIALIZED;
384 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) {
385 if (!dinput_devices[i]->enum_device) continue;
386 for (j = 0, r = S_OK; SUCCEEDED(r); j++) {
387 devInstance.dwSize = sizeof(devInstance);
388 TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name);
389 r = dinput_devices[i]->enum_device(dwDevType, dwFlags, &devInstance, This->dwVersion, j);
390 if (r == S_OK)
391 if (enum_callback_wrapper(lpCallback, &devInstance, pvRef) == DIENUM_STOP)
392 return S_OK;
396 return S_OK;
399 static ULONG WINAPI IDirectInputWImpl_AddRef( IDirectInput7W *iface )
401 IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
402 ULONG ref = InterlockedIncrement(&This->ref);
404 TRACE( "(%p) ref %d\n", This, ref );
405 return ref;
408 static ULONG WINAPI IDirectInputWImpl_Release( IDirectInput7W *iface )
410 IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
411 ULONG ref = InterlockedDecrement( &This->ref );
413 TRACE( "(%p) ref %d\n", This, ref );
415 if (ref == 0)
417 uninitialize_directinput_instance( This );
418 HeapFree( GetProcessHeap(), 0, This );
421 return ref;
424 static HRESULT WINAPI IDirectInputWImpl_QueryInterface( IDirectInput7W *iface, REFIID riid, LPVOID *ppobj )
426 IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
428 TRACE( "(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj );
430 if (!riid || !ppobj)
431 return E_POINTER;
433 *ppobj = NULL;
435 #if DIRECTINPUT_VERSION == 0x0700
436 if (IsEqualGUID( &IID_IDirectInputA, riid ) ||
437 IsEqualGUID( &IID_IDirectInput2A, riid ) ||
438 IsEqualGUID( &IID_IDirectInput7A, riid ))
439 *ppobj = &This->IDirectInput7A_iface;
440 else if (IsEqualGUID( &IID_IUnknown, riid ) ||
441 IsEqualGUID( &IID_IDirectInputW, riid ) ||
442 IsEqualGUID( &IID_IDirectInput2W, riid ) ||
443 IsEqualGUID( &IID_IDirectInput7W, riid ))
444 *ppobj = &This->IDirectInput7W_iface;
446 #else
447 if (IsEqualGUID( &IID_IDirectInput8A, riid ))
448 *ppobj = &This->IDirectInput8A_iface;
450 else if (IsEqualGUID( &IID_IUnknown, riid ) ||
451 IsEqualGUID( &IID_IDirectInput8W, riid ))
452 *ppobj = &This->IDirectInput8W_iface;
454 #endif
456 if (IsEqualGUID( &IID_IDirectInputJoyConfig8, riid ))
457 *ppobj = &This->IDirectInputJoyConfig8_iface;
459 if(*ppobj)
461 IUnknown_AddRef( (IUnknown*)*ppobj );
462 return DI_OK;
465 WARN( "Unsupported interface: %s\n", debugstr_guid(riid));
466 return E_NOINTERFACE;
469 static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
471 IDirectInputDeviceImpl *dev;
472 RAWINPUT ri;
473 UINT size = sizeof(ri);
474 int rim = GET_RAWINPUT_CODE_WPARAM( wparam );
476 TRACE( "%p %d %lx %lx\n", hwnd, msg, wparam, lparam );
478 if (msg == WM_INPUT && (rim == RIM_INPUT || rim == RIM_INPUTSINK))
480 size = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) );
481 if (size == (UINT)-1 || size < sizeof(RAWINPUTHEADER))
482 WARN( "Unable to read raw input data\n" );
483 else if (ri.header.dwType == RIM_TYPEMOUSE)
485 EnterCriticalSection( &dinput_hook_crit );
486 LIST_FOR_EACH_ENTRY( dev, &acquired_rawmouse_list, IDirectInputDeviceImpl, entry )
487 dinput_mouse_rawinput_hook( &dev->IDirectInputDevice8W_iface, wparam, lparam, &ri );
488 LeaveCriticalSection( &dinput_hook_crit );
492 return DefWindowProcW( hwnd, msg, wparam, lparam );
495 static void register_di_em_win_class(void)
497 WNDCLASSEXW class;
499 memset(&class, 0, sizeof(class));
500 class.cbSize = sizeof(class);
501 class.lpfnWndProc = di_em_win_wndproc;
502 class.hInstance = DINPUT_instance;
503 class.lpszClassName = di_em_win_w;
505 if (!RegisterClassExW( &class ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
506 WARN( "Unable to register message window class\n" );
509 static void unregister_di_em_win_class(void)
511 if (!UnregisterClassW( di_em_win_w, NULL ) && GetLastError() != ERROR_CLASS_DOES_NOT_EXIST)
512 WARN( "Unable to unregister message window class\n" );
515 static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion)
517 if (!This->initialized)
519 This->dwVersion = dwVersion;
520 This->evsequence = 1;
522 list_init( &This->device_players );
524 /* Add self to the list of the IDirectInputs */
525 EnterCriticalSection( &dinput_hook_crit );
526 list_add_head( &direct_input_list, &This->entry );
527 LeaveCriticalSection( &dinput_hook_crit );
529 This->initialized = TRUE;
531 if (!check_hook_thread())
533 uninitialize_directinput_instance( This );
534 return DIERR_GENERIC;
538 return DI_OK;
541 static void uninitialize_directinput_instance(IDirectInputImpl *This)
543 if (This->initialized)
545 struct DevicePlayer *device_player, *device_player2;
546 /* Remove self from the list of the IDirectInputs */
547 EnterCriticalSection( &dinput_hook_crit );
548 list_remove( &This->entry );
549 LeaveCriticalSection( &dinput_hook_crit );
551 LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2,
552 &This->device_players, struct DevicePlayer, entry )
553 HeapFree(GetProcessHeap(), 0, device_player);
555 check_hook_thread();
557 This->initialized = FALSE;
561 enum directinput_versions
563 DIRECTINPUT_VERSION_300 = 0x0300,
564 DIRECTINPUT_VERSION_500 = 0x0500,
565 DIRECTINPUT_VERSION_50A = 0x050A,
566 DIRECTINPUT_VERSION_5B2 = 0x05B2,
567 DIRECTINPUT_VERSION_602 = 0x0602,
568 DIRECTINPUT_VERSION_61A = 0x061A,
569 DIRECTINPUT_VERSION_700 = 0x0700,
572 static HRESULT WINAPI IDirectInputWImpl_Initialize( IDirectInput7W *iface, HINSTANCE hinst, DWORD version )
574 IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
576 TRACE("(%p)->(%p, 0x%04x)\n", This, hinst, version);
578 if (!hinst)
579 return DIERR_INVALIDPARAM;
580 else if (version == 0)
581 return DIERR_NOTINITIALIZED;
582 else if (version > DIRECTINPUT_VERSION_700)
583 return DIERR_OLDDIRECTINPUTVERSION;
584 else if (version != DIRECTINPUT_VERSION_300 && version != DIRECTINPUT_VERSION_500 &&
585 version != DIRECTINPUT_VERSION_50A && version != DIRECTINPUT_VERSION_5B2 &&
586 version != DIRECTINPUT_VERSION_602 && version != DIRECTINPUT_VERSION_61A &&
587 version != DIRECTINPUT_VERSION_700 && version != DIRECTINPUT_VERSION)
588 return DIERR_BETADIRECTINPUTVERSION;
590 return initialize_directinput_instance(This, version);
593 static HRESULT WINAPI IDirectInputWImpl_GetDeviceStatus( IDirectInput7W *iface, REFGUID rguid )
595 IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
596 HRESULT hr;
597 IDirectInputDeviceW *device;
599 TRACE( "(%p)->(%s)\n", This, debugstr_guid(rguid) );
601 if (!rguid) return E_POINTER;
602 if (!This->initialized)
603 return DIERR_NOTINITIALIZED;
605 hr = IDirectInput_CreateDevice( iface, rguid, &device, NULL );
606 if (hr != DI_OK) return DI_NOTATTACHED;
608 IUnknown_Release( device );
610 return DI_OK;
613 static HRESULT WINAPI IDirectInputWImpl_RunControlPanel( IDirectInput7W *iface, HWND hwndOwner, DWORD dwFlags )
615 IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
616 WCHAR control_exeW[] = {'c','o','n','t','r','o','l','.','e','x','e',0};
617 STARTUPINFOW si = {0};
618 PROCESS_INFORMATION pi;
620 TRACE( "(%p)->(%p, %08x)\n", This, hwndOwner, dwFlags );
622 if (hwndOwner && !IsWindow(hwndOwner))
623 return E_HANDLE;
625 if (dwFlags)
626 return DIERR_INVALIDPARAM;
628 if (!This->initialized)
629 return DIERR_NOTINITIALIZED;
631 if (!CreateProcessW(NULL, control_exeW, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
632 return HRESULT_FROM_WIN32(GetLastError());
634 return DI_OK;
637 static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
638 LPCWSTR pszName, LPGUID pguidInstance)
640 IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
642 FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance );
644 return DI_OK;
647 static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx( IDirectInput7W *iface, REFGUID rguid, REFIID riid,
648 LPVOID *pvOut, LPUNKNOWN lpUnknownOuter )
650 IDirectInputDevice8W *device;
651 IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
652 unsigned int i;
653 HRESULT hr;
655 TRACE( "(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid( rguid ), debugstr_guid( riid ), pvOut, lpUnknownOuter );
657 if (pvOut)
658 *pvOut = NULL;
660 if (!rguid || !pvOut)
661 return E_POINTER;
663 if (!This->initialized)
664 return DIERR_NOTINITIALIZED;
666 /* Loop on all the devices to see if anyone matches the given GUID */
667 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++)
669 if (!dinput_devices[i]->create_device) continue;
670 if (SUCCEEDED(hr = dinput_devices[i]->create_device( This, rguid, &device )))
672 hr = IDirectInputDevice8_QueryInterface( device, riid, pvOut );
673 IDirectInputDevice8_Release( device );
674 return hr;
678 WARN("invalid device GUID %s\n", debugstr_guid(rguid));
679 return DIERR_DEVICENOTREG;
682 static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
683 LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk)
685 return IDirectInput7_CreateDeviceEx( iface, rguid, &IID_IDirectInputDeviceW, (LPVOID *)pdev, punk );
688 /*******************************************************************************
689 * DirectInput8
692 static ULONG WINAPI IDirectInput8WImpl_AddRef(LPDIRECTINPUT8W iface)
694 IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
695 return IDirectInput_AddRef( &This->IDirectInput7W_iface );
698 static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj)
700 IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
701 return IDirectInput_QueryInterface( &This->IDirectInput7W_iface, riid, ppobj );
704 static ULONG WINAPI IDirectInput8WImpl_Release(LPDIRECTINPUT8W iface)
706 IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
707 return IDirectInput_Release( &This->IDirectInput7W_iface );
710 static HRESULT WINAPI IDirectInput8WImpl_CreateDevice(LPDIRECTINPUT8W iface, REFGUID rguid,
711 LPDIRECTINPUTDEVICE8W* pdev, LPUNKNOWN punk)
713 IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
714 return IDirectInput7_CreateDeviceEx( &This->IDirectInput7W_iface, rguid, &IID_IDirectInputDevice8W, (LPVOID *)pdev, punk );
717 static HRESULT WINAPI IDirectInput8WImpl_EnumDevices(LPDIRECTINPUT8W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
718 LPVOID pvRef, DWORD dwFlags)
720 IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
721 return IDirectInput_EnumDevices( &This->IDirectInput7W_iface, dwDevType, lpCallback, pvRef, dwFlags );
724 static HRESULT WINAPI IDirectInput8WImpl_GetDeviceStatus(LPDIRECTINPUT8W iface, REFGUID rguid)
726 IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
727 return IDirectInput_GetDeviceStatus( &This->IDirectInput7W_iface, rguid );
730 static HRESULT WINAPI IDirectInput8WImpl_RunControlPanel(LPDIRECTINPUT8W iface, HWND hwndOwner, DWORD dwFlags)
732 IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
733 return IDirectInput_RunControlPanel( &This->IDirectInput7W_iface, hwndOwner, dwFlags );
736 static HRESULT WINAPI IDirectInput8WImpl_Initialize( IDirectInput8W *iface, HINSTANCE hinst, DWORD version )
738 IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
740 TRACE("(%p)->(%p, 0x%04x)\n", This, hinst, version);
742 if (!hinst)
743 return DIERR_INVALIDPARAM;
744 else if (version == 0)
745 return DIERR_NOTINITIALIZED;
746 else if (version < DIRECTINPUT_VERSION)
747 return DIERR_BETADIRECTINPUTVERSION;
748 else if (version > DIRECTINPUT_VERSION)
749 return DIERR_OLDDIRECTINPUTVERSION;
751 return initialize_directinput_instance(This, version);
754 static HRESULT WINAPI IDirectInput8WImpl_FindDevice(LPDIRECTINPUT8W iface, REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance)
756 IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
757 return IDirectInput2_FindDevice( &This->IDirectInput7W_iface, rguid, pszName, pguidInstance );
760 static BOOL should_enumerate_device(const WCHAR *username, DWORD dwFlags,
761 struct list *device_players, REFGUID guid)
763 BOOL should_enumerate = TRUE;
764 struct DevicePlayer *device_player;
766 /* Check if user owns this device */
767 if (dwFlags & DIEDBSFL_THISUSER && username && *username)
769 should_enumerate = FALSE;
770 LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry)
772 if (IsEqualGUID(&device_player->instance_guid, guid))
774 if (*device_player->username && !lstrcmpW(username, device_player->username))
775 return TRUE; /* Device username matches */
776 break;
781 /* Check if this device is not owned by anyone */
782 if (dwFlags & DIEDBSFL_AVAILABLEDEVICES) {
783 BOOL found = FALSE;
784 should_enumerate = FALSE;
785 LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry)
787 if (IsEqualGUID(&device_player->instance_guid, guid))
789 if (*device_player->username)
790 found = TRUE;
791 break;
794 if (!found)
795 return TRUE; /* Device does not have a username */
798 return should_enumerate;
801 static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
802 LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat,
803 LPDIENUMDEVICESBYSEMANTICSCBW lpCallback,
804 LPVOID pvRef, DWORD dwFlags
807 static REFGUID guids[2] = { &GUID_SysKeyboard, &GUID_SysMouse };
808 static const DWORD actionMasks[] = { DIKEYBOARD_MASK, DIMOUSE_MASK };
809 IDirectInputImpl *This = impl_from_IDirectInput8W(iface);
810 DIDEVICEINSTANCEW didevi;
811 LPDIRECTINPUTDEVICE8W lpdid;
812 DWORD callbackFlags;
813 int i, j;
814 int device_count = 0;
815 int remain;
816 DIDEVICEINSTANCEW *didevis = 0;
818 FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat,
819 lpCallback, pvRef, dwFlags);
821 didevi.dwSize = sizeof(didevi);
823 /* Enumerate all the joysticks */
824 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++)
826 HRESULT enumSuccess;
828 if (!dinput_devices[i]->enum_device) continue;
830 for (j = 0, enumSuccess = S_OK; SUCCEEDED(enumSuccess); j++)
832 TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name);
834 /* Default behavior is to enumerate attached game controllers */
835 enumSuccess = dinput_devices[i]->enum_device(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j);
836 if (enumSuccess == S_OK &&
837 should_enumerate_device(ptszUserName, dwFlags, &This->device_players, &didevi.guidInstance))
839 if (device_count++)
840 didevis = HeapReAlloc(GetProcessHeap(), 0, didevis, sizeof(DIDEVICEINSTANCEW)*device_count);
841 else
842 didevis = HeapAlloc(GetProcessHeap(), 0, sizeof(DIDEVICEINSTANCEW)*device_count);
843 didevis[device_count-1] = didevi;
848 remain = device_count;
849 /* Add keyboard and mouse to remaining device count */
850 if (!(dwFlags & DIEDBSFL_FORCEFEEDBACK))
852 for (i = 0; i < ARRAY_SIZE(guids); i++)
854 if (should_enumerate_device(ptszUserName, dwFlags, &This->device_players, guids[i]))
855 remain++;
859 for (i = 0; i < device_count; i++)
861 callbackFlags = diactionformat_priorityW(lpdiActionFormat, lpdiActionFormat->dwGenre);
862 IDirectInput_CreateDevice(iface, &didevis[i].guidInstance, &lpdid, NULL);
864 if (lpCallback(&didevis[i], lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
866 HeapFree(GetProcessHeap(), 0, didevis);
867 IDirectInputDevice_Release(lpdid);
868 return DI_OK;
870 IDirectInputDevice_Release(lpdid);
873 HeapFree(GetProcessHeap(), 0, didevis);
875 if (dwFlags & DIEDBSFL_FORCEFEEDBACK) return DI_OK;
877 /* Enumerate keyboard and mouse */
878 for (i = 0; i < ARRAY_SIZE(guids); i++)
880 if (should_enumerate_device(ptszUserName, dwFlags, &This->device_players, guids[i]))
882 callbackFlags = diactionformat_priorityW(lpdiActionFormat, actionMasks[i]);
884 IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL);
885 IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
887 if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
889 IDirectInputDevice_Release(lpdid);
890 return DI_OK;
892 IDirectInputDevice_Release(lpdid);
896 return DI_OK;
899 static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices(
900 LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
901 LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
904 IDirectInputImpl *This = impl_from_IDirectInput8W(iface);
906 FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams, dwFlags, pvRefData);
908 /* Call helper function in config.c to do the real work */
909 return _configure_devices(iface, lpdiCallback, lpdiCDParams, dwFlags, pvRefData);
912 /*****************************************************************************
913 * IDirectInputJoyConfig8 interface
916 static inline IDirectInputImpl *impl_from_IDirectInputJoyConfig8(IDirectInputJoyConfig8 *iface)
918 return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInputJoyConfig8_iface );
921 static HRESULT WINAPI JoyConfig8Impl_QueryInterface(IDirectInputJoyConfig8 *iface, REFIID riid, void** ppobj)
923 IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface );
924 return IDirectInput_QueryInterface( &This->IDirectInput7W_iface, riid, ppobj );
927 static ULONG WINAPI JoyConfig8Impl_AddRef(IDirectInputJoyConfig8 *iface)
929 IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface );
930 return IDirectInput_AddRef( &This->IDirectInput7W_iface );
933 static ULONG WINAPI JoyConfig8Impl_Release(IDirectInputJoyConfig8 *iface)
935 IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface );
936 return IDirectInput_Release( &This->IDirectInput7W_iface );
939 static HRESULT WINAPI JoyConfig8Impl_Acquire(IDirectInputJoyConfig8 *iface)
941 FIXME( "(%p): stub!\n", iface );
942 return E_NOTIMPL;
945 static HRESULT WINAPI JoyConfig8Impl_Unacquire(IDirectInputJoyConfig8 *iface)
947 FIXME( "(%p): stub!\n", iface );
948 return E_NOTIMPL;
951 static HRESULT WINAPI JoyConfig8Impl_SetCooperativeLevel(IDirectInputJoyConfig8 *iface, HWND hwnd, DWORD flags)
953 FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, hwnd, flags );
954 return E_NOTIMPL;
957 static HRESULT WINAPI JoyConfig8Impl_SendNotify(IDirectInputJoyConfig8 *iface)
959 FIXME( "(%p): stub!\n", iface );
960 return E_NOTIMPL;
963 static HRESULT WINAPI JoyConfig8Impl_EnumTypes(IDirectInputJoyConfig8 *iface, LPDIJOYTYPECALLBACK cb, void *ref)
965 FIXME( "(%p)->(%p, %p): stub!\n", iface, cb, ref );
966 return E_NOTIMPL;
969 static HRESULT WINAPI JoyConfig8Impl_GetTypeInfo(IDirectInputJoyConfig8 *iface, LPCWSTR name, LPDIJOYTYPEINFO info, DWORD flags)
971 FIXME( "(%p)->(%s, %p, 0x%08x): stub!\n", iface, debugstr_w(name), info, flags );
972 return E_NOTIMPL;
975 static HRESULT WINAPI JoyConfig8Impl_SetTypeInfo(IDirectInputJoyConfig8 *iface, LPCWSTR name, LPCDIJOYTYPEINFO info, DWORD flags,
976 LPWSTR new_name)
978 FIXME( "(%p)->(%s, %p, 0x%08x, %s): stub!\n", iface, debugstr_w(name), info, flags, debugstr_w(new_name) );
979 return E_NOTIMPL;
982 static HRESULT WINAPI JoyConfig8Impl_DeleteType(IDirectInputJoyConfig8 *iface, LPCWSTR name)
984 FIXME( "(%p)->(%s): stub!\n", iface, debugstr_w(name) );
985 return E_NOTIMPL;
988 static HRESULT WINAPI JoyConfig8Impl_GetConfig(IDirectInputJoyConfig8 *iface, UINT id, LPDIJOYCONFIG info, DWORD flags)
990 IDirectInputImpl *di = impl_from_IDirectInputJoyConfig8(iface);
991 UINT found = 0;
992 int i, j;
993 HRESULT r;
995 FIXME("(%p)->(%d, %p, 0x%08x): semi-stub!\n", iface, id, info, flags);
997 #define X(x) if (flags & x) FIXME("\tflags |= "#x"\n");
998 X(DIJC_GUIDINSTANCE)
999 X(DIJC_REGHWCONFIGTYPE)
1000 X(DIJC_GAIN)
1001 X(DIJC_CALLOUT)
1002 #undef X
1004 /* Enumerate all joysticks in order */
1005 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++)
1007 if (!dinput_devices[i]->enum_device) continue;
1009 for (j = 0, r = S_OK; SUCCEEDED(r); j++)
1011 DIDEVICEINSTANCEW dev;
1012 dev.dwSize = sizeof(dev);
1013 if ((r = dinput_devices[i]->enum_device(DI8DEVCLASS_GAMECTRL, 0, &dev, di->dwVersion, j)) == S_OK)
1015 /* Only take into account the chosen id */
1016 if (found == id)
1018 if (flags & DIJC_GUIDINSTANCE)
1019 info->guidInstance = dev.guidInstance;
1021 return DI_OK;
1023 found += 1;
1028 return DIERR_NOMOREITEMS;
1031 static HRESULT WINAPI JoyConfig8Impl_SetConfig(IDirectInputJoyConfig8 *iface, UINT id, LPCDIJOYCONFIG info, DWORD flags)
1033 FIXME( "(%p)->(%d, %p, 0x%08x): stub!\n", iface, id, info, flags );
1034 return E_NOTIMPL;
1037 static HRESULT WINAPI JoyConfig8Impl_DeleteConfig(IDirectInputJoyConfig8 *iface, UINT id)
1039 FIXME( "(%p)->(%d): stub!\n", iface, id );
1040 return E_NOTIMPL;
1043 static HRESULT WINAPI JoyConfig8Impl_GetUserValues(IDirectInputJoyConfig8 *iface, LPDIJOYUSERVALUES info, DWORD flags)
1045 FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, info, flags );
1046 return E_NOTIMPL;
1049 static HRESULT WINAPI JoyConfig8Impl_SetUserValues(IDirectInputJoyConfig8 *iface, LPCDIJOYUSERVALUES info, DWORD flags)
1051 FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, info, flags );
1052 return E_NOTIMPL;
1055 static HRESULT WINAPI JoyConfig8Impl_AddNewHardware(IDirectInputJoyConfig8 *iface, HWND hwnd, REFGUID guid)
1057 FIXME( "(%p)->(%p, %s): stub!\n", iface, hwnd, debugstr_guid(guid) );
1058 return E_NOTIMPL;
1061 static HRESULT WINAPI JoyConfig8Impl_OpenTypeKey(IDirectInputJoyConfig8 *iface, LPCWSTR name, DWORD security, PHKEY key)
1063 FIXME( "(%p)->(%s, 0x%08x, %p): stub!\n", iface, debugstr_w(name), security, key );
1064 return E_NOTIMPL;
1067 static HRESULT WINAPI JoyConfig8Impl_OpenAppStatusKey(IDirectInputJoyConfig8 *iface, PHKEY key)
1069 FIXME( "(%p)->(%p): stub!\n", iface, key );
1070 return E_NOTIMPL;
1073 static const IDirectInput7WVtbl ddi7wvt = {
1074 IDirectInputWImpl_QueryInterface,
1075 IDirectInputWImpl_AddRef,
1076 IDirectInputWImpl_Release,
1077 IDirectInputWImpl_CreateDevice,
1078 IDirectInputWImpl_EnumDevices,
1079 IDirectInputWImpl_GetDeviceStatus,
1080 IDirectInputWImpl_RunControlPanel,
1081 IDirectInputWImpl_Initialize,
1082 IDirectInput2WImpl_FindDevice,
1083 IDirectInput7WImpl_CreateDeviceEx
1086 static const IDirectInput8WVtbl ddi8wvt = {
1087 IDirectInput8WImpl_QueryInterface,
1088 IDirectInput8WImpl_AddRef,
1089 IDirectInput8WImpl_Release,
1090 IDirectInput8WImpl_CreateDevice,
1091 IDirectInput8WImpl_EnumDevices,
1092 IDirectInput8WImpl_GetDeviceStatus,
1093 IDirectInput8WImpl_RunControlPanel,
1094 IDirectInput8WImpl_Initialize,
1095 IDirectInput8WImpl_FindDevice,
1096 IDirectInput8WImpl_EnumDevicesBySemantics,
1097 IDirectInput8WImpl_ConfigureDevices
1100 static const IDirectInputJoyConfig8Vtbl JoyConfig8vt =
1102 JoyConfig8Impl_QueryInterface,
1103 JoyConfig8Impl_AddRef,
1104 JoyConfig8Impl_Release,
1105 JoyConfig8Impl_Acquire,
1106 JoyConfig8Impl_Unacquire,
1107 JoyConfig8Impl_SetCooperativeLevel,
1108 JoyConfig8Impl_SendNotify,
1109 JoyConfig8Impl_EnumTypes,
1110 JoyConfig8Impl_GetTypeInfo,
1111 JoyConfig8Impl_SetTypeInfo,
1112 JoyConfig8Impl_DeleteType,
1113 JoyConfig8Impl_GetConfig,
1114 JoyConfig8Impl_SetConfig,
1115 JoyConfig8Impl_DeleteConfig,
1116 JoyConfig8Impl_GetUserValues,
1117 JoyConfig8Impl_SetUserValues,
1118 JoyConfig8Impl_AddNewHardware,
1119 JoyConfig8Impl_OpenTypeKey,
1120 JoyConfig8Impl_OpenAppStatusKey
1123 /*******************************************************************************
1124 * DirectInput ClassFactory
1126 typedef struct
1128 /* IUnknown fields */
1129 IClassFactory IClassFactory_iface;
1130 LONG ref;
1131 } IClassFactoryImpl;
1133 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1135 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
1138 static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1139 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1141 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1142 return E_NOINTERFACE;
1145 static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) {
1146 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1147 return InterlockedIncrement(&(This->ref));
1150 static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) {
1151 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1152 /* static class, won't be freed */
1153 return InterlockedDecrement(&(This->ref));
1156 static HRESULT WINAPI DICF_CreateInstance(
1157 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
1159 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1161 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1162 if ( IsEqualGUID( &IID_IUnknown, riid ) ||
1163 IsEqualGUID( &IID_IDirectInputA, riid ) ||
1164 IsEqualGUID( &IID_IDirectInputW, riid ) ||
1165 IsEqualGUID( &IID_IDirectInput2A, riid ) ||
1166 IsEqualGUID( &IID_IDirectInput2W, riid ) ||
1167 IsEqualGUID( &IID_IDirectInput7A, riid ) ||
1168 IsEqualGUID( &IID_IDirectInput7W, riid ) ||
1169 IsEqualGUID( &IID_IDirectInput8A, riid ) ||
1170 IsEqualGUID( &IID_IDirectInput8W, riid ) )
1172 return create_directinput_instance(riid, ppobj, NULL);
1175 FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
1176 return E_NOINTERFACE;
1179 static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1180 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1181 FIXME("(%p)->(%d),stub!\n",This,dolock);
1182 return S_OK;
1185 static const IClassFactoryVtbl DICF_Vtbl = {
1186 DICF_QueryInterface,
1187 DICF_AddRef,
1188 DICF_Release,
1189 DICF_CreateInstance,
1190 DICF_LockServer
1192 static IClassFactoryImpl DINPUT_CF = {{&DICF_Vtbl}, 1 };
1194 /***********************************************************************
1195 * DllGetClassObject (DINPUT.@)
1197 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1199 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1200 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1201 *ppv = &DINPUT_CF;
1202 IClassFactory_AddRef((IClassFactory*)*ppv);
1203 return S_OK;
1206 FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1207 return CLASS_E_CLASSNOTAVAILABLE;
1210 /******************************************************************************
1211 * DInput hook thread
1214 static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam )
1216 IDirectInputDeviceImpl *dev;
1217 int skip = 0;
1219 if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam );
1221 EnterCriticalSection( &dinput_hook_crit );
1222 LIST_FOR_EACH_ENTRY( dev, &acquired_mouse_list, IDirectInputDeviceImpl, entry )
1224 TRACE("calling dinput_mouse_hook (%p %lx %lx)\n", dev, wparam, lparam);
1225 skip |= dinput_mouse_hook( &dev->IDirectInputDevice8W_iface, wparam, lparam );
1227 LIST_FOR_EACH_ENTRY( dev, &acquired_keyboard_list, IDirectInputDeviceImpl, entry )
1229 if (dev->use_raw_input) continue;
1230 TRACE("calling dinput_keyboard_hook (%p %lx %lx)\n", dev, wparam, lparam);
1231 skip |= dinput_keyboard_hook( &dev->IDirectInputDevice8W_iface, wparam, lparam );
1233 LeaveCriticalSection( &dinput_hook_crit );
1235 return skip ? 1 : CallNextHookEx( 0, code, wparam, lparam );
1238 static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam )
1240 IDirectInputDeviceImpl *dev, *next;
1241 CWPSTRUCT *msg = (CWPSTRUCT *)lparam;
1242 HWND foreground;
1244 if (code != HC_ACTION || (msg->message != WM_KILLFOCUS &&
1245 msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE))
1246 return CallNextHookEx( 0, code, wparam, lparam );
1248 foreground = GetForegroundWindow();
1250 EnterCriticalSection( &dinput_hook_crit );
1251 LIST_FOR_EACH_ENTRY_SAFE( dev, next, &acquired_device_list, IDirectInputDeviceImpl, entry )
1253 if (msg->hwnd == dev->win && msg->hwnd != foreground)
1255 TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev );
1256 IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8W_iface );
1259 LIST_FOR_EACH_ENTRY_SAFE( dev, next, &acquired_mouse_list, IDirectInputDeviceImpl, entry )
1261 if (msg->hwnd == dev->win && msg->hwnd != foreground)
1263 TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev );
1264 IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8W_iface );
1267 LIST_FOR_EACH_ENTRY_SAFE( dev, next, &acquired_rawmouse_list, IDirectInputDeviceImpl, entry )
1269 if (msg->hwnd == dev->win && msg->hwnd != foreground)
1271 TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev );
1272 IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8W_iface );
1275 LIST_FOR_EACH_ENTRY_SAFE( dev, next, &acquired_keyboard_list, IDirectInputDeviceImpl, entry )
1277 if (msg->hwnd == dev->win && msg->hwnd != foreground)
1279 TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev );
1280 IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8W_iface );
1283 LeaveCriticalSection( &dinput_hook_crit );
1285 return CallNextHookEx( 0, code, wparam, lparam );
1288 static DWORD WINAPI hook_thread_proc(void *param)
1290 static HHOOK kbd_hook, mouse_hook;
1291 MSG msg;
1293 di_em_win = CreateWindowW( di_em_win_w, di_em_win_w, 0, 0, 0, 0, 0,
1294 HWND_MESSAGE, 0, DINPUT_instance, NULL );
1296 /* Force creation of the message queue */
1297 PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE );
1298 SetEvent(param);
1300 while (GetMessageW( &msg, 0, 0, 0 ))
1302 UINT kbd_cnt = 0, mice_cnt = 0;
1304 if (msg.message == WM_USER+0x10)
1306 HANDLE finished_event = (HANDLE)msg.lParam;
1308 TRACE( "Processing hook change notification wp:%ld lp:%#lx\n", msg.wParam, msg.lParam );
1310 if (!msg.wParam)
1312 if (kbd_hook) UnhookWindowsHookEx( kbd_hook );
1313 if (mouse_hook) UnhookWindowsHookEx( mouse_hook );
1314 kbd_hook = mouse_hook = NULL;
1315 break;
1318 EnterCriticalSection( &dinput_hook_crit );
1319 kbd_cnt = list_count( &acquired_keyboard_list );
1320 mice_cnt = list_count( &acquired_mouse_list );
1321 LeaveCriticalSection( &dinput_hook_crit );
1323 if (kbd_cnt && !kbd_hook)
1324 kbd_hook = SetWindowsHookExW( WH_KEYBOARD_LL, LL_hook_proc, DINPUT_instance, 0 );
1325 else if (!kbd_cnt && kbd_hook)
1327 UnhookWindowsHookEx( kbd_hook );
1328 kbd_hook = NULL;
1331 if (mice_cnt && !mouse_hook)
1332 mouse_hook = SetWindowsHookExW( WH_MOUSE_LL, LL_hook_proc, DINPUT_instance, 0 );
1333 else if (!mice_cnt && mouse_hook)
1335 UnhookWindowsHookEx( mouse_hook );
1336 mouse_hook = NULL;
1339 if (finished_event)
1340 SetEvent(finished_event);
1342 TranslateMessage(&msg);
1343 DispatchMessageW(&msg);
1346 DestroyWindow( di_em_win );
1347 di_em_win = NULL;
1349 FreeLibraryAndExitThread(DINPUT_instance, 0);
1352 static DWORD hook_thread_id;
1353 static HANDLE hook_thread_event;
1355 static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
1357 0, 0, &dinput_hook_crit,
1358 { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
1359 0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
1361 static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
1363 static BOOL check_hook_thread(void)
1365 static HANDLE hook_thread;
1366 HMODULE module;
1367 HANDLE wait_handle = NULL;
1369 EnterCriticalSection(&dinput_hook_crit);
1371 TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list));
1372 if (!list_empty(&direct_input_list) && !hook_thread)
1374 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)DINPUT_instance, &module);
1375 hook_thread_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1376 hook_thread = CreateThread(NULL, 0, hook_thread_proc, hook_thread_event, 0, &hook_thread_id);
1378 else if (list_empty(&direct_input_list) && hook_thread)
1380 DWORD tid = hook_thread_id;
1382 if (hook_thread_event) /* if thread is not started yet */
1384 WaitForSingleObject(hook_thread_event, INFINITE);
1385 CloseHandle(hook_thread_event);
1386 hook_thread_event = NULL;
1389 hook_thread_id = 0;
1390 PostThreadMessageW(tid, WM_USER+0x10, 0, 0);
1391 wait_handle = hook_thread;
1392 hook_thread = NULL;
1395 LeaveCriticalSection(&dinput_hook_crit);
1397 if (wait_handle)
1399 WaitForSingleObject(wait_handle, INFINITE);
1400 CloseHandle(wait_handle);
1402 return hook_thread_id != 0;
1405 void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired)
1407 static HHOOK callwndproc_hook;
1408 static ULONG foreground_cnt;
1409 IDirectInputDeviceImpl *dev = impl_from_IDirectInputDevice8W(iface);
1410 HANDLE hook_change_finished_event = NULL;
1412 EnterCriticalSection(&dinput_hook_crit);
1414 if (dev->dwCoopLevel & DISCL_FOREGROUND)
1416 if (acquired)
1417 foreground_cnt++;
1418 else
1419 foreground_cnt--;
1422 if (foreground_cnt && !callwndproc_hook)
1423 callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc,
1424 DINPUT_instance, GetCurrentThreadId() );
1425 else if (!foreground_cnt && callwndproc_hook)
1427 UnhookWindowsHookEx( callwndproc_hook );
1428 callwndproc_hook = NULL;
1431 if (hook_thread_event) /* if thread is not started yet */
1433 WaitForSingleObject(hook_thread_event, INFINITE);
1434 CloseHandle(hook_thread_event);
1435 hook_thread_event = NULL;
1438 if (dev->use_raw_input)
1440 if (acquired)
1442 dev->raw_device.dwFlags = 0;
1443 if (dev->dwCoopLevel & DISCL_BACKGROUND)
1444 dev->raw_device.dwFlags |= RIDEV_INPUTSINK;
1445 if (dev->dwCoopLevel & DISCL_EXCLUSIVE)
1446 dev->raw_device.dwFlags |= RIDEV_NOLEGACY;
1447 if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 2)
1448 dev->raw_device.dwFlags |= RIDEV_CAPTUREMOUSE;
1449 if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 6)
1450 dev->raw_device.dwFlags |= RIDEV_NOHOTKEYS;
1451 dev->raw_device.hwndTarget = di_em_win;
1453 else
1455 dev->raw_device.dwFlags = RIDEV_REMOVE;
1456 dev->raw_device.hwndTarget = NULL;
1459 if (!RegisterRawInputDevices( &dev->raw_device, 1, sizeof(RAWINPUTDEVICE) ))
1460 WARN( "Unable to (un)register raw device %x:%x\n", dev->raw_device.usUsagePage, dev->raw_device.usUsage );
1463 if (acquired)
1464 hook_change_finished_event = CreateEventW( NULL, FALSE, FALSE, NULL );
1465 PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, (LPARAM)hook_change_finished_event );
1467 LeaveCriticalSection(&dinput_hook_crit);
1469 if (acquired)
1471 WaitForSingleObject(hook_change_finished_event, INFINITE);
1472 CloseHandle(hook_change_finished_event);
1476 void check_dinput_events(void)
1478 /* Windows does not do that, but our current implementation of winex11
1479 * requires periodic event polling to forward events to the wineserver.
1481 * We have to call this function from multiple places, because:
1482 * - some games do not explicitly poll for mouse events
1483 * (for example Culpa Innata)
1484 * - some games only poll the device, and neither keyboard nor mouse
1485 * (for example Civilization: Call to Power 2)
1487 MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0);
1490 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved)
1492 switch(reason)
1494 case DLL_PROCESS_ATTACH:
1495 DisableThreadLibraryCalls(inst);
1496 DINPUT_instance = inst;
1497 register_di_em_win_class();
1498 break;
1499 case DLL_PROCESS_DETACH:
1500 if (reserved) break;
1501 unregister_di_em_win_class();
1502 DeleteCriticalSection(&dinput_hook_crit);
1503 break;
1505 return TRUE;