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
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
39 #define NONAMELESSUNION
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
52 #include "dinput_private.h"
53 #include "device_private.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
[] =
81 &joystick_linuxinput_device
,
82 &joystick_linux_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
);
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
) );
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
);
142 HeapFree( GetProcessHeap(), 0, This
);
146 if (out
) *out
= This
;
150 /******************************************************************************
151 * DirectInputCreateEx (DINPUT.@)
153 HRESULT WINAPI
DirectInputCreateEx(
154 HINSTANCE hinst
, DWORD dwVersion
, REFIID riid
, LPVOID
*ppDI
,
157 IDirectInputImpl
*This
;
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
);
174 return DIERR_NOINTERFACE
;
176 hr
= IDirectInput_Initialize( &This
->IDirectInput7A_iface
, hinst
, dwVersion
);
179 IDirectInput_Release( &This
->IDirectInput7A_iface
);
187 /******************************************************************************
188 * DirectInput8Create (DINPUT8.@)
190 HRESULT WINAPI DECLSPEC_HOTPATCH
DirectInput8Create(HINSTANCE hinst
,
191 DWORD version
, REFIID iid
, void **out
, IUnknown
*outer
)
193 IDirectInputImpl
*This
;
196 TRACE("hinst %p, version %#x, iid %s, out %p, outer %p.\n",
197 hinst
, version
, debugstr_guid(iid
), out
, outer
);
202 if (!IsEqualGUID(&IID_IDirectInput8A
, iid
) &&
203 !IsEqualGUID(&IID_IDirectInput8W
, iid
) &&
204 !IsEqualGUID(&IID_IUnknown
, iid
))
207 return DIERR_NOINTERFACE
;
210 hr
= create_directinput_instance(iid
, out
, &This
);
214 ERR("Failed to create DirectInput, hr %#x.\n", 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
);
224 IDirectInput8_Release(&This
->IDirectInput8A_iface
);
230 if (!outer
&& IsEqualGUID(&IID_IDirectInput8W
, iid
))
232 hr
= IDirectInput8_Initialize(&This
->IDirectInput8W_iface
, hinst
, version
);
235 IDirectInput8_Release(&This
->IDirectInput8W_iface
);
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) {
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";
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
)) {
287 static const struct {
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
)
302 TRACE("DIEDFL_ALLDEVICES\n");
305 for (i
= 0; i
< ARRAY_SIZE(flags
); i
++)
306 if (flags
[i
].mask
& dwFlags
)
307 TRACE("%s ",flags
[i
].name
);
312 static DWORD
diactionformat_priorityW(LPDIACTIONFORMATW lpdiaf
, DWORD genre
)
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
)
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
,
343 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
344 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
346 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
351 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
352 __ASM_CFI(".cfi_same_value %ebp\n\t")
355 #define enum_callback_wrapper(callback, instance, ref) (callback)((instance), (ref))
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
;
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
);
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
);
391 if (enum_callback_wrapper(lpCallback
, &devInstance
, pvRef
) == DIENUM_STOP
)
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
);
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
);
417 uninitialize_directinput_instance( This
);
418 HeapFree( GetProcessHeap(), 0, This
);
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
);
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
;
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
;
456 if (IsEqualGUID( &IID_IDirectInputJoyConfig8
, riid
))
457 *ppobj
= &This
->IDirectInputJoyConfig8_iface
;
461 IUnknown_AddRef( (IUnknown
*)*ppobj
);
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
;
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)
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
;
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
);
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
);
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
);
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
);
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
))
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());
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
);
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
);
655 TRACE( "(%p)->(%s, %s, %p, %p)\n", This
, debugstr_guid( rguid
), debugstr_guid( riid
), pvOut
, lpUnknownOuter
);
660 if (!rguid
|| !pvOut
)
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
);
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 /*******************************************************************************
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
);
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 */
781 /* Check if this device is not owned by anyone */
782 if (dwFlags
& DIEDBSFL_AVAILABLEDEVICES
) {
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
)
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
;
814 int device_count
= 0;
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
++)
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
))
840 didevis
= HeapReAlloc(GetProcessHeap(), 0, didevis
, sizeof(DIDEVICEINSTANCEW
)*device_count
);
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
]))
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
);
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
);
892 IDirectInputDevice_Release(lpdid
);
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
);
945 static HRESULT WINAPI
JoyConfig8Impl_Unacquire(IDirectInputJoyConfig8
*iface
)
947 FIXME( "(%p): stub!\n", iface
);
951 static HRESULT WINAPI
JoyConfig8Impl_SetCooperativeLevel(IDirectInputJoyConfig8
*iface
, HWND hwnd
, DWORD flags
)
953 FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface
, hwnd
, flags
);
957 static HRESULT WINAPI
JoyConfig8Impl_SendNotify(IDirectInputJoyConfig8
*iface
)
959 FIXME( "(%p): stub!\n", iface
);
963 static HRESULT WINAPI
JoyConfig8Impl_EnumTypes(IDirectInputJoyConfig8
*iface
, LPDIJOYTYPECALLBACK cb
, void *ref
)
965 FIXME( "(%p)->(%p, %p): stub!\n", iface
, cb
, ref
);
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
);
975 static HRESULT WINAPI
JoyConfig8Impl_SetTypeInfo(IDirectInputJoyConfig8
*iface
, LPCWSTR name
, LPCDIJOYTYPEINFO info
, DWORD flags
,
978 FIXME( "(%p)->(%s, %p, 0x%08x, %s): stub!\n", iface
, debugstr_w(name
), info
, flags
, debugstr_w(new_name
) );
982 static HRESULT WINAPI
JoyConfig8Impl_DeleteType(IDirectInputJoyConfig8
*iface
, LPCWSTR name
)
984 FIXME( "(%p)->(%s): stub!\n", iface
, debugstr_w(name
) );
988 static HRESULT WINAPI
JoyConfig8Impl_GetConfig(IDirectInputJoyConfig8
*iface
, UINT id
, LPDIJOYCONFIG info
, DWORD flags
)
990 IDirectInputImpl
*di
= impl_from_IDirectInputJoyConfig8(iface
);
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");
999 X(DIJC_REGHWCONFIGTYPE
)
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 */
1018 if (flags
& DIJC_GUIDINSTANCE
)
1019 info
->guidInstance
= dev
.guidInstance
;
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
);
1037 static HRESULT WINAPI
JoyConfig8Impl_DeleteConfig(IDirectInputJoyConfig8
*iface
, UINT id
)
1039 FIXME( "(%p)->(%d): stub!\n", iface
, id
);
1043 static HRESULT WINAPI
JoyConfig8Impl_GetUserValues(IDirectInputJoyConfig8
*iface
, LPDIJOYUSERVALUES info
, DWORD flags
)
1045 FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface
, info
, flags
);
1049 static HRESULT WINAPI
JoyConfig8Impl_SetUserValues(IDirectInputJoyConfig8
*iface
, LPCDIJOYUSERVALUES info
, DWORD flags
)
1051 FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface
, info
, flags
);
1055 static HRESULT WINAPI
JoyConfig8Impl_AddNewHardware(IDirectInputJoyConfig8
*iface
, HWND hwnd
, REFGUID guid
)
1057 FIXME( "(%p)->(%p, %s): stub!\n", iface
, hwnd
, debugstr_guid(guid
) );
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
);
1067 static HRESULT WINAPI
JoyConfig8Impl_OpenAppStatusKey(IDirectInputJoyConfig8
*iface
, PHKEY key
)
1069 FIXME( "(%p)->(%p): stub!\n", iface
, key
);
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
1128 /* IUnknown fields */
1129 IClassFactory IClassFactory_iface
;
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
);
1185 static const IClassFactoryVtbl DICF_Vtbl
= {
1186 DICF_QueryInterface
,
1189 DICF_CreateInstance
,
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
) ) {
1202 IClassFactory_AddRef((IClassFactory
*)*ppv
);
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
;
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
;
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
;
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
);
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
);
1312 if (kbd_hook
) UnhookWindowsHookEx( kbd_hook
);
1313 if (mouse_hook
) UnhookWindowsHookEx( mouse_hook
);
1314 kbd_hook
= mouse_hook
= NULL
;
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
);
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
);
1340 SetEvent(finished_event
);
1342 TranslateMessage(&msg
);
1343 DispatchMessageW(&msg
);
1346 DestroyWindow( di_em_win
);
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
;
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
;
1390 PostThreadMessageW(tid
, WM_USER
+0x10, 0, 0);
1391 wait_handle
= hook_thread
;
1395 LeaveCriticalSection(&dinput_hook_crit
);
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
)
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
)
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
;
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
);
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
);
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
)
1494 case DLL_PROCESS_ATTACH
:
1495 DisableThreadLibraryCalls(inst
);
1496 DINPUT_instance
= inst
;
1497 register_di_em_win_class();
1499 case DLL_PROCESS_DETACH
:
1500 if (reserved
) break;
1501 unregister_di_em_win_class();
1502 DeleteCriticalSection(&dinput_hook_crit
);