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
38 #define NONAMELESSUNION
50 #include "dinput_private.h"
51 #include "device_private.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(dinput
);
58 static const IDirectInput7WVtbl dinput7_vtbl
;
59 static const IDirectInput8WVtbl dinput8_vtbl
;
60 static const IDirectInputJoyConfig8Vtbl joy_config_vtbl
;
62 static inline struct dinput
*impl_from_IDirectInput7W( IDirectInput7W
*iface
)
64 return CONTAINING_RECORD( iface
, struct dinput
, IDirectInput7W_iface
);
67 static inline struct dinput
*impl_from_IDirectInput8W( IDirectInput8W
*iface
)
69 return CONTAINING_RECORD( iface
, struct dinput
, IDirectInput8W_iface
);
72 static inline struct dinput_device
*impl_from_IDirectInputDevice8W( IDirectInputDevice8W
*iface
)
74 return CONTAINING_RECORD( iface
, struct dinput_device
, IDirectInputDevice8W_iface
);
77 HINSTANCE DINPUT_instance
;
79 static HWND di_em_win
;
81 static HANDLE dinput_thread
;
82 static DWORD dinput_thread_id
;
84 static CRITICAL_SECTION dinput_hook_crit
;
85 static CRITICAL_SECTION_DEBUG dinput_critsect_debug
=
87 0, 0, &dinput_hook_crit
,
88 { &dinput_critsect_debug
.ProcessLocksList
, &dinput_critsect_debug
.ProcessLocksList
},
89 0, 0, { (DWORD_PTR
)(__FILE__
": dinput_hook_crit") }
91 static CRITICAL_SECTION dinput_hook_crit
= { &dinput_critsect_debug
, -1, 0, 0, 0, 0 };
93 static struct list acquired_mouse_list
= LIST_INIT( acquired_mouse_list
);
94 static struct list acquired_rawmouse_list
= LIST_INIT( acquired_rawmouse_list
);
95 static struct list acquired_keyboard_list
= LIST_INIT( acquired_keyboard_list
);
96 static struct list acquired_device_list
= LIST_INIT( acquired_device_list
);
98 static HRESULT
initialize_directinput_instance( struct dinput
*impl
, DWORD version
);
99 static void uninitialize_directinput_instance( struct dinput
*impl
);
101 void dinput_hooks_acquire_device( IDirectInputDevice8W
*iface
)
103 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
105 EnterCriticalSection( &dinput_hook_crit
);
106 if (IsEqualGUID( &impl
->guid
, &GUID_SysMouse
))
107 list_add_tail( impl
->use_raw_input
? &acquired_rawmouse_list
: &acquired_mouse_list
, &impl
->entry
);
108 else if (IsEqualGUID( &impl
->guid
, &GUID_SysKeyboard
))
109 list_add_tail( &acquired_keyboard_list
, &impl
->entry
);
111 list_add_tail( &acquired_device_list
, &impl
->entry
);
112 LeaveCriticalSection( &dinput_hook_crit
);
115 void dinput_hooks_unacquire_device( IDirectInputDevice8W
*iface
)
117 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
119 EnterCriticalSection( &dinput_hook_crit
);
120 list_remove( &impl
->entry
);
121 LeaveCriticalSection( &dinput_hook_crit
);
124 static void dinput_device_internal_unacquire( IDirectInputDevice8W
*iface
)
126 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
128 TRACE( "iface %p.\n", iface
);
130 EnterCriticalSection( &impl
->crit
);
131 if (impl
->status
== STATUS_ACQUIRED
)
133 impl
->vtbl
->unacquire( iface
);
134 impl
->status
= STATUS_UNACQUIRED
;
135 list_remove( &impl
->entry
);
137 LeaveCriticalSection( &impl
->crit
);
140 static HRESULT
dinput_create( IUnknown
**out
)
144 if (!(impl
= calloc( 1, sizeof(struct dinput
) ))) return E_OUTOFMEMORY
;
145 impl
->IDirectInput7A_iface
.lpVtbl
= &dinput7_a_vtbl
;
146 impl
->IDirectInput7W_iface
.lpVtbl
= &dinput7_vtbl
;
147 impl
->IDirectInput8A_iface
.lpVtbl
= &dinput8_a_vtbl
;
148 impl
->IDirectInput8W_iface
.lpVtbl
= &dinput8_vtbl
;
149 impl
->IDirectInputJoyConfig8_iface
.lpVtbl
= &joy_config_vtbl
;
152 #if DIRECTINPUT_VERSION == 0x0700
153 *out
= (IUnknown
*)&impl
->IDirectInput7W_iface
;
155 *out
= (IUnknown
*)&impl
->IDirectInput8W_iface
;
160 /******************************************************************************
161 * DirectInputCreateEx (DINPUT.@)
163 HRESULT WINAPI
DirectInputCreateEx( HINSTANCE hinst
, DWORD version
, REFIID iid
, void **out
, IUnknown
*outer
)
168 TRACE( "hinst %p, version %#lx, iid %s, out %p, outer %p.\n", hinst
, version
, debugstr_guid( iid
), out
, outer
);
170 if (!IsEqualGUID( &IID_IDirectInputA
, iid
) &&
171 !IsEqualGUID( &IID_IDirectInputW
, iid
) &&
172 !IsEqualGUID( &IID_IDirectInput2A
, iid
) &&
173 !IsEqualGUID( &IID_IDirectInput2W
, iid
) &&
174 !IsEqualGUID( &IID_IDirectInput7A
, iid
) &&
175 !IsEqualGUID( &IID_IDirectInput7W
, iid
))
176 return DIERR_NOINTERFACE
;
178 if (FAILED(hr
= dinput_create( &unknown
))) return hr
;
179 hr
= IUnknown_QueryInterface( unknown
, iid
, out
);
180 IUnknown_Release( unknown
);
181 if (FAILED(hr
)) return hr
;
183 if (outer
|| FAILED(hr
= IDirectInput7_Initialize( (IDirectInput7W
*)unknown
, hinst
, version
)))
185 IUnknown_Release( unknown
);
193 /******************************************************************************
194 * DirectInput8Create (DINPUT8.@)
196 HRESULT WINAPI DECLSPEC_HOTPATCH
DirectInput8Create( HINSTANCE hinst
, DWORD version
, REFIID iid
, void **out
, IUnknown
*outer
)
201 TRACE( "hinst %p, version %#lx, iid %s, out %p, outer %p.\n", hinst
, version
, debugstr_guid( iid
), out
, outer
);
203 if (!out
) return E_POINTER
;
205 if (!IsEqualGUID( &IID_IDirectInput8A
, iid
) &&
206 !IsEqualGUID( &IID_IDirectInput8W
, iid
) &&
207 !IsEqualGUID( &IID_IUnknown
, iid
))
210 return DIERR_NOINTERFACE
;
213 if (FAILED(hr
= dinput_create( &unknown
))) return hr
;
214 hr
= IUnknown_QueryInterface( unknown
, iid
, out
);
215 IUnknown_Release( unknown
);
216 if (FAILED(hr
)) return hr
;
218 if (outer
|| FAILED(hr
= IDirectInput8_Initialize( (IDirectInput8W
*)unknown
, hinst
, version
)))
220 IUnknown_Release( (IUnknown
*)unknown
);
228 /******************************************************************************
229 * DirectInputCreateA (DINPUT.@)
231 HRESULT WINAPI DECLSPEC_HOTPATCH
DirectInputCreateA( HINSTANCE hinst
, DWORD version
, IDirectInputA
**out
, IUnknown
*outer
)
233 return DirectInputCreateEx( hinst
, version
, &IID_IDirectInput7A
, (void **)out
, outer
);
236 /******************************************************************************
237 * DirectInputCreateW (DINPUT.@)
239 HRESULT WINAPI DECLSPEC_HOTPATCH
DirectInputCreateW( HINSTANCE hinst
, DWORD version
, IDirectInputW
**out
, IUnknown
*outer
)
241 return DirectInputCreateEx( hinst
, version
, &IID_IDirectInput7W
, (void **)out
, outer
);
244 static DWORD
diactionformat_priorityW( DIACTIONFORMATW
*action_format
, DWORD genre
)
247 DWORD priorityFlags
= 0;
249 /* If there's at least one action for the device it's priority 1 */
250 for (i
= 0; i
< action_format
->dwNumActions
; i
++)
251 if ((action_format
->rgoAction
[i
].dwSemantic
& genre
) == genre
)
252 priorityFlags
|= DIEDBS_MAPPEDPRI1
;
254 return priorityFlags
;
257 #if defined __i386__ && defined _MSC_VER
258 __declspec(naked
) BOOL
enum_callback_wrapper(void *callback
, const void *instance
, void *ref
)
271 #elif defined __i386__ && defined __GNUC__
272 extern BOOL
enum_callback_wrapper(void *callback
, const void *instance
, void *ref
);
273 __ASM_GLOBAL_FUNC( enum_callback_wrapper
,
275 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
276 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
278 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
283 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
284 __ASM_CFI(".cfi_same_value %ebp\n\t")
287 #define enum_callback_wrapper(callback, instance, ref) (callback)((instance), (ref))
290 /******************************************************************************
291 * IDirectInputW_EnumDevices
293 static HRESULT WINAPI
dinput7_EnumDevices( IDirectInput7W
*iface
, DWORD type
, LPDIENUMDEVICESCALLBACKW callback
,
294 void *context
, DWORD flags
)
296 struct dinput
*impl
= impl_from_IDirectInput7W( iface
);
298 TRACE( "iface %p, type %#lx, callback %p, context %p, flags %#lx.\n", iface
, type
, callback
, context
, flags
);
300 if (!callback
) return DIERR_INVALIDPARAM
;
302 if (type
> DIDEVTYPE_JOYSTICK
) return DIERR_INVALIDPARAM
;
303 if (flags
& ~(DIEDFL_ATTACHEDONLY
| DIEDFL_FORCEFEEDBACK
| DIEDFL_INCLUDEALIASES
| DIEDFL_INCLUDEPHANTOMS
))
304 return DIERR_INVALIDPARAM
;
306 return IDirectInput8_EnumDevices( &impl
->IDirectInput8W_iface
, type
, callback
, context
, flags
);
309 static ULONG WINAPI
dinput7_AddRef( IDirectInput7W
*iface
)
311 struct dinput
*impl
= impl_from_IDirectInput7W( iface
);
312 ULONG ref
= InterlockedIncrement( &impl
->ref
);
313 TRACE( "iface %p increasing refcount to %lu.\n", iface
, ref
);
317 static ULONG WINAPI
dinput7_Release( IDirectInput7W
*iface
)
319 struct dinput
*impl
= impl_from_IDirectInput7W( iface
);
320 ULONG ref
= InterlockedDecrement( &impl
->ref
);
322 TRACE( "iface %p decreasing refcount to %lu.\n", iface
, ref
);
326 uninitialize_directinput_instance( impl
);
333 static HRESULT WINAPI
dinput7_QueryInterface( IDirectInput7W
*iface
, REFIID iid
, void **out
)
335 struct dinput
*impl
= impl_from_IDirectInput7W( iface
);
337 TRACE( "iface %p, iid %s, out %p.\n", iface
, debugstr_guid( iid
), out
);
339 if (!iid
|| !out
) return E_POINTER
;
343 #if DIRECTINPUT_VERSION == 0x0700
344 if (IsEqualGUID( &IID_IDirectInputA
, iid
) ||
345 IsEqualGUID( &IID_IDirectInput2A
, iid
) ||
346 IsEqualGUID( &IID_IDirectInput7A
, iid
))
347 *out
= &impl
->IDirectInput7A_iface
;
348 else if (IsEqualGUID( &IID_IUnknown
, iid
) ||
349 IsEqualGUID( &IID_IDirectInputW
, iid
) ||
350 IsEqualGUID( &IID_IDirectInput2W
, iid
) ||
351 IsEqualGUID( &IID_IDirectInput7W
, iid
))
352 *out
= &impl
->IDirectInput7W_iface
;
355 if (IsEqualGUID( &IID_IDirectInput8A
, iid
))
356 *out
= &impl
->IDirectInput8A_iface
;
357 else if (IsEqualGUID( &IID_IUnknown
, iid
) ||
358 IsEqualGUID( &IID_IDirectInput8W
, iid
))
359 *out
= &impl
->IDirectInput8W_iface
;
363 if (IsEqualGUID( &IID_IDirectInputJoyConfig8
, iid
))
364 *out
= &impl
->IDirectInputJoyConfig8_iface
;
368 IUnknown_AddRef( (IUnknown
*)*out
);
372 WARN( "Unsupported interface: %s\n", debugstr_guid( iid
) );
373 return E_NOINTERFACE
;
376 static LRESULT WINAPI
di_em_win_wndproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
378 struct dinput_device
*impl
;
380 UINT size
= sizeof(ri
);
381 int rim
= GET_RAWINPUT_CODE_WPARAM( wparam
);
383 TRACE( "%p %d %Ix %Ix\n", hwnd
, msg
, wparam
, lparam
);
385 if (msg
== WM_INPUT
&& (rim
== RIM_INPUT
|| rim
== RIM_INPUTSINK
))
387 size
= GetRawInputData( (HRAWINPUT
)lparam
, RID_INPUT
, &ri
, &size
, sizeof(RAWINPUTHEADER
) );
388 if (size
== (UINT
)-1 || size
< sizeof(RAWINPUTHEADER
))
389 WARN( "Unable to read raw input data\n" );
390 else if (ri
.header
.dwType
== RIM_TYPEMOUSE
)
392 EnterCriticalSection( &dinput_hook_crit
);
393 LIST_FOR_EACH_ENTRY( impl
, &acquired_rawmouse_list
, struct dinput_device
, entry
)
394 dinput_mouse_rawinput_hook( &impl
->IDirectInputDevice8W_iface
, wparam
, lparam
, &ri
);
395 LeaveCriticalSection( &dinput_hook_crit
);
399 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
402 static void register_di_em_win_class(void)
406 memset(&class, 0, sizeof(class));
407 class.cbSize
= sizeof(class);
408 class.lpfnWndProc
= di_em_win_wndproc
;
409 class.hInstance
= DINPUT_instance
;
410 class.lpszClassName
= L
"DIEmWin";
412 if (!RegisterClassExW( &class ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS
)
413 WARN( "Unable to register message window class\n" );
416 static void unregister_di_em_win_class(void)
418 if (!UnregisterClassW( L
"DIEmWin", NULL
) && GetLastError() != ERROR_CLASS_DOES_NOT_EXIST
)
419 WARN( "Unable to unregister message window class\n" );
422 static HRESULT
initialize_directinput_instance( struct dinput
*impl
, DWORD version
)
424 if (!impl
->initialized
)
426 impl
->dwVersion
= version
;
427 impl
->evsequence
= 1;
429 list_init( &impl
->device_players
);
431 impl
->initialized
= TRUE
;
437 static void uninitialize_directinput_instance( struct dinput
*impl
)
439 if (impl
->initialized
)
441 struct DevicePlayer
*device_player
, *device_player2
;
443 LIST_FOR_EACH_ENTRY_SAFE ( device_player
, device_player2
, &impl
->device_players
, struct DevicePlayer
, entry
)
444 free( device_player
);
446 impl
->initialized
= FALSE
;
450 enum directinput_versions
452 DIRECTINPUT_VERSION_300
= 0x0300,
453 DIRECTINPUT_VERSION_500
= 0x0500,
454 DIRECTINPUT_VERSION_50A
= 0x050A,
455 DIRECTINPUT_VERSION_5B2
= 0x05B2,
456 DIRECTINPUT_VERSION_602
= 0x0602,
457 DIRECTINPUT_VERSION_61A
= 0x061A,
458 DIRECTINPUT_VERSION_700
= 0x0700,
461 static HRESULT WINAPI
dinput7_Initialize( IDirectInput7W
*iface
, HINSTANCE hinst
, DWORD version
)
463 struct dinput
*impl
= impl_from_IDirectInput7W( iface
);
465 TRACE( "iface %p, hinst %p, version %#lx.\n", iface
, hinst
, version
);
468 return DIERR_INVALIDPARAM
;
469 else if (version
== 0)
470 return DIERR_NOTINITIALIZED
;
471 else if (version
> DIRECTINPUT_VERSION_700
)
472 return DIERR_OLDDIRECTINPUTVERSION
;
473 else if (version
!= DIRECTINPUT_VERSION_300
&& version
!= DIRECTINPUT_VERSION_500
&&
474 version
!= DIRECTINPUT_VERSION_50A
&& version
!= DIRECTINPUT_VERSION_5B2
&&
475 version
!= DIRECTINPUT_VERSION_602
&& version
!= DIRECTINPUT_VERSION_61A
&&
476 version
!= DIRECTINPUT_VERSION_700
&& version
!= DIRECTINPUT_VERSION
)
477 return DIERR_BETADIRECTINPUTVERSION
;
479 return initialize_directinput_instance( impl
, version
);
482 static HRESULT WINAPI
dinput7_GetDeviceStatus( IDirectInput7W
*iface
, const GUID
*guid
)
484 struct dinput
*impl
= impl_from_IDirectInput7W( iface
);
486 IDirectInputDeviceW
*device
;
488 TRACE( "iface %p, guid %s.\n", iface
, debugstr_guid( guid
) );
490 if (!guid
) return E_POINTER
;
491 if (!impl
->initialized
) return DIERR_NOTINITIALIZED
;
493 hr
= IDirectInput_CreateDevice( iface
, guid
, &device
, NULL
);
494 if (hr
!= DI_OK
) return DI_NOTATTACHED
;
496 IUnknown_Release( device
);
501 static HRESULT WINAPI
dinput7_RunControlPanel( IDirectInput7W
*iface
, HWND owner
, DWORD flags
)
503 struct dinput
*impl
= impl_from_IDirectInput7W( iface
);
504 WCHAR control_exe
[] = {L
"control.exe"};
505 STARTUPINFOW si
= {0};
506 PROCESS_INFORMATION pi
;
508 TRACE( "iface %p, owner %p, flags %#lx.\n", iface
, owner
, flags
);
510 if (owner
&& !IsWindow( owner
)) return E_HANDLE
;
511 if (flags
) return DIERR_INVALIDPARAM
;
512 if (!impl
->initialized
) return DIERR_NOTINITIALIZED
;
514 if (!CreateProcessW( NULL
, control_exe
, NULL
, NULL
, FALSE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
))
515 return HRESULT_FROM_WIN32(GetLastError());
520 static HRESULT WINAPI
dinput7_FindDevice( IDirectInput7W
*iface
, const GUID
*guid
, const WCHAR
*name
, GUID
*instance_guid
)
522 FIXME( "iface %p, guid %s, name %s, instance_guid %s stub!\n", iface
, debugstr_guid( guid
),
523 debugstr_w(name
), debugstr_guid( instance_guid
) );
527 static HRESULT WINAPI
dinput7_CreateDeviceEx( IDirectInput7W
*iface
, const GUID
*guid
,
528 REFIID iid
, void **out
, IUnknown
*outer
)
530 struct dinput
*impl
= impl_from_IDirectInput7W( iface
);
531 IDirectInputDevice8W
*device
;
534 TRACE( "iface %p, guid %s, iid %s, out %p, outer %p.\n", iface
, debugstr_guid( guid
),
535 debugstr_guid( iid
), out
, outer
);
537 if (!out
) return E_POINTER
;
540 if (!guid
) return E_POINTER
;
541 if (!impl
->initialized
) return DIERR_NOTINITIALIZED
;
543 if (IsEqualGUID( &GUID_SysKeyboard
, guid
)) hr
= keyboard_create_device( impl
, guid
, &device
);
544 else if (IsEqualGUID( &GUID_SysMouse
, guid
)) hr
= mouse_create_device( impl
, guid
, &device
);
545 else hr
= hid_joystick_create_device( impl
, guid
, &device
);
547 if (FAILED(hr
)) return hr
;
549 if (FAILED(hr
= dinput_device_init_device_format( device
)))
551 IDirectInputDevice8_Release( device
);
555 hr
= IDirectInputDevice8_QueryInterface( device
, iid
, out
);
556 IDirectInputDevice8_Release( device
);
560 static HRESULT WINAPI
dinput7_CreateDevice( IDirectInput7W
*iface
, const GUID
*guid
,
561 IDirectInputDeviceW
**out
, IUnknown
*outer
)
563 return IDirectInput7_CreateDeviceEx( iface
, guid
, &IID_IDirectInputDeviceW
, (void **)out
, outer
);
566 /*******************************************************************************
570 static ULONG WINAPI
dinput8_AddRef( IDirectInput8W
*iface
)
572 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
573 return IDirectInput7_AddRef( &impl
->IDirectInput7W_iface
);
576 static HRESULT WINAPI
dinput8_QueryInterface( IDirectInput8W
*iface
, REFIID iid
, void **out
)
578 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
579 return IDirectInput7_QueryInterface( &impl
->IDirectInput7W_iface
, iid
, out
);
582 static ULONG WINAPI
dinput8_Release( IDirectInput8W
*iface
)
584 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
585 return IDirectInput7_Release( &impl
->IDirectInput7W_iface
);
588 static HRESULT WINAPI
dinput8_CreateDevice( IDirectInput8W
*iface
, const GUID
*guid
,
589 IDirectInputDevice8W
**out
, IUnknown
*outer
)
591 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
592 return IDirectInput7_CreateDeviceEx( &impl
->IDirectInput7W_iface
, guid
,
593 &IID_IDirectInputDevice8W
, (void **)out
, outer
);
596 static BOOL
try_enum_device( DWORD type
, LPDIENUMDEVICESCALLBACKW callback
,
597 DIDEVICEINSTANCEW
*instance
, void *context
, DWORD flags
)
599 if (type
&& (instance
->dwDevType
& 0xff) != type
) return DIENUM_CONTINUE
;
600 if ((flags
& DIEDFL_FORCEFEEDBACK
) && IsEqualGUID( &instance
->guidFFDriver
, &GUID_NULL
))
601 return DIENUM_CONTINUE
;
602 return enum_callback_wrapper( callback
, instance
, context
);
605 static HRESULT WINAPI
dinput8_EnumDevices( IDirectInput8W
*iface
, DWORD type
, LPDIENUMDEVICESCALLBACKW callback
, void *context
,
608 DIDEVICEINSTANCEW instance
= {.dwSize
= sizeof(DIDEVICEINSTANCEW
)};
609 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
610 DWORD device_class
= 0, device_type
= 0;
614 TRACE( "iface %p, type %#lx, callback %p, context %p, flags %#lx.\n", iface
, type
, callback
, context
, flags
);
616 if (!callback
) return DIERR_INVALIDPARAM
;
618 if ((type
> DI8DEVCLASS_GAMECTRL
&& type
< DI8DEVTYPE_DEVICE
) || type
> DI8DEVTYPE_SUPPLEMENTAL
)
619 return DIERR_INVALIDPARAM
;
620 if (flags
& ~(DIEDFL_ATTACHEDONLY
| DIEDFL_FORCEFEEDBACK
| DIEDFL_INCLUDEALIASES
|
621 DIEDFL_INCLUDEPHANTOMS
| DIEDFL_INCLUDEHIDDEN
))
622 return DIERR_INVALIDPARAM
;
624 if (!impl
->initialized
) return DIERR_NOTINITIALIZED
;
626 if (type
<= DI8DEVCLASS_GAMECTRL
) device_class
= type
;
627 else device_type
= type
;
629 if (device_class
== DI8DEVCLASS_ALL
|| device_class
== DI8DEVCLASS_POINTER
)
631 hr
= mouse_enum_device( type
, flags
, &instance
, impl
->dwVersion
);
632 if (hr
== DI_OK
&& try_enum_device( device_type
, callback
, &instance
, context
, flags
) == DIENUM_STOP
)
636 if (device_class
== DI8DEVCLASS_ALL
|| device_class
== DI8DEVCLASS_KEYBOARD
)
638 hr
= keyboard_enum_device( type
, flags
, &instance
, impl
->dwVersion
);
639 if (hr
== DI_OK
&& try_enum_device( device_type
, callback
, &instance
, context
, flags
) == DIENUM_STOP
)
643 if (device_class
== DI8DEVCLASS_ALL
|| device_class
== DI8DEVCLASS_GAMECTRL
)
647 hr
= hid_joystick_enum_device( type
, flags
, &instance
, impl
->dwVersion
, i
++ );
648 if (hr
== DI_OK
&& try_enum_device( device_type
, callback
, &instance
, context
, flags
) == DIENUM_STOP
)
650 } while (SUCCEEDED(hr
));
656 static HRESULT WINAPI
dinput8_GetDeviceStatus( IDirectInput8W
*iface
, const GUID
*guid
)
658 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
659 return IDirectInput7_GetDeviceStatus( &impl
->IDirectInput7W_iface
, guid
);
662 static HRESULT WINAPI
dinput8_RunControlPanel( IDirectInput8W
*iface
, HWND owner
, DWORD flags
)
664 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
665 return IDirectInput7_RunControlPanel( &impl
->IDirectInput7W_iface
, owner
, flags
);
668 static HRESULT WINAPI
dinput8_Initialize( IDirectInput8W
*iface
, HINSTANCE hinst
, DWORD version
)
670 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
672 TRACE( "iface %p, hinst %p, version %#lx.\n", iface
, hinst
, version
);
675 return DIERR_INVALIDPARAM
;
676 else if (version
== 0)
677 return DIERR_NOTINITIALIZED
;
678 else if (version
< DIRECTINPUT_VERSION
)
679 return DIERR_BETADIRECTINPUTVERSION
;
680 else if (version
> DIRECTINPUT_VERSION
)
681 return DIERR_OLDDIRECTINPUTVERSION
;
683 return initialize_directinput_instance( impl
, version
);
686 static HRESULT WINAPI
dinput8_FindDevice( IDirectInput8W
*iface
, const GUID
*guid
, const WCHAR
*name
, GUID
*instance_guid
)
688 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
689 return IDirectInput7_FindDevice( &impl
->IDirectInput7W_iface
, guid
, name
, instance_guid
);
692 static BOOL
should_enumerate_device( const WCHAR
*username
, DWORD flags
, struct list
*device_players
, const GUID
*guid
)
694 BOOL should_enumerate
= TRUE
;
695 struct DevicePlayer
*device_player
;
697 /* Check if user owns impl device */
698 if (flags
& DIEDBSFL_THISUSER
&& username
&& *username
)
700 should_enumerate
= FALSE
;
701 LIST_FOR_EACH_ENTRY(device_player
, device_players
, struct DevicePlayer
, entry
)
703 if (IsEqualGUID(&device_player
->instance_guid
, guid
))
705 if (*device_player
->username
&& !wcscmp( username
, device_player
->username
))
706 return TRUE
; /* Device username matches */
712 /* Check if impl device is not owned by anyone */
713 if (flags
& DIEDBSFL_AVAILABLEDEVICES
)
716 should_enumerate
= FALSE
;
717 LIST_FOR_EACH_ENTRY(device_player
, device_players
, struct DevicePlayer
, entry
)
719 if (IsEqualGUID(&device_player
->instance_guid
, guid
))
721 if (*device_player
->username
)
727 return TRUE
; /* Device does not have a username */
730 return should_enumerate
;
733 struct enum_device_by_semantics_params
735 IDirectInput8W
*iface
;
736 const WCHAR
*username
;
739 DIDEVICEINSTANCEW
*instances
;
740 DWORD instance_count
;
743 static BOOL CALLBACK
enum_device_by_semantics( const DIDEVICEINSTANCEW
*instance
, void *context
)
745 struct enum_device_by_semantics_params
*params
= context
;
746 struct dinput
*impl
= impl_from_IDirectInput8W( params
->iface
);
748 if (should_enumerate_device( params
->username
, params
->flags
, &impl
->device_players
, &instance
->guidInstance
))
750 params
->instance_count
++;
751 params
->instances
= realloc( params
->instances
, sizeof(DIDEVICEINSTANCEW
) * params
->instance_count
);
752 params
->instances
[params
->instance_count
- 1] = *instance
;
755 return DIENUM_CONTINUE
;
758 static HRESULT WINAPI
dinput8_EnumDevicesBySemantics( IDirectInput8W
*iface
, const WCHAR
*username
, DIACTIONFORMATW
*action_format
,
759 LPDIENUMDEVICESBYSEMANTICSCBW callback
, void *context
, DWORD flags
)
761 struct enum_device_by_semantics_params params
= {.iface
= iface
, .username
= username
, .flags
= flags
};
762 DWORD callbackFlags
, enum_flags
= DIEDFL_ATTACHEDONLY
| (flags
& DIEDFL_FORCEFEEDBACK
);
763 static const GUID
*guids
[2] = {&GUID_SysKeyboard
, &GUID_SysMouse
};
764 static const DWORD actionMasks
[] = { DIKEYBOARD_MASK
, DIMOUSE_MASK
};
765 struct dinput
*impl
= impl_from_IDirectInput8W( iface
);
766 DIDEVICEINSTANCEW didevi
;
767 IDirectInputDevice8W
*lpdid
;
772 FIXME( "iface %p, username %s, action_format %p, callback %p, context %p, flags %#lx stub!\n",
773 iface
, debugstr_w(username
), action_format
, callback
, context
, flags
);
775 didevi
.dwSize
= sizeof(didevi
);
777 hr
= IDirectInput8_EnumDevices( &impl
->IDirectInput8W_iface
, DI8DEVCLASS_GAMECTRL
,
778 enum_device_by_semantics
, ¶ms
, enum_flags
);
781 free( params
.instances
);
785 remain
= params
.instance_count
;
786 /* Add keyboard and mouse to remaining device count */
787 if (!(flags
& DIEDBSFL_FORCEFEEDBACK
))
789 for (i
= 0; i
< ARRAY_SIZE(guids
); i
++)
791 if (should_enumerate_device( username
, flags
, &impl
->device_players
, guids
[i
] )) remain
++;
795 for (i
= 0; i
< params
.instance_count
; i
++)
797 callbackFlags
= diactionformat_priorityW( action_format
, action_format
->dwGenre
);
798 IDirectInput_CreateDevice( iface
, ¶ms
.instances
[i
].guidInstance
, &lpdid
, NULL
);
800 if (callback( ¶ms
.instances
[i
], lpdid
, callbackFlags
, --remain
, context
) == DIENUM_STOP
)
802 free( params
.instances
);
803 IDirectInputDevice_Release(lpdid
);
806 IDirectInputDevice_Release(lpdid
);
809 free( params
.instances
);
811 if (flags
& DIEDBSFL_FORCEFEEDBACK
) return DI_OK
;
813 /* Enumerate keyboard and mouse */
814 for (i
= 0; i
< ARRAY_SIZE(guids
); i
++)
816 if (should_enumerate_device( username
, flags
, &impl
->device_players
, guids
[i
] ))
818 callbackFlags
= diactionformat_priorityW( action_format
, actionMasks
[i
] );
820 IDirectInput_CreateDevice(iface
, guids
[i
], &lpdid
, NULL
);
821 IDirectInputDevice_GetDeviceInfo(lpdid
, &didevi
);
823 if (callback( &didevi
, lpdid
, callbackFlags
, --remain
, context
) == DIENUM_STOP
)
825 IDirectInputDevice_Release(lpdid
);
828 IDirectInputDevice_Release(lpdid
);
835 static HRESULT WINAPI
dinput8_ConfigureDevices( IDirectInput8W
*iface
, LPDICONFIGUREDEVICESCALLBACK callback
,
836 DICONFIGUREDEVICESPARAMSW
*params
, DWORD flags
, void *context
)
838 FIXME( "iface %p, callback %p, params %p, flags %#lx, context %p stub!\n", iface
, callback
,
839 params
, flags
, context
);
841 /* Call helper function in config.c to do the real work */
842 return _configure_devices( iface
, callback
, params
, flags
, context
);
845 /*****************************************************************************
846 * IDirectInputJoyConfig8 interface
849 static inline struct dinput
*impl_from_IDirectInputJoyConfig8( IDirectInputJoyConfig8
*iface
)
851 return CONTAINING_RECORD( iface
, struct dinput
, IDirectInputJoyConfig8_iface
);
854 static HRESULT WINAPI
joy_config_QueryInterface( IDirectInputJoyConfig8
*iface
, REFIID iid
, void **out
)
856 struct dinput
*impl
= impl_from_IDirectInputJoyConfig8( iface
);
857 return IDirectInput7_QueryInterface( &impl
->IDirectInput7W_iface
, iid
, out
);
860 static ULONG WINAPI
joy_config_AddRef( IDirectInputJoyConfig8
*iface
)
862 struct dinput
*impl
= impl_from_IDirectInputJoyConfig8( iface
);
863 return IDirectInput7_AddRef( &impl
->IDirectInput7W_iface
);
866 static ULONG WINAPI
joy_config_Release( IDirectInputJoyConfig8
*iface
)
868 struct dinput
*impl
= impl_from_IDirectInputJoyConfig8( iface
);
869 return IDirectInput7_Release( &impl
->IDirectInput7W_iface
);
872 static HRESULT WINAPI
joy_config_Acquire( IDirectInputJoyConfig8
*iface
)
874 FIXME( "iface %p stub!\n", iface
);
878 static HRESULT WINAPI
joy_config_Unacquire( IDirectInputJoyConfig8
*iface
)
880 FIXME( "iface %p stub!\n", iface
);
884 static HRESULT WINAPI
joy_config_SetCooperativeLevel( IDirectInputJoyConfig8
*iface
, HWND hwnd
, DWORD flags
)
886 FIXME( "iface %p, hwnd %p, flags %#lx stub!\n", iface
, hwnd
, flags
);
890 static HRESULT WINAPI
joy_config_SendNotify( IDirectInputJoyConfig8
*iface
)
892 FIXME( "iface %p stub!\n", iface
);
896 static HRESULT WINAPI
joy_config_EnumTypes( IDirectInputJoyConfig8
*iface
, LPDIJOYTYPECALLBACK callback
, void *context
)
898 FIXME( "iface %p, callback %p, context %p stub!\n", iface
, callback
, context
);
902 static HRESULT WINAPI
joy_config_GetTypeInfo( IDirectInputJoyConfig8
*iface
, const WCHAR
*name
,
903 DIJOYTYPEINFO
*info
, DWORD flags
)
905 FIXME( "iface %p, name %s, info %p, flags %#lx stub!\n", iface
, debugstr_w(name
), info
, flags
);
909 static HRESULT WINAPI
joy_config_SetTypeInfo( IDirectInputJoyConfig8
*iface
, const WCHAR
*name
,
910 const DIJOYTYPEINFO
*info
, DWORD flags
, WCHAR
*new_name
)
912 FIXME( "iface %p, name %s, info %p, flags %#lx, new_name %s stub!\n",
913 iface
, debugstr_w(name
), info
, flags
, debugstr_w(new_name
) );
917 static HRESULT WINAPI
joy_config_DeleteType( IDirectInputJoyConfig8
*iface
, const WCHAR
*name
)
919 FIXME( "iface %p, name %s stub!\n", iface
, debugstr_w(name
) );
923 struct find_device_from_index_params
926 DIDEVICEINSTANCEW instance
;
929 static BOOL CALLBACK
find_device_from_index( const DIDEVICEINSTANCEW
*instance
, void *context
)
931 struct find_device_from_index_params
*params
= context
;
932 params
->instance
= *instance
;
933 if (!params
->index
--) return DIENUM_STOP
;
934 return DIENUM_CONTINUE
;
937 static HRESULT WINAPI
joy_config_GetConfig( IDirectInputJoyConfig8
*iface
, UINT id
, DIJOYCONFIG
*info
, DWORD flags
)
939 struct dinput
*impl
= impl_from_IDirectInputJoyConfig8( iface
);
940 struct find_device_from_index_params params
= {.index
= id
};
943 FIXME( "iface %p, id %u, info %p, flags %#lx stub!\n", iface
, id
, info
, flags
);
945 #define X(x) if (flags & x) FIXME("\tflags |= "#x"\n");
947 X(DIJC_REGHWCONFIGTYPE
)
952 hr
= IDirectInput8_EnumDevices( &impl
->IDirectInput8W_iface
, DI8DEVCLASS_GAMECTRL
,
953 find_device_from_index
, ¶ms
, 0 );
954 if (FAILED(hr
)) return hr
;
955 if (params
.index
!= ~0) return DIERR_NOMOREITEMS
;
956 if (flags
& DIJC_GUIDINSTANCE
) info
->guidInstance
= params
.instance
.guidInstance
;
960 static HRESULT WINAPI
joy_config_SetConfig( IDirectInputJoyConfig8
*iface
, UINT id
, const DIJOYCONFIG
*info
, DWORD flags
)
962 FIXME( "iface %p, id %u, info %p, flags %#lx stub!\n", iface
, id
, info
, flags
);
966 static HRESULT WINAPI
joy_config_DeleteConfig( IDirectInputJoyConfig8
*iface
, UINT id
)
968 FIXME( "iface %p, id %u stub!\n", iface
, id
);
972 static HRESULT WINAPI
joy_config_GetUserValues( IDirectInputJoyConfig8
*iface
, DIJOYUSERVALUES
*info
, DWORD flags
)
974 FIXME( "iface %p, info %p, flags %#lx stub!\n", iface
, info
, flags
);
978 static HRESULT WINAPI
joy_config_SetUserValues( IDirectInputJoyConfig8
*iface
, const DIJOYUSERVALUES
*info
, DWORD flags
)
980 FIXME( "iface %p, info %p, flags %#lx stub!\n", iface
, info
, flags
);
984 static HRESULT WINAPI
joy_config_AddNewHardware( IDirectInputJoyConfig8
*iface
, HWND hwnd
, const GUID
*guid
)
986 FIXME( "iface %p, hwnd %p, guid %s stub!\n", iface
, hwnd
, debugstr_guid( guid
) );
990 static HRESULT WINAPI
joy_config_OpenTypeKey( IDirectInputJoyConfig8
*iface
, const WCHAR
*name
, DWORD security
, HKEY
*key
)
992 FIXME( "iface %p, name %s, security %lu, key %p stub!\n", iface
, debugstr_w(name
), security
, key
);
996 static HRESULT WINAPI
joy_config_OpenAppStatusKey( IDirectInputJoyConfig8
*iface
, HKEY
*key
)
998 FIXME( "iface %p, key %p stub!\n", iface
, key
);
1002 static const IDirectInput7WVtbl dinput7_vtbl
=
1004 dinput7_QueryInterface
,
1007 dinput7_CreateDevice
,
1008 dinput7_EnumDevices
,
1009 dinput7_GetDeviceStatus
,
1010 dinput7_RunControlPanel
,
1013 dinput7_CreateDeviceEx
,
1016 static const IDirectInput8WVtbl dinput8_vtbl
=
1018 dinput8_QueryInterface
,
1021 dinput8_CreateDevice
,
1022 dinput8_EnumDevices
,
1023 dinput8_GetDeviceStatus
,
1024 dinput8_RunControlPanel
,
1027 dinput8_EnumDevicesBySemantics
,
1028 dinput8_ConfigureDevices
,
1031 static const IDirectInputJoyConfig8Vtbl joy_config_vtbl
=
1033 joy_config_QueryInterface
,
1037 joy_config_Unacquire
,
1038 joy_config_SetCooperativeLevel
,
1039 joy_config_SendNotify
,
1040 joy_config_EnumTypes
,
1041 joy_config_GetTypeInfo
,
1042 joy_config_SetTypeInfo
,
1043 joy_config_DeleteType
,
1044 joy_config_GetConfig
,
1045 joy_config_SetConfig
,
1046 joy_config_DeleteConfig
,
1047 joy_config_GetUserValues
,
1048 joy_config_SetUserValues
,
1049 joy_config_AddNewHardware
,
1050 joy_config_OpenTypeKey
,
1051 joy_config_OpenAppStatusKey
,
1054 struct class_factory
1056 IClassFactory IClassFactory_iface
;
1059 static inline struct class_factory
*impl_from_IClassFactory( IClassFactory
*iface
)
1061 return CONTAINING_RECORD( iface
, struct class_factory
, IClassFactory_iface
);
1064 static HRESULT WINAPI
class_factory_QueryInterface( IClassFactory
*iface
, REFIID iid
, void **out
)
1066 struct class_factory
*impl
= impl_from_IClassFactory(iface
);
1068 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
1070 if (IsEqualGUID(iid
, &IID_IUnknown
) ||
1071 IsEqualGUID(iid
, &IID_IClassFactory
))
1072 *out
= &impl
->IClassFactory_iface
;
1076 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
1077 return E_NOINTERFACE
;
1080 IUnknown_AddRef((IUnknown
*)*out
);
1084 static ULONG WINAPI
class_factory_AddRef( IClassFactory
*iface
)
1089 static ULONG WINAPI
class_factory_Release( IClassFactory
*iface
)
1094 static HRESULT WINAPI
class_factory_CreateInstance( IClassFactory
*iface
, IUnknown
*outer
, REFIID iid
, void **out
)
1099 TRACE( "iface %p, outer %p, iid %s, out %p.\n", iface
, outer
, debugstr_guid( iid
), out
);
1101 if (outer
) return CLASS_E_NOAGGREGATION
;
1103 if (FAILED(hr
= dinput_create( &unknown
))) return hr
;
1104 hr
= IUnknown_QueryInterface( unknown
, iid
, out
);
1105 IUnknown_Release( unknown
);
1110 static HRESULT WINAPI
class_factory_LockServer( IClassFactory
*iface
, BOOL lock
)
1112 FIXME( "iface %p, lock %d stub!\n", iface
, lock
);
1116 static const IClassFactoryVtbl class_factory_vtbl
=
1118 class_factory_QueryInterface
,
1119 class_factory_AddRef
,
1120 class_factory_Release
,
1121 class_factory_CreateInstance
,
1122 class_factory_LockServer
,
1125 static struct class_factory class_factory
= {{&class_factory_vtbl
}};
1127 /***********************************************************************
1128 * DllGetClassObject (DINPUT.@)
1130 HRESULT WINAPI
DllGetClassObject( REFCLSID clsid
, REFIID iid
, void **out
)
1132 TRACE( "clsid %s, iid %s, out %p.\n", debugstr_guid( clsid
), debugstr_guid( iid
), out
);
1134 #if DIRECTINPUT_VERSION == 0x0700
1135 if (IsEqualCLSID( &CLSID_DirectInput
, clsid
))
1136 return IClassFactory_QueryInterface( &class_factory
.IClassFactory_iface
, iid
, out
);
1138 if (IsEqualCLSID( &CLSID_DirectInput8
, clsid
))
1139 return IClassFactory_QueryInterface( &class_factory
.IClassFactory_iface
, iid
, out
);
1142 WARN( "%s not implemented, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid( clsid
) );
1143 return CLASS_E_CLASSNOTAVAILABLE
;
1146 /******************************************************************************
1147 * DInput hook thread
1150 static LRESULT CALLBACK
LL_hook_proc( int code
, WPARAM wparam
, LPARAM lparam
)
1152 struct dinput_device
*impl
;
1155 if (code
!= HC_ACTION
) return CallNextHookEx( 0, code
, wparam
, lparam
);
1157 EnterCriticalSection( &dinput_hook_crit
);
1158 LIST_FOR_EACH_ENTRY( impl
, &acquired_mouse_list
, struct dinput_device
, entry
)
1160 TRACE( "calling dinput_mouse_hook (%p %Ix %Ix)\n", impl
, wparam
, lparam
);
1161 skip
|= dinput_mouse_hook( &impl
->IDirectInputDevice8W_iface
, wparam
, lparam
);
1163 LIST_FOR_EACH_ENTRY( impl
, &acquired_keyboard_list
, struct dinput_device
, entry
)
1165 if (impl
->use_raw_input
) continue;
1166 TRACE( "calling dinput_keyboard_hook (%p %Ix %Ix)\n", impl
, wparam
, lparam
);
1167 skip
|= dinput_keyboard_hook( &impl
->IDirectInputDevice8W_iface
, wparam
, lparam
);
1169 LeaveCriticalSection( &dinput_hook_crit
);
1171 return skip
? 1 : CallNextHookEx( 0, code
, wparam
, lparam
);
1174 static LRESULT CALLBACK
callwndproc_proc( int code
, WPARAM wparam
, LPARAM lparam
)
1176 struct dinput_device
*impl
, *next
;
1177 CWPSTRUCT
*msg
= (CWPSTRUCT
*)lparam
;
1180 if (code
!= HC_ACTION
|| (msg
->message
!= WM_KILLFOCUS
&&
1181 msg
->message
!= WM_ACTIVATEAPP
&& msg
->message
!= WM_ACTIVATE
))
1182 return CallNextHookEx( 0, code
, wparam
, lparam
);
1184 foreground
= GetForegroundWindow();
1186 EnterCriticalSection( &dinput_hook_crit
);
1187 LIST_FOR_EACH_ENTRY_SAFE( impl
, next
, &acquired_device_list
, struct dinput_device
, entry
)
1189 if (msg
->hwnd
== impl
->win
&& msg
->hwnd
!= foreground
)
1191 TRACE( "%p window is not foreground - unacquiring %p\n", impl
->win
, impl
);
1192 dinput_device_internal_unacquire( &impl
->IDirectInputDevice8W_iface
);
1195 LIST_FOR_EACH_ENTRY_SAFE( impl
, next
, &acquired_mouse_list
, struct dinput_device
, entry
)
1197 if (msg
->hwnd
== impl
->win
&& msg
->hwnd
!= foreground
)
1199 TRACE( "%p window is not foreground - unacquiring %p\n", impl
->win
, impl
);
1200 dinput_device_internal_unacquire( &impl
->IDirectInputDevice8W_iface
);
1203 LIST_FOR_EACH_ENTRY_SAFE( impl
, next
, &acquired_rawmouse_list
, struct dinput_device
, entry
)
1205 if (msg
->hwnd
== impl
->win
&& msg
->hwnd
!= foreground
)
1207 TRACE( "%p window is not foreground - unacquiring %p\n", impl
->win
, impl
);
1208 dinput_device_internal_unacquire( &impl
->IDirectInputDevice8W_iface
);
1211 LIST_FOR_EACH_ENTRY_SAFE( impl
, next
, &acquired_keyboard_list
, struct dinput_device
, entry
)
1213 if (msg
->hwnd
== impl
->win
&& msg
->hwnd
!= foreground
)
1215 TRACE( "%p window is not foreground - unacquiring %p\n", impl
->win
, impl
);
1216 dinput_device_internal_unacquire( &impl
->IDirectInputDevice8W_iface
);
1219 LeaveCriticalSection( &dinput_hook_crit
);
1221 return CallNextHookEx( 0, code
, wparam
, lparam
);
1224 static DWORD WINAPI
dinput_thread_proc( void *params
)
1226 HANDLE events
[128], start_event
= params
;
1227 static HHOOK kbd_hook
, mouse_hook
;
1228 struct dinput_device
*impl
, *next
;
1229 SIZE_T events_count
= 0;
1230 HANDLE finished_event
;
1234 di_em_win
= CreateWindowW( L
"DIEmWin", L
"DIEmWin", 0, 0, 0, 0, 0, HWND_MESSAGE
, 0, DINPUT_instance
, NULL
);
1236 /* Force creation of the message queue */
1237 PeekMessageW( &msg
, 0, 0, 0, PM_NOREMOVE
);
1238 SetEvent( start_event
);
1240 while ((ret
= MsgWaitForMultipleObjectsEx( events_count
, events
, INFINITE
, QS_ALLINPUT
, 0 )) <= events_count
)
1242 UINT kbd_cnt
= 0, mice_cnt
= 0;
1244 if (ret
< events_count
)
1246 EnterCriticalSection( &dinput_hook_crit
);
1247 LIST_FOR_EACH_ENTRY_SAFE( impl
, next
, &acquired_device_list
, struct dinput_device
, entry
)
1249 if (impl
->read_event
== events
[ret
])
1251 if (FAILED( impl
->vtbl
->read( &impl
->IDirectInputDevice8W_iface
) ))
1253 dinput_device_internal_unacquire( &impl
->IDirectInputDevice8W_iface
);
1254 impl
->status
= STATUS_UNPLUGGED
;
1259 LeaveCriticalSection( &dinput_hook_crit
);
1262 while (PeekMessageW( &msg
, 0, 0, 0, PM_REMOVE
))
1264 if (msg
.message
!= WM_USER
+0x10)
1266 TranslateMessage(&msg
);
1267 DispatchMessageW(&msg
);
1271 finished_event
= (HANDLE
)msg
.lParam
;
1273 TRACE( "Processing hook change notification wparam %#Ix, lparam %#Ix.\n", msg
.wParam
, msg
.lParam
);
1277 if (kbd_hook
) UnhookWindowsHookEx( kbd_hook
);
1278 if (mouse_hook
) UnhookWindowsHookEx( mouse_hook
);
1279 kbd_hook
= mouse_hook
= NULL
;
1283 EnterCriticalSection( &dinput_hook_crit
);
1284 kbd_cnt
= list_count( &acquired_keyboard_list
);
1285 mice_cnt
= list_count( &acquired_mouse_list
);
1286 LeaveCriticalSection( &dinput_hook_crit
);
1288 if (kbd_cnt
&& !kbd_hook
)
1289 kbd_hook
= SetWindowsHookExW( WH_KEYBOARD_LL
, LL_hook_proc
, DINPUT_instance
, 0 );
1290 else if (!kbd_cnt
&& kbd_hook
)
1292 UnhookWindowsHookEx( kbd_hook
);
1296 if (mice_cnt
&& !mouse_hook
)
1297 mouse_hook
= SetWindowsHookExW( WH_MOUSE_LL
, LL_hook_proc
, DINPUT_instance
, 0 );
1298 else if (!mice_cnt
&& mouse_hook
)
1300 UnhookWindowsHookEx( mouse_hook
);
1304 SetEvent(finished_event
);
1308 EnterCriticalSection( &dinput_hook_crit
);
1309 LIST_FOR_EACH_ENTRY( impl
, &acquired_device_list
, struct dinput_device
, entry
)
1311 if (!impl
->read_event
|| !impl
->vtbl
->read
) continue;
1312 if (events_count
>= ARRAY_SIZE(events
)) break;
1313 events
[events_count
++] = impl
->read_event
;
1315 LeaveCriticalSection( &dinput_hook_crit
);
1318 if (ret
!= events_count
) ERR("Unexpected termination, ret %#lx\n", ret
);
1321 DestroyWindow( di_em_win
);
1326 static BOOL WINAPI
dinput_thread_start_once( INIT_ONCE
*once
, void *param
, void **context
)
1330 start_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
1331 if (!start_event
) ERR( "failed to create start event, error %lu\n", GetLastError() );
1333 dinput_thread
= CreateThread( NULL
, 0, dinput_thread_proc
, start_event
, 0, &dinput_thread_id
);
1334 if (!dinput_thread
) ERR( "failed to create internal thread, error %lu\n", GetLastError() );
1336 WaitForSingleObject( start_event
, INFINITE
);
1337 CloseHandle( start_event
);
1342 static void dinput_thread_start(void)
1344 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
1345 InitOnceExecuteOnce( &init_once
, dinput_thread_start_once
, NULL
, NULL
);
1348 static void dinput_thread_stop(void)
1350 PostThreadMessageW( dinput_thread_id
, WM_USER
+ 0x10, 0, 0 );
1351 if (WaitForSingleObject( dinput_thread
, 500 ) == WAIT_TIMEOUT
)
1352 WARN("Timeout while waiting for internal thread\n");
1353 CloseHandle( dinput_thread
);
1356 void check_dinput_hooks( IDirectInputDevice8W
*iface
, BOOL acquired
)
1358 static HHOOK callwndproc_hook
;
1359 static ULONG foreground_cnt
;
1360 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1361 HANDLE hook_change_finished_event
= NULL
;
1363 dinput_thread_start();
1365 EnterCriticalSection(&dinput_hook_crit
);
1367 if (impl
->dwCoopLevel
& DISCL_FOREGROUND
)
1375 if (foreground_cnt
&& !callwndproc_hook
)
1376 callwndproc_hook
= SetWindowsHookExW( WH_CALLWNDPROC
, callwndproc_proc
,
1377 DINPUT_instance
, GetCurrentThreadId() );
1378 else if (!foreground_cnt
&& callwndproc_hook
)
1380 UnhookWindowsHookEx( callwndproc_hook
);
1381 callwndproc_hook
= NULL
;
1384 if (impl
->use_raw_input
)
1388 impl
->raw_device
.dwFlags
= 0;
1389 if (impl
->dwCoopLevel
& DISCL_BACKGROUND
)
1390 impl
->raw_device
.dwFlags
|= RIDEV_INPUTSINK
;
1391 if (impl
->dwCoopLevel
& DISCL_EXCLUSIVE
)
1392 impl
->raw_device
.dwFlags
|= RIDEV_NOLEGACY
;
1393 if ((impl
->dwCoopLevel
& DISCL_EXCLUSIVE
) && impl
->raw_device
.usUsage
== 2)
1394 impl
->raw_device
.dwFlags
|= RIDEV_CAPTUREMOUSE
;
1395 if ((impl
->dwCoopLevel
& DISCL_EXCLUSIVE
) && impl
->raw_device
.usUsage
== 6)
1396 impl
->raw_device
.dwFlags
|= RIDEV_NOHOTKEYS
;
1397 impl
->raw_device
.hwndTarget
= di_em_win
;
1401 impl
->raw_device
.dwFlags
= RIDEV_REMOVE
;
1402 impl
->raw_device
.hwndTarget
= NULL
;
1405 if (!RegisterRawInputDevices( &impl
->raw_device
, 1, sizeof(RAWINPUTDEVICE
) ))
1406 WARN( "Unable to (un)register raw device %x:%x\n", impl
->raw_device
.usUsagePage
, impl
->raw_device
.usUsage
);
1409 hook_change_finished_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
1410 PostThreadMessageW( dinput_thread_id
, WM_USER
+ 0x10, 1, (LPARAM
)hook_change_finished_event
);
1412 LeaveCriticalSection(&dinput_hook_crit
);
1414 WaitForSingleObject(hook_change_finished_event
, INFINITE
);
1415 CloseHandle(hook_change_finished_event
);
1418 void check_dinput_events(void)
1420 /* Windows does not do that, but our current implementation of winex11
1421 * requires periodic event polling to forward events to the wineserver.
1423 * We have to call this function from multiple places, because:
1424 * - some games do not explicitly poll for mouse events
1425 * (for example Culpa Innata)
1426 * - some games only poll the device, and neither keyboard nor mouse
1427 * (for example Civilization: Call to Power 2)
1428 * - some games do not explicitly poll for keyboard events
1429 * (for example Morrowind in its key binding page)
1431 MsgWaitForMultipleObjectsEx(0, NULL
, 0, QS_ALLINPUT
, 0);
1434 BOOL WINAPI
DllMain( HINSTANCE inst
, DWORD reason
, void *reserved
)
1436 TRACE( "inst %p, reason %lu, reserved %p.\n", inst
, reason
, reserved
);
1440 case DLL_PROCESS_ATTACH
:
1441 DisableThreadLibraryCalls(inst
);
1442 DINPUT_instance
= inst
;
1443 register_di_em_win_class();
1445 case DLL_PROCESS_DETACH
:
1446 if (reserved
) break;
1447 dinput_thread_stop();
1448 unregister_di_em_win_class();