3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
36 #include "device_private.h"
37 #include "dinput_private.h"
39 #include "wine/debug.h"
41 #define WM_WINE_NOTIFY_ACTIVITY WM_USER
43 WINE_DEFAULT_DEBUG_CHANNEL(dinput
);
45 /* Windows uses this GUID for guidProduct on non-keyboard/mouse devices.
46 * Data1 contains the device VID (low word) and PID (high word).
47 * Data4 ends with the ASCII bytes "PIDVID".
49 DEFINE_GUID( dinput_pidvid_guid
, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 'P', 'I', 'D', 'V', 'I', 'D' );
51 static inline struct dinput_device
*impl_from_IDirectInputDevice8W( IDirectInputDevice8W
*iface
)
53 return CONTAINING_RECORD( iface
, struct dinput_device
, IDirectInputDevice8W_iface
);
56 static inline IDirectInputDevice8A
*IDirectInputDevice8A_from_impl( struct dinput_device
*This
)
58 return &This
->IDirectInputDevice8A_iface
;
60 static inline IDirectInputDevice8W
*IDirectInputDevice8W_from_impl( struct dinput_device
*This
)
62 return &This
->IDirectInputDevice8W_iface
;
65 static inline const char *debugstr_didataformat( const DIDATAFORMAT
*data
)
67 if (!data
) return "(null)";
68 return wine_dbg_sprintf( "%p dwSize %lu, dwObjsize %lu, dwFlags %#lx, dwDataSize %lu, dwNumObjs %lu, rgodf %p",
69 data
, data
->dwSize
, data
->dwObjSize
, data
->dwFlags
, data
->dwDataSize
, data
->dwNumObjs
, data
->rgodf
);
72 static inline const char *debugstr_diobjectdataformat( const DIOBJECTDATAFORMAT
*data
)
74 if (!data
) return "(null)";
75 return wine_dbg_sprintf( "%p pguid %s, dwOfs %#lx, dwType %#lx, dwFlags %#lx", data
,
76 debugstr_guid( data
->pguid
), data
->dwOfs
, data
->dwType
, data
->dwFlags
);
79 static inline BOOL
is_exclusively_acquired( struct dinput_device
*device
)
81 return device
->status
== STATUS_ACQUIRED
&& (device
->dwCoopLevel
& DISCL_EXCLUSIVE
);
84 static void _dump_cooperativelevel_DI(DWORD dwFlags
) {
85 if (TRACE_ON(dinput
)) {
91 #define FE(x) { x, #x}
95 FE(DISCL_NONEXCLUSIVE
),
99 TRACE(" cooperative level : ");
100 for (i
= 0; i
< ARRAY_SIZE(flags
); i
++)
101 if (flags
[i
].mask
& dwFlags
)
102 TRACE("%s ",flags
[i
].name
);
107 BOOL
get_app_key(HKEY
*defkey
, HKEY
*appkey
)
109 char buffer
[MAX_PATH
+16];
114 /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */
115 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\DirectInput", defkey
))
118 len
= GetModuleFileNameA(0, buffer
, MAX_PATH
);
119 if (len
&& len
< MAX_PATH
)
123 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */
124 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\AppDefaults", &tmpkey
))
126 char *p
, *appname
= buffer
;
127 if ((p
= strrchr(appname
, '/'))) appname
= p
+ 1;
128 if ((p
= strrchr(appname
, '\\'))) appname
= p
+ 1;
129 strcat(appname
, "\\DirectInput");
131 if (RegOpenKeyA(tmpkey
, appname
, appkey
)) *appkey
= 0;
136 return *defkey
|| *appkey
;
139 DWORD
get_config_key( HKEY defkey
, HKEY appkey
, const WCHAR
*name
, WCHAR
*buffer
, DWORD size
)
141 if (appkey
&& !RegQueryValueExW( appkey
, name
, 0, NULL
, (LPBYTE
)buffer
, &size
)) return 0;
143 if (defkey
&& !RegQueryValueExW( defkey
, name
, 0, NULL
, (LPBYTE
)buffer
, &size
)) return 0;
145 return ERROR_FILE_NOT_FOUND
;
148 BOOL
device_instance_is_disabled( DIDEVICEINSTANCEW
*instance
, BOOL
*override
)
150 static const WCHAR disabled_str
[] = {'d', 'i', 's', 'a', 'b', 'l', 'e', 'd', 0};
151 static const WCHAR override_str
[] = {'o', 'v', 'e', 'r', 'r', 'i', 'd', 'e', 0};
152 static const WCHAR joystick_key
[] = {'J', 'o', 'y', 's', 't', 'i', 'c', 'k', 's', 0};
153 WCHAR buffer
[MAX_PATH
];
154 HKEY hkey
, appkey
, temp
;
155 BOOL disable
= FALSE
;
157 get_app_key( &hkey
, &appkey
);
158 if (override
) *override
= FALSE
;
160 /* Joystick settings are in the 'joysticks' subkey */
163 if (RegOpenKeyW( appkey
, joystick_key
, &temp
)) temp
= 0;
164 RegCloseKey( appkey
);
170 if (RegOpenKeyW( hkey
, joystick_key
, &temp
)) temp
= 0;
175 /* Look for the "controllername"="disabled" key */
176 if (!get_config_key( hkey
, appkey
, instance
->tszInstanceName
, buffer
, sizeof(buffer
) ))
178 if (!wcscmp( disabled_str
, buffer
))
180 TRACE( "Disabling joystick '%s' based on registry key.\n", debugstr_w(instance
->tszInstanceName
) );
183 else if (override
&& !wcscmp( override_str
, buffer
))
185 TRACE( "Force enabling joystick '%s' based on registry key.\n", debugstr_w(instance
->tszInstanceName
) );
190 if (appkey
) RegCloseKey( appkey
);
191 if (hkey
) RegCloseKey( hkey
);
196 static void dinput_device_release_user_format( struct dinput_device
*impl
)
198 free( impl
->user_format
.rgodf
);
199 impl
->user_format
.rgodf
= NULL
;
202 static inline LPDIOBJECTDATAFORMAT
dataformat_to_odf(LPCDIDATAFORMAT df
, int idx
)
204 if (idx
< 0 || idx
>= df
->dwNumObjs
) return NULL
;
205 return (LPDIOBJECTDATAFORMAT
)((LPBYTE
)df
->rgodf
+ idx
* df
->dwObjSize
);
208 /* dataformat_to_odf_by_type
209 * Find the Nth object of the selected type in the DataFormat
211 LPDIOBJECTDATAFORMAT
dataformat_to_odf_by_type(LPCDIDATAFORMAT df
, int n
, DWORD type
)
215 for (i
=0; i
< df
->dwNumObjs
; i
++)
217 LPDIOBJECTDATAFORMAT odf
= dataformat_to_odf(df
, i
);
219 if (odf
->dwType
& type
)
231 static BOOL
match_device_object( const DIDATAFORMAT
*device_format
, DIDATAFORMAT
*user_format
,
232 const DIOBJECTDATAFORMAT
*match_obj
, DWORD version
)
234 DWORD i
, device_instance
, instance
= DIDFT_GETINSTANCE( match_obj
->dwType
);
235 DIOBJECTDATAFORMAT
*device_obj
, *user_obj
;
237 if (version
< 0x0700 && instance
== 0xff) instance
= 0xffff;
239 for (i
= 0; i
< device_format
->dwNumObjs
; i
++)
241 user_obj
= user_format
->rgodf
+ i
;
242 device_obj
= device_format
->rgodf
+ i
;
243 device_instance
= DIDFT_GETINSTANCE( device_obj
->dwType
);
245 if (!(user_obj
->dwType
& DIDFT_OPTIONAL
)) continue; /* already matched */
246 if (match_obj
->pguid
&& device_obj
->pguid
&& !IsEqualGUID( device_obj
->pguid
, match_obj
->pguid
)) continue;
247 if (instance
!= DIDFT_GETINSTANCE( DIDFT_ANYINSTANCE
) && instance
!= device_instance
) continue;
248 if (!(DIDFT_GETTYPE( match_obj
->dwType
) & DIDFT_GETTYPE( device_obj
->dwType
))) continue;
250 TRACE( "match %s with device %s\n", debugstr_diobjectdataformat( match_obj
),
251 debugstr_diobjectdataformat( device_obj
) );
253 *user_obj
= *device_obj
;
254 user_obj
->dwOfs
= match_obj
->dwOfs
;
261 static HRESULT
dinput_device_init_user_format( struct dinput_device
*impl
, const DIDATAFORMAT
*format
)
263 DIDATAFORMAT
*user_format
= &impl
->user_format
, *device_format
= &impl
->device_format
;
264 DIOBJECTDATAFORMAT
*user_obj
, *match_obj
;
267 *user_format
= *device_format
;
268 user_format
->dwFlags
= format
->dwFlags
;
269 user_format
->dwDataSize
= format
->dwDataSize
;
270 user_format
->dwNumObjs
+= format
->dwNumObjs
;
271 if (!(user_format
->rgodf
= calloc( user_format
->dwNumObjs
, sizeof(DIOBJECTDATAFORMAT
) ))) return DIERR_OUTOFMEMORY
;
273 user_obj
= user_format
->rgodf
+ user_format
->dwNumObjs
;
274 while (user_obj
-- > user_format
->rgodf
) user_obj
->dwType
|= DIDFT_OPTIONAL
;
276 for (i
= 0; i
< device_format
->dwNumObjs
; i
++)
277 impl
->object_properties
[i
].app_data
= -1;
279 for (i
= 0; i
< format
->dwNumObjs
; ++i
)
281 match_obj
= format
->rgodf
+ i
;
283 if (!match_device_object( device_format
, user_format
, match_obj
, impl
->dinput
->dwVersion
))
285 WARN( "object %s not found\n", debugstr_diobjectdataformat( match_obj
) );
286 if (!(match_obj
->dwType
& DIDFT_OPTIONAL
)) goto failed
;
287 user_obj
= user_format
->rgodf
+ device_format
->dwNumObjs
+ i
;
288 *user_obj
= *match_obj
;
292 user_obj
= user_format
->rgodf
+ user_format
->dwNumObjs
;
293 while (user_obj
-- > user_format
->rgodf
) user_obj
->dwType
&= ~DIDFT_OPTIONAL
;
298 free( user_format
->rgodf
);
299 user_format
->rgodf
= NULL
;
300 return DIERR_INVALIDPARAM
;
303 int dinput_device_object_index_from_id( IDirectInputDevice8W
*iface
, DWORD id
)
305 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
306 const DIDATAFORMAT
*format
= &impl
->device_format
;
307 const DIOBJECTDATAFORMAT
*object
;
309 if (!format
->rgodf
) return -1;
311 object
= format
->rgodf
+ impl
->device_format
.dwNumObjs
;
312 while (object
-- > format
->rgodf
)
314 if (!object
->dwType
) continue;
315 if ((object
->dwType
& 0x00ffffff) == (id
& 0x00ffffff)) return object
- format
->rgodf
;
323 * Retrieves an open registry key to save the mapping, parametrized for an username,
324 * specific device and specific action mapping guid.
326 static HKEY
get_mapping_key( const WCHAR
*device
, const WCHAR
*username
, const WCHAR
*guid
, BOOL
delete )
328 static const WCHAR format
[] = L
"Software\\Wine\\DirectInput\\Mappings\\%s\\%s\\%s";
329 SIZE_T len
= wcslen( format
) + wcslen( username
) + wcslen( device
) + wcslen( guid
) + 1;
333 if (!(keyname
= malloc( sizeof(WCHAR
) * len
))) return 0;
335 /* The key used is HKCU\Software\Wine\DirectInput\Mappings\[username]\[device]\[mapping_guid] */
336 swprintf( keyname
, len
, format
, username
, device
, guid
);
338 if (delete) RegDeleteTreeW( HKEY_CURRENT_USER
, keyname
);
339 if (RegCreateKeyW( HKEY_CURRENT_USER
, keyname
, &hkey
)) hkey
= 0;
346 static HRESULT
save_mapping_settings(IDirectInputDevice8W
*iface
, LPDIACTIONFORMATW lpdiaf
, LPCWSTR lpszUsername
)
348 WCHAR
*guid_str
= NULL
;
349 DIDEVICEINSTANCEW didev
;
353 didev
.dwSize
= sizeof(didev
);
354 IDirectInputDevice8_GetDeviceInfo(iface
, &didev
);
356 if (StringFromCLSID(&lpdiaf
->guidActionMap
, &guid_str
) != S_OK
)
357 return DI_SETTINGSNOTSAVED
;
359 if (!(hkey
= get_mapping_key( didev
.tszInstanceName
, lpszUsername
, guid_str
, TRUE
)))
361 CoTaskMemFree(guid_str
);
362 return DI_SETTINGSNOTSAVED
;
365 /* Write each of the actions mapped for this device.
366 Format is "dwSemantic"="dwObjID" and key is of type REG_DWORD
368 for (i
= 0; i
< lpdiaf
->dwNumActions
; i
++)
372 if (IsEqualGUID(&didev
.guidInstance
, &lpdiaf
->rgoAction
[i
].guidInstance
) &&
373 lpdiaf
->rgoAction
[i
].dwHow
!= DIAH_UNMAPPED
)
375 swprintf( label
, 9, L
"%x", lpdiaf
->rgoAction
[i
].dwSemantic
);
376 RegSetValueExW( hkey
, label
, 0, REG_DWORD
, (const BYTE
*)&lpdiaf
->rgoAction
[i
].dwObjID
,
382 CoTaskMemFree(guid_str
);
387 static BOOL
load_mapping_settings( struct dinput_device
*This
, LPDIACTIONFORMATW lpdiaf
, const WCHAR
*username
)
391 DIDEVICEINSTANCEW didev
;
394 didev
.dwSize
= sizeof(didev
);
395 IDirectInputDevice8_GetDeviceInfo(&This
->IDirectInputDevice8W_iface
, &didev
);
397 if (StringFromCLSID(&lpdiaf
->guidActionMap
, &guid_str
) != S_OK
)
400 if (!(hkey
= get_mapping_key( didev
.tszInstanceName
, username
, guid_str
, FALSE
)))
402 CoTaskMemFree(guid_str
);
406 /* Try to read each action in the DIACTIONFORMAT from registry */
407 for (i
= 0; i
< lpdiaf
->dwNumActions
; i
++)
409 DWORD id
, size
= sizeof(DWORD
);
412 swprintf( label
, 9, L
"%x", lpdiaf
->rgoAction
[i
].dwSemantic
);
414 if (!RegQueryValueExW(hkey
, label
, 0, NULL
, (LPBYTE
) &id
, &size
))
416 lpdiaf
->rgoAction
[i
].dwObjID
= id
;
417 lpdiaf
->rgoAction
[i
].guidInstance
= didev
.guidInstance
;
418 lpdiaf
->rgoAction
[i
].dwHow
= DIAH_DEFAULT
;
424 CoTaskMemFree(guid_str
);
429 void queue_event( IDirectInputDevice8W
*iface
, int index
, DWORD data
, DWORD time
, DWORD seq
)
431 static ULONGLONG notify_ms
= 0;
432 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
433 struct object_properties
*properties
= This
->object_properties
+ index
;
434 const DIOBJECTDATAFORMAT
*user_obj
= This
->user_format
.rgodf
+ index
;
435 ULONGLONG time_ms
= GetTickCount64();
438 if (time_ms
- notify_ms
> 1000)
440 PostMessageW(GetDesktopWindow(), WM_WINE_NOTIFY_ACTIVITY
, 0, 0);
444 if (!This
->queue_len
|| This
->overflow
|| !user_obj
->dwType
) return;
446 next_pos
= (This
->queue_head
+ 1) % This
->queue_len
;
447 if (next_pos
== This
->queue_tail
)
449 TRACE(" queue overflowed\n");
450 This
->overflow
= TRUE
;
454 TRACE( " queueing %lu at offset %lu (queue head %u / size %u)\n", data
, user_obj
->dwOfs
, This
->queue_head
, This
->queue_len
);
456 This
->data_queue
[This
->queue_head
].dwOfs
= user_obj
->dwOfs
;
457 This
->data_queue
[This
->queue_head
].dwData
= data
;
458 This
->data_queue
[This
->queue_head
].dwTimeStamp
= time
;
459 This
->data_queue
[This
->queue_head
].dwSequence
= seq
;
460 This
->data_queue
[This
->queue_head
].uAppData
= properties
->app_data
;
462 This
->queue_head
= next_pos
;
463 /* Send event if asked */
466 static HRESULT WINAPI
dinput_device_Acquire( IDirectInputDevice8W
*iface
)
468 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
472 TRACE( "iface %p.\n", iface
);
474 EnterCriticalSection( &impl
->crit
);
475 if (impl
->status
== STATUS_ACQUIRED
)
477 else if (!impl
->user_format
.rgodf
)
478 hr
= DIERR_INVALIDPARAM
;
479 else if ((impl
->dwCoopLevel
& DISCL_FOREGROUND
) && impl
->win
!= GetForegroundWindow())
480 hr
= DIERR_OTHERAPPHASPRIO
;
481 else if ((impl
->dwCoopLevel
& DISCL_FOREGROUND
) && (!GetWindowThreadProcessId( impl
->win
, &pid
) || pid
!= GetCurrentProcessId()))
482 hr
= DIERR_INVALIDPARAM
;
485 impl
->status
= STATUS_ACQUIRED
;
486 if (FAILED(hr
= impl
->vtbl
->acquire( iface
))) impl
->status
= STATUS_UNACQUIRED
;
488 LeaveCriticalSection( &impl
->crit
);
489 if (hr
!= DI_OK
) return hr
;
491 dinput_hooks_acquire_device( iface
);
496 static HRESULT WINAPI
dinput_device_Unacquire( IDirectInputDevice8W
*iface
)
498 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
501 TRACE( "iface %p.\n", iface
);
503 EnterCriticalSection( &impl
->crit
);
504 if (impl
->status
!= STATUS_ACQUIRED
) hr
= DI_NOEFFECT
;
505 else hr
= impl
->vtbl
->unacquire( iface
);
506 impl
->status
= STATUS_UNACQUIRED
;
507 LeaveCriticalSection( &impl
->crit
);
508 if (hr
!= DI_OK
) return hr
;
510 dinput_hooks_unacquire_device( iface
);
515 static HRESULT WINAPI
dinput_device_SetDataFormat( IDirectInputDevice8W
*iface
, const DIDATAFORMAT
*format
)
517 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
521 TRACE( "iface %p, format %p.\n", iface
, format
);
523 if (!format
) return E_POINTER
;
524 if (TRACE_ON( dinput
))
526 TRACE( "user format %s\n", debugstr_didataformat( format
) );
527 for (i
= 0; i
< format
->dwNumObjs
; ++i
) TRACE( " %lu: object %s\n", i
, debugstr_diobjectdataformat( format
->rgodf
+ i
) );
530 if (format
->dwSize
!= sizeof(DIDATAFORMAT
)) return DIERR_INVALIDPARAM
;
531 if (format
->dwObjSize
!= sizeof(DIOBJECTDATAFORMAT
)) return DIERR_INVALIDPARAM
;
532 if (This
->status
== STATUS_ACQUIRED
) return DIERR_ACQUIRED
;
534 EnterCriticalSection(&This
->crit
);
536 dinput_device_release_user_format( This
);
537 res
= dinput_device_init_user_format( This
, format
);
539 LeaveCriticalSection(&This
->crit
);
543 static HRESULT WINAPI
dinput_device_SetCooperativeLevel( IDirectInputDevice8W
*iface
, HWND hwnd
, DWORD flags
)
545 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
548 TRACE( "iface %p, hwnd %p, flags %#lx.\n", iface
, hwnd
, flags
);
550 _dump_cooperativelevel_DI( flags
);
552 if ((flags
& (DISCL_EXCLUSIVE
| DISCL_NONEXCLUSIVE
)) == 0 ||
553 (flags
& (DISCL_EXCLUSIVE
| DISCL_NONEXCLUSIVE
)) == (DISCL_EXCLUSIVE
| DISCL_NONEXCLUSIVE
) ||
554 (flags
& (DISCL_FOREGROUND
| DISCL_BACKGROUND
)) == 0 ||
555 (flags
& (DISCL_FOREGROUND
| DISCL_BACKGROUND
)) == (DISCL_FOREGROUND
| DISCL_BACKGROUND
))
556 return DIERR_INVALIDPARAM
;
558 if (hwnd
&& GetWindowLongW(hwnd
, GWL_STYLE
) & WS_CHILD
) return E_HANDLE
;
560 if (!hwnd
&& flags
== (DISCL_NONEXCLUSIVE
| DISCL_BACKGROUND
)) hwnd
= GetDesktopWindow();
562 if (!IsWindow(hwnd
)) return E_HANDLE
;
564 /* For security reasons native does not allow exclusive background level
565 for mouse and keyboard only */
566 if (flags
& DISCL_EXCLUSIVE
&& flags
& DISCL_BACKGROUND
&&
567 (IsEqualGUID( &This
->guid
, &GUID_SysMouse
) || IsEqualGUID( &This
->guid
, &GUID_SysKeyboard
)))
568 return DIERR_UNSUPPORTED
;
570 EnterCriticalSection(&This
->crit
);
571 if (This
->status
== STATUS_ACQUIRED
) hr
= DIERR_ACQUIRED
;
575 This
->dwCoopLevel
= flags
;
578 LeaveCriticalSection(&This
->crit
);
583 static HRESULT WINAPI
dinput_device_GetDeviceInfo( IDirectInputDevice8W
*iface
, DIDEVICEINSTANCEW
*instance
)
585 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
588 TRACE( "iface %p, instance %p.\n", iface
, instance
);
590 if (!instance
) return E_POINTER
;
591 if (instance
->dwSize
!= sizeof(DIDEVICEINSTANCE_DX3W
) &&
592 instance
->dwSize
!= sizeof(DIDEVICEINSTANCEW
))
593 return DIERR_INVALIDPARAM
;
595 size
= instance
->dwSize
;
596 memcpy( instance
, &impl
->instance
, size
);
597 instance
->dwSize
= size
;
602 static HRESULT WINAPI
dinput_device_SetEventNotification( IDirectInputDevice8W
*iface
, HANDLE event
)
604 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
606 TRACE( "iface %p, event %p.\n", iface
, event
);
608 EnterCriticalSection(&This
->crit
);
609 This
->hEvent
= event
;
610 LeaveCriticalSection(&This
->crit
);
614 void dinput_device_internal_addref( struct dinput_device
*impl
)
616 ULONG ref
= InterlockedIncrement( &impl
->internal_ref
);
617 TRACE( "impl %p, internal ref %lu.\n", impl
, ref
);
620 void dinput_device_internal_release( struct dinput_device
*impl
)
622 ULONG ref
= InterlockedDecrement( &impl
->internal_ref
);
623 TRACE( "impl %p, internal ref %lu.\n", impl
, ref
);
627 if (impl
->vtbl
->destroy
) impl
->vtbl
->destroy( &impl
->IDirectInputDevice8W_iface
);
629 free( impl
->object_properties
);
630 free( impl
->data_queue
);
632 free( impl
->device_format
.rgodf
);
633 dinput_device_release_user_format( impl
);
635 dinput_internal_release( impl
->dinput
);
636 impl
->crit
.DebugInfo
->Spare
[0] = 0;
637 DeleteCriticalSection( &impl
->crit
);
643 static ULONG WINAPI
dinput_device_Release( IDirectInputDevice8W
*iface
)
645 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
646 ULONG ref
= InterlockedDecrement( &impl
->ref
);
648 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
652 IDirectInputDevice_Unacquire( iface
);
653 input_thread_remove_user();
654 dinput_device_internal_release( impl
);
660 static HRESULT WINAPI
dinput_device_GetCapabilities( IDirectInputDevice8W
*iface
, DIDEVCAPS
*caps
)
662 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
665 TRACE( "iface %p, caps %p.\n", iface
, caps
);
667 if (!caps
) return E_POINTER
;
668 if (caps
->dwSize
!= sizeof(DIDEVCAPS_DX3
) &&
669 caps
->dwSize
!= sizeof(DIDEVCAPS
))
670 return DIERR_INVALIDPARAM
;
673 memcpy( caps
, &impl
->caps
, size
);
679 static HRESULT WINAPI
dinput_device_QueryInterface( IDirectInputDevice8W
*iface
, const GUID
*iid
, void **out
)
681 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
683 TRACE( "iface %p, iid %s, out %p.\n", iface
, debugstr_guid( iid
), out
);
685 if (IsEqualGUID( &IID_IDirectInputDeviceA
, iid
) ||
686 IsEqualGUID( &IID_IDirectInputDevice2A
, iid
) ||
687 IsEqualGUID( &IID_IDirectInputDevice7A
, iid
) ||
688 IsEqualGUID( &IID_IDirectInputDevice8A
, iid
))
690 IDirectInputDevice2_AddRef(iface
);
691 *out
= IDirectInputDevice8A_from_impl( This
);
695 if (IsEqualGUID( &IID_IUnknown
, iid
) ||
696 IsEqualGUID( &IID_IDirectInputDeviceW
, iid
) ||
697 IsEqualGUID( &IID_IDirectInputDevice2W
, iid
) ||
698 IsEqualGUID( &IID_IDirectInputDevice7W
, iid
) ||
699 IsEqualGUID( &IID_IDirectInputDevice8W
, iid
))
701 IDirectInputDevice2_AddRef(iface
);
702 *out
= IDirectInputDevice8W_from_impl( This
);
706 WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid
) );
707 return E_NOINTERFACE
;
710 static ULONG WINAPI
dinput_device_AddRef( IDirectInputDevice8W
*iface
)
712 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
713 ULONG ref
= InterlockedIncrement( &impl
->ref
);
714 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
718 struct enum_objects_params
720 LPDIENUMDEVICEOBJECTSCALLBACKW callback
;
724 static BOOL
enum_objects_callback( struct dinput_device
*impl
, UINT index
, struct hid_value_caps
*caps
,
725 const DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
727 struct enum_objects_params
*params
= data
;
728 if (instance
->wUsagePage
== HID_USAGE_PAGE_PID
&& !(instance
->dwType
& DIDFT_NODATA
))
729 return DIENUM_CONTINUE
;
731 /* Applications may return non-zero values instead of DIENUM_CONTINUE. */
732 return params
->callback( instance
, params
->context
) ? DIENUM_CONTINUE
: DIENUM_STOP
;
735 static HRESULT WINAPI
dinput_device_EnumObjects( IDirectInputDevice8W
*iface
, LPDIENUMDEVICEOBJECTSCALLBACKW callback
,
736 void *context
, DWORD flags
)
738 static const DIPROPHEADER filter
=
740 .dwSize
= sizeof(filter
),
741 .dwHeaderSize
= sizeof(filter
),
742 .dwHow
= DIPH_DEVICE
,
744 struct enum_objects_params params
= {.callback
= callback
, .context
= context
};
745 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
748 TRACE( "iface %p, callback %p, context %p, flags %#lx.\n", iface
, callback
, context
, flags
);
750 if (!callback
) return DIERR_INVALIDPARAM
;
751 if (flags
& ~(DIDFT_AXIS
| DIDFT_POV
| DIDFT_BUTTON
| DIDFT_NODATA
| DIDFT_COLLECTION
))
752 return DIERR_INVALIDPARAM
;
754 if (flags
== DIDFT_ALL
|| (flags
& DIDFT_AXIS
))
756 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_AXIS
, enum_objects_callback
, ¶ms
);
757 if (FAILED(hr
)) return hr
;
758 if (hr
!= DIENUM_CONTINUE
) return DI_OK
;
760 if (flags
== DIDFT_ALL
|| (flags
& DIDFT_POV
))
762 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_POV
, enum_objects_callback
, ¶ms
);
763 if (FAILED(hr
)) return hr
;
764 if (hr
!= DIENUM_CONTINUE
) return DI_OK
;
766 if (flags
== DIDFT_ALL
|| (flags
& DIDFT_BUTTON
))
768 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_BUTTON
, enum_objects_callback
, ¶ms
);
769 if (FAILED(hr
)) return hr
;
770 if (hr
!= DIENUM_CONTINUE
) return DI_OK
;
772 if (flags
== DIDFT_ALL
|| (flags
& (DIDFT_NODATA
| DIDFT_COLLECTION
)))
774 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_NODATA
, enum_objects_callback
, ¶ms
);
775 if (FAILED(hr
)) return hr
;
776 if (hr
!= DIENUM_CONTINUE
) return DI_OK
;
782 static HRESULT
enum_object_filter_init( struct dinput_device
*impl
, DIPROPHEADER
*filter
)
784 DIOBJECTDATAFORMAT
*user_objs
= impl
->user_format
.rgodf
;
785 DWORD i
, count
= impl
->device_format
.dwNumObjs
;
787 if (filter
->dwHow
> DIPH_BYUSAGE
) return DIERR_INVALIDPARAM
;
788 if (filter
->dwHow
== DIPH_BYUSAGE
&& !(impl
->instance
.dwDevType
& DIDEVTYPE_HID
)) return DIERR_UNSUPPORTED
;
789 if (filter
->dwHow
!= DIPH_BYOFFSET
) return DI_OK
;
791 if (!user_objs
) return DIERR_NOTFOUND
;
793 for (i
= 0; i
< count
; i
++)
795 if (!user_objs
[i
].dwType
) continue;
796 if (user_objs
[i
].dwOfs
== filter
->dwObj
) break;
798 if (i
== count
) return DIERR_NOTFOUND
;
800 filter
->dwObj
= impl
->device_format
.rgodf
[i
].dwOfs
;
804 static HRESULT
check_property( struct dinput_device
*impl
, const GUID
*guid
, const DIPROPHEADER
*header
, BOOL set
)
806 switch (LOWORD( guid
))
808 case (DWORD_PTR
)DIPROP_VIDPID
:
809 case (DWORD_PTR
)DIPROP_TYPENAME
:
810 case (DWORD_PTR
)DIPROP_USERNAME
:
811 case (DWORD_PTR
)DIPROP_KEYNAME
:
812 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
813 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
814 case (DWORD_PTR
)DIPROP_APPDATA
:
815 if (impl
->dinput
->dwVersion
< 0x0800) return DIERR_UNSUPPORTED
;
819 switch (LOWORD( guid
))
821 case (DWORD_PTR
)DIPROP_INSTANCENAME
:
822 case (DWORD_PTR
)DIPROP_KEYNAME
:
823 case (DWORD_PTR
)DIPROP_PRODUCTNAME
:
824 case (DWORD_PTR
)DIPROP_TYPENAME
:
825 case (DWORD_PTR
)DIPROP_USERNAME
:
826 if (header
->dwSize
!= sizeof(DIPROPSTRING
)) return DIERR_INVALIDPARAM
;
829 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
830 case (DWORD_PTR
)DIPROP_AXISMODE
:
831 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
832 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
833 case (DWORD_PTR
)DIPROP_DEADZONE
:
834 case (DWORD_PTR
)DIPROP_FFGAIN
:
835 case (DWORD_PTR
)DIPROP_FFLOAD
:
836 case (DWORD_PTR
)DIPROP_GRANULARITY
:
837 case (DWORD_PTR
)DIPROP_JOYSTICKID
:
838 case (DWORD_PTR
)DIPROP_SATURATION
:
839 case (DWORD_PTR
)DIPROP_SCANCODE
:
840 case (DWORD_PTR
)DIPROP_VIDPID
:
841 if (header
->dwSize
!= sizeof(DIPROPDWORD
)) return DIERR_INVALIDPARAM
;
844 case (DWORD_PTR
)DIPROP_APPDATA
:
845 if (header
->dwSize
!= sizeof(DIPROPPOINTER
)) return DIERR_INVALIDPARAM
;
848 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
849 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
850 case (DWORD_PTR
)DIPROP_RANGE
:
851 if (header
->dwSize
!= sizeof(DIPROPRANGE
)) return DIERR_INVALIDPARAM
;
854 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
855 if (header
->dwSize
!= sizeof(DIPROPGUIDANDPATH
)) return DIERR_INVALIDPARAM
;
859 switch (LOWORD( guid
))
861 case (DWORD_PTR
)DIPROP_PRODUCTNAME
:
862 case (DWORD_PTR
)DIPROP_INSTANCENAME
:
863 case (DWORD_PTR
)DIPROP_VIDPID
:
864 case (DWORD_PTR
)DIPROP_JOYSTICKID
:
865 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
866 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
867 case (DWORD_PTR
)DIPROP_FFGAIN
:
868 case (DWORD_PTR
)DIPROP_TYPENAME
:
869 case (DWORD_PTR
)DIPROP_USERNAME
:
870 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
871 case (DWORD_PTR
)DIPROP_AXISMODE
:
872 case (DWORD_PTR
)DIPROP_FFLOAD
:
873 if (header
->dwHow
!= DIPH_DEVICE
) return DIERR_UNSUPPORTED
;
874 if (header
->dwObj
) return DIERR_INVALIDPARAM
;
877 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
878 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
879 case (DWORD_PTR
)DIPROP_RANGE
:
880 case (DWORD_PTR
)DIPROP_DEADZONE
:
881 case (DWORD_PTR
)DIPROP_SATURATION
:
882 case (DWORD_PTR
)DIPROP_GRANULARITY
:
883 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
884 if (header
->dwHow
== DIPH_DEVICE
&& !set
) return DIERR_UNSUPPORTED
;
887 case (DWORD_PTR
)DIPROP_KEYNAME
:
888 if (header
->dwHow
== DIPH_DEVICE
) return DIERR_INVALIDPARAM
;
891 case (DWORD_PTR
)DIPROP_SCANCODE
:
892 case (DWORD_PTR
)DIPROP_APPDATA
:
893 if (header
->dwHow
== DIPH_DEVICE
) return DIERR_UNSUPPORTED
;
899 switch (LOWORD( guid
))
901 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
902 if (impl
->status
== STATUS_ACQUIRED
) return DIERR_ACQUIRED
;
904 case (DWORD_PTR
)DIPROP_AXISMODE
:
905 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
906 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
907 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
908 if (impl
->status
== STATUS_ACQUIRED
) return DIERR_ACQUIRED
;
910 case (DWORD_PTR
)DIPROP_FFLOAD
:
911 case (DWORD_PTR
)DIPROP_GRANULARITY
:
912 case (DWORD_PTR
)DIPROP_VIDPID
:
913 case (DWORD_PTR
)DIPROP_TYPENAME
:
914 case (DWORD_PTR
)DIPROP_USERNAME
:
915 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
916 return DIERR_READONLY
;
919 switch (LOWORD( guid
))
921 case (DWORD_PTR
)DIPROP_RANGE
:
923 const DIPROPRANGE
*value
= (const DIPROPRANGE
*)header
;
924 if (value
->lMin
> value
->lMax
) return DIERR_INVALIDPARAM
;
927 case (DWORD_PTR
)DIPROP_DEADZONE
:
928 case (DWORD_PTR
)DIPROP_SATURATION
:
929 case (DWORD_PTR
)DIPROP_FFGAIN
:
931 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
932 if (value
->dwData
> 10000) return DIERR_INVALIDPARAM
;
935 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
936 case (DWORD_PTR
)DIPROP_AXISMODE
:
937 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
939 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
940 if (value
->dwData
> 1) return DIERR_INVALIDPARAM
;
943 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
944 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
945 return DIERR_UNSUPPORTED
;
950 switch (LOWORD( guid
))
952 case (DWORD_PTR
)DIPROP_RANGE
:
953 case (DWORD_PTR
)DIPROP_GRANULARITY
:
954 if (!impl
->caps
.dwAxes
) return DIERR_UNSUPPORTED
;
957 case (DWORD_PTR
)DIPROP_KEYNAME
:
958 /* not supported on the mouse */
959 if (impl
->caps
.dwAxes
&& !(impl
->caps
.dwDevType
& DIDEVTYPE_HID
)) return DIERR_UNSUPPORTED
;
962 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
963 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
964 case (DWORD_PTR
)DIPROP_DEADZONE
:
965 case (DWORD_PTR
)DIPROP_SATURATION
:
966 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
967 /* not supported on the mouse or keyboard */
968 if (!(impl
->caps
.dwDevType
& DIDEVTYPE_HID
)) return DIERR_UNSUPPORTED
;
971 case (DWORD_PTR
)DIPROP_FFLOAD
:
972 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
973 if (!is_exclusively_acquired( impl
)) return DIERR_NOTEXCLUSIVEACQUIRED
;
975 case (DWORD_PTR
)DIPROP_PRODUCTNAME
:
976 case (DWORD_PTR
)DIPROP_INSTANCENAME
:
977 case (DWORD_PTR
)DIPROP_VIDPID
:
978 case (DWORD_PTR
)DIPROP_JOYSTICKID
:
979 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
980 if (!impl
->vtbl
->get_property
) return DIERR_UNSUPPORTED
;
988 struct get_object_property_params
990 IDirectInputDevice8W
*iface
;
991 DIPROPHEADER
*header
;
995 static BOOL
get_object_property( struct dinput_device
*device
, UINT index
, struct hid_value_caps
*caps
,
996 const DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
998 struct get_object_property_params
*params
= data
;
999 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( params
->iface
);
1000 const struct object_properties
*properties
;
1002 if (index
== -1) return DIENUM_STOP
;
1003 properties
= impl
->object_properties
+ index
;
1005 switch (params
->property
)
1007 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
1009 DIPROPRANGE
*value
= (DIPROPRANGE
*)params
->header
;
1010 value
->lMin
= properties
->physical_min
;
1011 value
->lMax
= properties
->physical_max
;
1014 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
1016 DIPROPRANGE
*value
= (DIPROPRANGE
*)params
->header
;
1017 value
->lMin
= properties
->logical_min
;
1018 value
->lMax
= properties
->logical_max
;
1021 case (DWORD_PTR
)DIPROP_RANGE
:
1023 DIPROPRANGE
*value
= (DIPROPRANGE
*)params
->header
;
1024 value
->lMin
= properties
->range_min
;
1025 value
->lMax
= properties
->range_max
;
1028 case (DWORD_PTR
)DIPROP_DEADZONE
:
1030 DIPROPDWORD
*value
= (DIPROPDWORD
*)params
->header
;
1031 value
->dwData
= properties
->deadzone
;
1034 case (DWORD_PTR
)DIPROP_SATURATION
:
1036 DIPROPDWORD
*value
= (DIPROPDWORD
*)params
->header
;
1037 value
->dwData
= properties
->saturation
;
1040 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1042 DIPROPDWORD
*value
= (DIPROPDWORD
*)params
->header
;
1043 value
->dwData
= properties
->calibration_mode
;
1046 case (DWORD_PTR
)DIPROP_GRANULARITY
:
1048 DIPROPDWORD
*value
= (DIPROPDWORD
*)params
->header
;
1049 value
->dwData
= properties
->granularity
;
1052 case (DWORD_PTR
)DIPROP_KEYNAME
:
1054 DIPROPSTRING
*value
= (DIPROPSTRING
*)params
->header
;
1055 lstrcpynW( value
->wsz
, instance
->tszName
, ARRAY_SIZE(value
->wsz
) );
1058 case (DWORD_PTR
)DIPROP_APPDATA
:
1060 DIPROPPOINTER
*value
= (DIPROPPOINTER
*)params
->header
;
1061 value
->uData
= properties
->app_data
;
1069 static HRESULT
dinput_device_get_property( IDirectInputDevice8W
*iface
, const GUID
*guid
, DIPROPHEADER
*header
)
1071 struct get_object_property_params params
= {.iface
= iface
, .header
= header
, .property
= LOWORD( guid
)};
1072 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1073 DWORD object_mask
= DIDFT_AXIS
| DIDFT_BUTTON
| DIDFT_POV
;
1074 DIPROPHEADER filter
;
1078 if (FAILED(hr
= enum_object_filter_init( impl
, &filter
))) return hr
;
1079 if (FAILED(hr
= check_property( impl
, guid
, header
, FALSE
))) return hr
;
1081 switch (LOWORD( guid
))
1083 case (DWORD_PTR
)DIPROP_PRODUCTNAME
:
1084 case (DWORD_PTR
)DIPROP_INSTANCENAME
:
1085 case (DWORD_PTR
)DIPROP_VIDPID
:
1086 case (DWORD_PTR
)DIPROP_JOYSTICKID
:
1087 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
1088 case (DWORD_PTR
)DIPROP_FFLOAD
:
1089 return impl
->vtbl
->get_property( iface
, LOWORD( guid
), header
, NULL
);
1091 case (DWORD_PTR
)DIPROP_RANGE
:
1092 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
1093 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
1094 case (DWORD_PTR
)DIPROP_DEADZONE
:
1095 case (DWORD_PTR
)DIPROP_SATURATION
:
1096 case (DWORD_PTR
)DIPROP_GRANULARITY
:
1097 case (DWORD_PTR
)DIPROP_KEYNAME
:
1098 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1099 case (DWORD_PTR
)DIPROP_APPDATA
:
1100 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, object_mask
, get_object_property
, ¶ms
);
1101 if (FAILED(hr
)) return hr
;
1102 if (hr
== DIENUM_CONTINUE
) return DIERR_NOTFOUND
;
1105 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
1107 DIPROPDWORD
*value
= (DIPROPDWORD
*)header
;
1108 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1109 value
->dwData
= impl
->autocenter
;
1112 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
1114 DIPROPDWORD
*value
= (DIPROPDWORD
*)header
;
1115 value
->dwData
= impl
->buffersize
;
1118 case (DWORD_PTR
)DIPROP_USERNAME
:
1120 DIPROPSTRING
*value
= (DIPROPSTRING
*)header
;
1121 struct DevicePlayer
*device_player
;
1122 LIST_FOR_EACH_ENTRY( device_player
, &impl
->dinput
->device_players
, struct DevicePlayer
, entry
)
1124 if (IsEqualGUID( &device_player
->instance_guid
, &impl
->guid
))
1126 if (!*device_player
->username
) break;
1127 lstrcpynW( value
->wsz
, device_player
->username
, ARRAY_SIZE(value
->wsz
) );
1133 case (DWORD_PTR
)DIPROP_FFGAIN
:
1135 DIPROPDWORD
*value
= (DIPROPDWORD
*)header
;
1136 value
->dwData
= impl
->device_gain
;
1139 case (DWORD_PTR
)DIPROP_CALIBRATION
:
1140 return DIERR_INVALIDPARAM
;
1142 FIXME( "Unknown property %s\n", debugstr_guid( guid
) );
1143 return DIERR_UNSUPPORTED
;
1149 static HRESULT WINAPI
dinput_device_GetProperty( IDirectInputDevice8W
*iface
, const GUID
*guid
, DIPROPHEADER
*header
)
1151 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1154 TRACE( "iface %p, guid %s, header %p\n", iface
, debugstr_guid( guid
), header
);
1156 if (!header
) return DIERR_INVALIDPARAM
;
1157 if (header
->dwHeaderSize
!= sizeof(DIPROPHEADER
)) return DIERR_INVALIDPARAM
;
1158 if (!IS_DIPROP( guid
)) return DI_OK
;
1160 EnterCriticalSection( &impl
->crit
);
1161 hr
= dinput_device_get_property( iface
, guid
, header
);
1162 LeaveCriticalSection( &impl
->crit
);
1167 struct set_object_property_params
1169 IDirectInputDevice8W
*iface
;
1170 const DIPROPHEADER
*header
;
1174 static BOOL
set_object_property( struct dinput_device
*device
, UINT index
, struct hid_value_caps
*caps
,
1175 const DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
1177 struct set_object_property_params
*params
= data
;
1178 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( params
->iface
);
1179 struct object_properties
*properties
;
1181 if (index
== -1) return DIENUM_STOP
;
1182 properties
= impl
->object_properties
+ index
;
1184 switch (params
->property
)
1186 case (DWORD_PTR
)DIPROP_RANGE
:
1188 const DIPROPRANGE
*value
= (const DIPROPRANGE
*)params
->header
;
1189 properties
->range_min
= value
->lMin
;
1190 properties
->range_max
= value
->lMax
;
1191 return DIENUM_CONTINUE
;
1193 case (DWORD_PTR
)DIPROP_DEADZONE
:
1195 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)params
->header
;
1196 properties
->deadzone
= value
->dwData
;
1197 return DIENUM_CONTINUE
;
1199 case (DWORD_PTR
)DIPROP_SATURATION
:
1201 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)params
->header
;
1202 properties
->saturation
= value
->dwData
;
1203 return DIENUM_CONTINUE
;
1205 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1207 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)params
->header
;
1208 properties
->calibration_mode
= value
->dwData
;
1209 return DIENUM_CONTINUE
;
1211 case (DWORD_PTR
)DIPROP_APPDATA
:
1213 DIPROPPOINTER
*value
= (DIPROPPOINTER
*)params
->header
;
1214 properties
->app_data
= value
->uData
;
1215 return DIENUM_CONTINUE
;
1222 static BOOL
reset_object_value( struct dinput_device
*impl
, UINT index
, struct hid_value_caps
*caps
,
1223 const DIDEVICEOBJECTINSTANCEW
*instance
, void *context
)
1225 struct object_properties
*properties
;
1228 if (index
== -1) return DIENUM_STOP
;
1229 properties
= impl
->object_properties
+ index
;
1231 if (instance
->dwType
& DIDFT_AXIS
)
1233 LONG range_min
= 0, range_max
= 0xfffe;
1234 if (properties
->range_min
!= DIPROPRANGE_NOMIN
) range_min
= properties
->range_min
;
1235 if (properties
->range_max
!= DIPROPRANGE_NOMAX
) range_max
= properties
->range_max
;
1236 tmp
= round( (range_min
+ range_max
) / 2.0 );
1239 *(LONG
*)(impl
->device_state
+ instance
->dwOfs
) = tmp
;
1240 return DIENUM_CONTINUE
;
1243 static void reset_device_state( IDirectInputDevice8W
*iface
)
1245 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1246 DIPROPHEADER filter
=
1248 .dwHeaderSize
= sizeof(DIPROPHEADER
),
1249 .dwSize
= sizeof(DIPROPHEADER
),
1250 .dwHow
= DIPH_DEVICE
,
1254 impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_AXIS
| DIDFT_POV
, reset_object_value
, impl
);
1257 static HRESULT
dinput_device_set_property( IDirectInputDevice8W
*iface
, const GUID
*guid
,
1258 const DIPROPHEADER
*header
)
1260 struct set_object_property_params params
= {.iface
= iface
, .header
= header
, .property
= LOWORD( guid
)};
1261 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1262 DIPROPHEADER filter
;
1266 if (FAILED(hr
= enum_object_filter_init( impl
, &filter
))) return hr
;
1267 if (FAILED(hr
= check_property( impl
, guid
, header
, TRUE
))) return hr
;
1269 switch (LOWORD( guid
))
1271 case (DWORD_PTR
)DIPROP_RANGE
:
1272 case (DWORD_PTR
)DIPROP_DEADZONE
:
1273 case (DWORD_PTR
)DIPROP_SATURATION
:
1275 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_AXIS
, set_object_property
, ¶ms
);
1276 if (FAILED(hr
)) return hr
;
1277 reset_device_state( iface
);
1280 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1282 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1283 if (value
->dwData
> DIPROPCALIBRATIONMODE_RAW
) return DIERR_INVALIDPARAM
;
1284 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_AXIS
, set_object_property
, ¶ms
);
1285 if (FAILED(hr
)) return hr
;
1286 reset_device_state( iface
);
1289 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
1291 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1292 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1293 impl
->autocenter
= value
->dwData
;
1296 case (DWORD_PTR
)DIPROP_FFGAIN
:
1298 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1299 impl
->device_gain
= value
->dwData
;
1300 if (!is_exclusively_acquired( impl
)) return DI_OK
;
1301 if (!impl
->vtbl
->send_device_gain
) return DI_OK
;
1302 return impl
->vtbl
->send_device_gain( iface
, impl
->device_gain
);
1304 case (DWORD_PTR
)DIPROP_AXISMODE
:
1306 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1308 TRACE( "Axis mode: %s\n", value
->dwData
== DIPROPAXISMODE_ABS
? "absolute" : "relative" );
1310 impl
->user_format
.dwFlags
&= ~DIDFT_AXIS
;
1311 impl
->user_format
.dwFlags
|= value
->dwData
== DIPROPAXISMODE_ABS
? DIDF_ABSAXIS
: DIDF_RELAXIS
;
1315 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
1317 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1319 TRACE( "buffersize %lu\n", value
->dwData
);
1321 impl
->buffersize
= value
->dwData
;
1322 impl
->queue_len
= min( impl
->buffersize
, 1024 );
1323 free( impl
->data_queue
);
1325 impl
->data_queue
= impl
->queue_len
? malloc( impl
->queue_len
* sizeof(DIDEVICEOBJECTDATA
) ) : NULL
;
1326 impl
->queue_head
= impl
->queue_tail
= impl
->overflow
= 0;
1329 case (DWORD_PTR
)DIPROP_APPDATA
:
1331 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_ALL
, set_object_property
, ¶ms
);
1332 if (FAILED(hr
)) return hr
;
1336 FIXME( "Unknown property %s\n", debugstr_guid( guid
) );
1337 return DIERR_UNSUPPORTED
;
1343 static HRESULT WINAPI
dinput_device_SetProperty( IDirectInputDevice8W
*iface
, const GUID
*guid
,
1344 const DIPROPHEADER
*header
)
1346 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1349 TRACE( "iface %p, guid %s, header %p\n", iface
, debugstr_guid( guid
), header
);
1351 if (!header
) return DIERR_INVALIDPARAM
;
1352 if (header
->dwHeaderSize
!= sizeof(DIPROPHEADER
)) return DIERR_INVALIDPARAM
;
1353 if (!IS_DIPROP( guid
)) return DI_OK
;
1355 EnterCriticalSection( &impl
->crit
);
1356 hr
= dinput_device_set_property( iface
, guid
, header
);
1357 LeaveCriticalSection( &impl
->crit
);
1362 static void dinput_device_set_username( struct dinput_device
*impl
, const DIPROPSTRING
*value
)
1364 struct DevicePlayer
*device_player
;
1367 LIST_FOR_EACH_ENTRY( device_player
, &impl
->dinput
->device_players
, struct DevicePlayer
, entry
)
1369 if (IsEqualGUID( &device_player
->instance_guid
, &impl
->guid
))
1375 if (!found
&& (device_player
= malloc( sizeof(struct DevicePlayer
) )))
1377 list_add_tail( &impl
->dinput
->device_players
, &device_player
->entry
);
1378 device_player
->instance_guid
= impl
->guid
;
1381 lstrcpynW( device_player
->username
, value
->wsz
, ARRAY_SIZE(device_player
->username
) );
1384 static BOOL
get_object_info( struct dinput_device
*device
, UINT index
, struct hid_value_caps
*caps
,
1385 const DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
1387 DIDEVICEOBJECTINSTANCEW
*dest
= data
;
1388 DWORD size
= dest
->dwSize
;
1390 memcpy( dest
, instance
, size
);
1391 dest
->dwSize
= size
;
1396 static HRESULT WINAPI
dinput_device_GetObjectInfo( IDirectInputDevice8W
*iface
,
1397 DIDEVICEOBJECTINSTANCEW
*instance
, DWORD obj
, DWORD how
)
1399 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1400 DIPROPHEADER filter
=
1402 .dwSize
= sizeof(filter
),
1403 .dwHeaderSize
= sizeof(filter
),
1409 TRACE( "iface %p, instance %p, obj %#lx, how %#lx.\n", iface
, instance
, obj
, how
);
1411 if (!instance
) return E_POINTER
;
1412 if (instance
->dwSize
!= sizeof(DIDEVICEOBJECTINSTANCE_DX3W
) && instance
->dwSize
!= sizeof(DIDEVICEOBJECTINSTANCEW
))
1413 return DIERR_INVALIDPARAM
;
1414 if (how
== DIPH_DEVICE
) return DIERR_INVALIDPARAM
;
1415 if (FAILED(hr
= enum_object_filter_init( impl
, &filter
))) return hr
;
1417 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_ALL
, get_object_info
, instance
);
1418 if (FAILED(hr
)) return hr
;
1419 if (hr
== DIENUM_CONTINUE
) return DIERR_NOTFOUND
;
1423 static HRESULT WINAPI
dinput_device_GetDeviceState( IDirectInputDevice8W
*iface
, DWORD size
, void *data
)
1425 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1426 DIDATAFORMAT
*device_format
= &impl
->device_format
, *user_format
= &impl
->user_format
;
1427 DIOBJECTDATAFORMAT
*device_obj
, *user_obj
;
1428 BYTE
*user_state
= data
;
1429 DIPROPHEADER filter
=
1431 .dwSize
= sizeof(filter
),
1432 .dwHeaderSize
= sizeof(filter
),
1433 .dwHow
= DIPH_DEVICE
,
1438 TRACE( "iface %p, size %lu, data %p.\n", iface
, size
, data
);
1440 if (!data
) return DIERR_INVALIDPARAM
;
1442 IDirectInputDevice2_Poll( iface
);
1444 EnterCriticalSection( &impl
->crit
);
1445 if (impl
->status
== STATUS_UNPLUGGED
)
1446 hr
= DIERR_INPUTLOST
;
1447 else if (impl
->status
!= STATUS_ACQUIRED
)
1448 hr
= DIERR_NOTACQUIRED
;
1449 else if (!user_format
->rgodf
)
1450 hr
= DIERR_INVALIDPARAM
;
1451 else if (size
!= user_format
->dwDataSize
)
1452 hr
= DIERR_INVALIDPARAM
;
1455 memset( user_state
, 0, size
);
1457 user_obj
= user_format
->rgodf
+ device_format
->dwNumObjs
;
1458 device_obj
= device_format
->rgodf
+ device_format
->dwNumObjs
;
1459 while (user_obj
-- > user_format
->rgodf
&& device_obj
-- > device_format
->rgodf
)
1461 if (user_obj
->dwType
& DIDFT_BUTTON
)
1462 user_state
[user_obj
->dwOfs
] = impl
->device_state
[device_obj
->dwOfs
];
1465 /* reset optional POVs to their default */
1466 user_obj
= user_format
->rgodf
+ user_format
->dwNumObjs
;
1467 while (user_obj
-- > user_format
->rgodf
+ device_format
->dwNumObjs
)
1468 if (user_obj
->dwType
& DIDFT_POV
) *(ULONG
*)(user_state
+ user_obj
->dwOfs
) = 0xffffffff;
1470 user_obj
= user_format
->rgodf
+ device_format
->dwNumObjs
;
1471 device_obj
= device_format
->rgodf
+ device_format
->dwNumObjs
;
1472 while (user_obj
-- > user_format
->rgodf
&& device_obj
-- > device_format
->rgodf
)
1474 if (user_obj
->dwType
& (DIDFT_POV
| DIDFT_AXIS
))
1475 *(ULONG
*)(user_state
+ user_obj
->dwOfs
) = *(ULONG
*)(impl
->device_state
+ device_obj
->dwOfs
);
1476 if (!(user_format
->dwFlags
& DIDF_ABSAXIS
) && (device_obj
->dwType
& DIDFT_RELAXIS
))
1477 *(ULONG
*)(impl
->device_state
+ device_obj
->dwOfs
) = 0;
1482 LeaveCriticalSection( &impl
->crit
);
1487 static HRESULT WINAPI
dinput_device_GetDeviceData( IDirectInputDevice8W
*iface
, DWORD size
, DIDEVICEOBJECTDATA
*data
,
1488 DWORD
*count
, DWORD flags
)
1490 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
1491 HRESULT ret
= DI_OK
;
1494 TRACE( "iface %p, size %lu, data %p, count %p, flags %#lx.\n", iface
, size
, data
, count
, flags
);
1496 if (This
->dinput
->dwVersion
== 0x0800 || size
== sizeof(DIDEVICEOBJECTDATA_DX3
))
1498 if (!This
->queue_len
) return DIERR_NOTBUFFERED
;
1499 if (This
->status
== STATUS_UNPLUGGED
) return DIERR_INPUTLOST
;
1500 if (This
->status
!= STATUS_ACQUIRED
) return DIERR_NOTACQUIRED
;
1503 if (!This
->queue_len
)
1505 if (size
< sizeof(DIDEVICEOBJECTDATA_DX3
)) return DIERR_INVALIDPARAM
;
1507 IDirectInputDevice2_Poll(iface
);
1508 EnterCriticalSection(&This
->crit
);
1510 len
= This
->queue_head
- This
->queue_tail
;
1511 if (len
< 0) len
+= This
->queue_len
;
1513 if ((*count
!= INFINITE
) && (len
> *count
)) len
= *count
;
1518 for (i
= 0; i
< len
; i
++)
1520 int n
= (This
->queue_tail
+ i
) % This
->queue_len
;
1521 memcpy( (char *)data
+ size
* i
, This
->data_queue
+ n
, size
);
1526 if (This
->overflow
&& This
->dinput
->dwVersion
== 0x0800)
1527 ret
= DI_BUFFEROVERFLOW
;
1529 if (!(flags
& DIGDD_PEEK
))
1531 /* Advance reading position */
1532 This
->queue_tail
= (This
->queue_tail
+ len
) % This
->queue_len
;
1533 This
->overflow
= FALSE
;
1536 LeaveCriticalSection(&This
->crit
);
1538 TRACE( "Returning %lu events queued\n", *count
);
1542 static HRESULT WINAPI
dinput_device_RunControlPanel( IDirectInputDevice8W
*iface
, HWND hwnd
, DWORD flags
)
1544 FIXME( "iface %p, hwnd %p, flags %#lx stub!\n", iface
, hwnd
, flags
);
1548 static HRESULT WINAPI
dinput_device_Initialize( IDirectInputDevice8W
*iface
, HINSTANCE instance
,
1549 DWORD version
, const GUID
*guid
)
1551 FIXME( "iface %p, instance %p, version %#lx, guid %s stub!\n", iface
, instance
, version
,
1552 debugstr_guid( guid
) );
1556 static HRESULT WINAPI
dinput_device_CreateEffect( IDirectInputDevice8W
*iface
, const GUID
*guid
,
1557 const DIEFFECT
*params
, IDirectInputEffect
**out
,
1560 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1564 TRACE( "iface %p, guid %s, params %p, out %p, outer %p\n", iface
, debugstr_guid( guid
),
1565 params
, out
, outer
);
1567 if (!out
) return E_POINTER
;
1570 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1571 if (!impl
->vtbl
->create_effect
) return DIERR_UNSUPPORTED
;
1572 if (FAILED(hr
= impl
->vtbl
->create_effect( iface
, out
))) return hr
;
1574 hr
= IDirectInputEffect_Initialize( *out
, DINPUT_instance
, impl
->dinput
->dwVersion
, guid
);
1575 if (FAILED(hr
)) goto failed
;
1576 if (!params
) return DI_OK
;
1578 flags
= params
->dwSize
== sizeof(DIEFFECT_DX6
) ? DIEP_ALLPARAMS
: DIEP_ALLPARAMS_DX5
;
1579 if (!is_exclusively_acquired( impl
)) flags
|= DIEP_NODOWNLOAD
;
1580 hr
= IDirectInputEffect_SetParameters( *out
, params
, flags
);
1581 if (FAILED(hr
)) goto failed
;
1585 IDirectInputEffect_Release( *out
);
1590 static HRESULT WINAPI
dinput_device_EnumEffects( IDirectInputDevice8W
*iface
, LPDIENUMEFFECTSCALLBACKW callback
,
1591 void *context
, DWORD type
)
1593 DIEFFECTINFOW info
= {.dwSize
= sizeof(info
)};
1596 TRACE( "iface %p, callback %p, context %p, type %#lx.\n", iface
, callback
, context
, type
);
1598 if (!callback
) return DIERR_INVALIDPARAM
;
1600 type
= DIEFT_GETTYPE( type
);
1602 if (type
== DIEFT_ALL
|| type
== DIEFT_CONSTANTFORCE
)
1604 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_ConstantForce
);
1605 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1606 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1609 if (type
== DIEFT_ALL
|| type
== DIEFT_RAMPFORCE
)
1611 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_RampForce
);
1612 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1613 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1616 if (type
== DIEFT_ALL
|| type
== DIEFT_PERIODIC
)
1618 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Square
);
1619 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1620 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1622 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Sine
);
1623 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1624 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1626 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Triangle
);
1627 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1628 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1630 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_SawtoothUp
);
1631 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1632 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1634 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_SawtoothDown
);
1635 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1636 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1639 if (type
== DIEFT_ALL
|| type
== DIEFT_CONDITION
)
1641 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Spring
);
1642 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1643 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1645 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Damper
);
1646 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1647 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1649 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Inertia
);
1650 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1651 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1653 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Friction
);
1654 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1655 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1661 static HRESULT WINAPI
dinput_device_GetEffectInfo( IDirectInputDevice8W
*iface
, DIEFFECTINFOW
*info
,
1664 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1666 TRACE( "iface %p, info %p, guid %s.\n", iface
, info
, debugstr_guid( guid
) );
1668 if (!info
) return E_POINTER
;
1669 if (info
->dwSize
!= sizeof(DIEFFECTINFOW
)) return DIERR_INVALIDPARAM
;
1670 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_DEVICENOTREG
;
1671 if (!impl
->vtbl
->get_effect_info
) return DIERR_UNSUPPORTED
;
1672 return impl
->vtbl
->get_effect_info( iface
, info
, guid
);
1675 static HRESULT WINAPI
dinput_device_GetForceFeedbackState( IDirectInputDevice8W
*iface
, DWORD
*out
)
1677 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1680 TRACE( "iface %p, out %p.\n", iface
, out
);
1682 if (!out
) return E_POINTER
;
1685 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1687 EnterCriticalSection( &impl
->crit
);
1688 if (!is_exclusively_acquired( impl
)) hr
= DIERR_NOTEXCLUSIVEACQUIRED
;
1689 else *out
= impl
->force_feedback_state
;
1690 LeaveCriticalSection( &impl
->crit
);
1695 static HRESULT WINAPI
dinput_device_SendForceFeedbackCommand( IDirectInputDevice8W
*iface
, DWORD command
)
1697 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1700 TRACE( "iface %p, command %#lx.\n", iface
, command
);
1704 case DISFFC_RESET
: break;
1705 case DISFFC_STOPALL
: break;
1706 case DISFFC_PAUSE
: break;
1707 case DISFFC_CONTINUE
: break;
1708 case DISFFC_SETACTUATORSON
: break;
1709 case DISFFC_SETACTUATORSOFF
: break;
1710 default: return DIERR_INVALIDPARAM
;
1713 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1714 if (!impl
->vtbl
->send_force_feedback_command
) return DIERR_UNSUPPORTED
;
1716 EnterCriticalSection( &impl
->crit
);
1717 if (!is_exclusively_acquired( impl
)) hr
= DIERR_NOTEXCLUSIVEACQUIRED
;
1718 else hr
= impl
->vtbl
->send_force_feedback_command( iface
, command
, FALSE
);
1719 LeaveCriticalSection( &impl
->crit
);
1724 static HRESULT WINAPI
dinput_device_EnumCreatedEffectObjects( IDirectInputDevice8W
*iface
,
1725 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK callback
,
1726 void *context
, DWORD flags
)
1728 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1730 TRACE( "iface %p, callback %p, context %p, flags %#lx.\n", iface
, callback
, context
, flags
);
1732 if (!callback
) return DIERR_INVALIDPARAM
;
1733 if (flags
) return DIERR_INVALIDPARAM
;
1734 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DI_OK
;
1735 if (!impl
->vtbl
->enum_created_effect_objects
) return DIERR_UNSUPPORTED
;
1737 return impl
->vtbl
->enum_created_effect_objects( iface
, callback
, context
, flags
);
1740 static HRESULT WINAPI
dinput_device_Escape( IDirectInputDevice8W
*iface
, DIEFFESCAPE
*escape
)
1742 FIXME( "iface %p, escape %p stub!\n", iface
, escape
);
1746 static HRESULT WINAPI
dinput_device_Poll( IDirectInputDevice8W
*iface
)
1748 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1749 HRESULT hr
= DI_NOEFFECT
;
1751 EnterCriticalSection( &impl
->crit
);
1752 if (impl
->status
== STATUS_UNPLUGGED
) hr
= DIERR_INPUTLOST
;
1753 else if (impl
->status
!= STATUS_ACQUIRED
) hr
= DIERR_NOTACQUIRED
;
1754 LeaveCriticalSection( &impl
->crit
);
1755 if (FAILED(hr
)) return hr
;
1757 if (impl
->vtbl
->poll
) return impl
->vtbl
->poll( iface
);
1761 static HRESULT WINAPI
dinput_device_SendDeviceData( IDirectInputDevice8W
*iface
, DWORD size
,
1762 const DIDEVICEOBJECTDATA
*data
, DWORD
*count
, DWORD flags
)
1764 FIXME( "iface %p, size %lu, data %p, count %p, flags %#lx stub!\n", iface
, size
, data
, count
, flags
);
1768 static HRESULT WINAPI
dinput_device_EnumEffectsInFile( IDirectInputDevice8W
*iface
, const WCHAR
*filename
,
1769 LPDIENUMEFFECTSINFILECALLBACK callback
,
1770 void *context
, DWORD flags
)
1772 FIXME( "iface %p, filename %s, callback %p, context %p, flags %#lx stub!\n", iface
,
1773 debugstr_w(filename
), callback
, context
, flags
);
1777 static HRESULT WINAPI
dinput_device_WriteEffectToFile( IDirectInputDevice8W
*iface
, const WCHAR
*filename
,
1778 DWORD count
, DIFILEEFFECT
*effects
, DWORD flags
)
1780 FIXME( "iface %p, filename %s, count %lu, effects %p, flags %#lx stub!\n", iface
,
1781 debugstr_w(filename
), count
, effects
, flags
);
1785 BOOL
device_object_matches_semantic( const DIDEVICEINSTANCEW
*instance
, const DIOBJECTDATAFORMAT
*object
,
1786 DWORD semantic
, BOOL exact
)
1788 DWORD value
= semantic
& 0xff, axis
= (semantic
>> 15) & 3, type
;
1790 switch (semantic
& 0x700)
1792 case 0x200: type
= DIDFT_ABSAXIS
; break;
1793 case 0x300: type
= DIDFT_RELAXIS
; break;
1794 case 0x400: type
= DIDFT_BUTTON
; break;
1795 case 0x600: type
= DIDFT_POV
; break;
1796 default: return FALSE
;
1799 if (!(DIDFT_GETTYPE( object
->dwType
) & type
)) return FALSE
;
1800 if ((semantic
& 0xf0000000) == 0x80000000)
1802 switch (semantic
& 0x0f000000)
1804 case 0x01000000: return (instance
->dwDevType
& 0xf) == DIDEVTYPE_KEYBOARD
&& object
->dwOfs
== value
;
1805 case 0x02000000: return (instance
->dwDevType
& 0xf) == DIDEVTYPE_MOUSE
&& object
->dwOfs
== value
;
1806 default: return FALSE
;
1809 if (axis
&& (axis
- 1) != DIDFT_GETINSTANCE( object
->dwType
)) return FALSE
;
1810 return !exact
|| !value
|| value
== DIDFT_GETINSTANCE( object
->dwType
) + 1;
1813 static HRESULT WINAPI
dinput_device_BuildActionMap( IDirectInputDevice8W
*iface
, DIACTIONFORMATW
*format
,
1814 const WCHAR
*username
, DWORD flags
)
1816 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1817 DIOBJECTDATAFORMAT
*object
, *object_end
;
1818 DIACTIONW
*action
, *action_end
;
1819 DWORD i
, username_len
= MAX_PATH
;
1820 WCHAR username_buf
[MAX_PATH
];
1823 TRACE( "iface %p, format %p, username %s, flags %#lx\n", iface
, format
,
1824 debugstr_w(username
), flags
);
1826 if (!format
) return DIERR_INVALIDPARAM
;
1827 if (flags
!= DIDBAM_DEFAULT
&& flags
!= DIDBAM_PRESERVE
&&
1828 flags
!= DIDBAM_INITIALIZE
&& flags
!= DIDBAM_HWDEFAULTS
)
1829 return DIERR_INVALIDPARAM
;
1830 if (format
->dwNumActions
* 4 != format
->dwDataSize
)
1831 return DIERR_INVALIDPARAM
;
1833 TRACE( "format guid %s, genre %#lx, name %s\n", debugstr_guid(&format
->guidActionMap
),
1834 format
->dwGenre
, debugstr_w(format
->tszActionMap
) );
1835 for (i
= 0; i
< format
->dwNumActions
; i
++)
1837 DIACTIONW
*action
= format
->rgoAction
+ i
;
1838 TRACE( " %lu: app_data %#Ix, semantic %#lx, flags %#lx, instance %s, obj_id %#lx, how %#lx, name %s\n",
1839 i
, action
->uAppData
, action
->dwSemantic
, action
->dwFlags
, debugstr_guid(&action
->guidInstance
),
1840 action
->dwObjID
, action
->dwHow
, debugstr_w(action
->lptszActionName
) );
1843 action_end
= format
->rgoAction
+ format
->dwNumActions
;
1844 for (action
= format
->rgoAction
; action
< action_end
; action
++)
1846 if (!action
->dwSemantic
) return DIERR_INVALIDPARAM
;
1847 if (flags
== DIDBAM_PRESERVE
&& !IsEqualCLSID( &action
->guidInstance
, &GUID_NULL
) &&
1848 !IsEqualCLSID( &action
->guidInstance
, &impl
->guid
)) continue;
1849 if (action
->dwFlags
& DIA_APPMAPPED
) action
->dwHow
= DIAH_APPREQUESTED
;
1850 else action
->dwHow
= 0;
1851 if (action
->dwHow
== DIAH_APPREQUESTED
|| action
->dwHow
== DIAH_USERCONFIG
) continue;
1852 if ((action
->dwSemantic
& 0xf0000000) == 0x80000000) action
->dwFlags
&= ~DIA_APPNOMAP
;
1853 if (!(action
->dwFlags
& DIA_APPNOMAP
)) action
->guidInstance
= GUID_NULL
;
1856 /* Unless asked the contrary by these flags, try to load a previous mapping */
1857 if (!(flags
& DIDBAM_HWDEFAULTS
))
1859 /* Retrieve logged user name if necessary */
1860 if (username
== NULL
) GetUserNameW( username_buf
, &username_len
);
1861 else lstrcpynW( username_buf
, username
, MAX_PATH
);
1862 load_mapping_settings( impl
, format
, username_buf
);
1865 if (!(mapped
= calloc( impl
->device_format
.dwNumObjs
, sizeof(*mapped
) ))) return DIERR_OUTOFMEMORY
;
1867 /* check already mapped objects */
1868 action_end
= format
->rgoAction
+ format
->dwNumActions
;
1869 for (action
= format
->rgoAction
; action
< action_end
; action
++)
1871 if (!action
->dwHow
|| !action
->dwObjID
) continue;
1872 if (!IsEqualGUID(&action
->guidInstance
, &impl
->guid
)) continue;
1874 object_end
= impl
->device_format
.rgodf
+ impl
->device_format
.dwNumObjs
;
1875 for (object
= impl
->device_format
.rgodf
; object
< object_end
; object
++)
1877 if (action
->dwObjID
!= object
->dwType
) continue;
1878 mapped
[object
- impl
->device_format
.rgodf
] = TRUE
;
1883 /* map any unmapped priority 1 objects */
1884 action_end
= format
->rgoAction
+ format
->dwNumActions
;
1885 for (action
= format
->rgoAction
; action
< action_end
; action
++)
1887 if (action
->dwHow
|| (action
->dwFlags
& DIA_APPNOMAP
)) continue; /* already mapped */
1888 if (action
->dwSemantic
& 0x4000) continue; /* priority 1 */
1890 object_end
= impl
->device_format
.rgodf
+ impl
->device_format
.dwNumObjs
;
1891 for (object
= impl
->device_format
.rgodf
; object
< object_end
; object
++)
1893 if (mapped
[object
- impl
->device_format
.rgodf
]) continue;
1894 if (!device_object_matches_semantic( &impl
->instance
, object
, action
->dwSemantic
, TRUE
)) continue;
1895 if ((action
->dwFlags
& DIA_FORCEFEEDBACK
) && !(object
->dwType
& DIDFT_FFACTUATOR
)) continue;
1896 action
->dwObjID
= object
->dwType
;
1897 action
->guidInstance
= impl
->guid
;
1898 action
->dwHow
= DIAH_DEFAULT
;
1899 mapped
[object
- impl
->device_format
.rgodf
] = TRUE
;
1904 /* map any unmapped priority 2 objects */
1905 for (action
= format
->rgoAction
; action
< action_end
; action
++)
1907 if (action
->dwHow
|| (action
->dwFlags
& DIA_APPNOMAP
)) continue; /* already mapped */
1908 if (!(action
->dwSemantic
& 0x4000)) continue; /* priority 2 */
1910 object_end
= impl
->device_format
.rgodf
+ impl
->device_format
.dwNumObjs
;
1911 for (object
= impl
->device_format
.rgodf
; object
< object_end
; object
++)
1913 if (mapped
[object
- impl
->device_format
.rgodf
]) continue;
1914 if (!device_object_matches_semantic( &impl
->instance
, object
, action
->dwSemantic
, FALSE
)) continue;
1915 if ((action
->dwFlags
& DIA_FORCEFEEDBACK
) && !(object
->dwType
& DIDFT_FFACTUATOR
)) continue;
1916 action
->dwObjID
= object
->dwType
;
1917 action
->guidInstance
= impl
->guid
;
1918 action
->dwHow
= DIAH_DEFAULT
;
1919 mapped
[object
- impl
->device_format
.rgodf
] = TRUE
;
1924 for (i
= 0; i
< impl
->device_format
.dwNumObjs
; ++i
) if (mapped
[i
]) break;
1927 if (i
== impl
->device_format
.dwNumObjs
) return DI_NOEFFECT
;
1931 static BOOL
init_object_app_data( struct dinput_device
*device
, UINT index
, struct hid_value_caps
*caps
,
1932 const DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
1934 struct object_properties
*properties
;
1935 const DIACTIONFORMATW
*format
= data
;
1936 const DIACTIONW
*action
= format
->rgoAction
+ format
->dwNumActions
;
1938 if (index
== -1) return DIENUM_STOP
;
1939 if (instance
->wUsagePage
== HID_USAGE_PAGE_PID
) return DIENUM_CONTINUE
;
1941 properties
= device
->object_properties
+ index
;
1942 properties
->app_data
= 0;
1944 while (action
-- > format
->rgoAction
)
1946 if (action
->dwObjID
!= instance
->dwType
) continue;
1947 properties
->app_data
= action
->uAppData
;
1951 return DIENUM_CONTINUE
;
1954 static HRESULT WINAPI
dinput_device_SetActionMap( IDirectInputDevice8W
*iface
, DIACTIONFORMATW
*format
,
1955 const WCHAR
*username
, DWORD flags
)
1957 static const DIPROPHEADER filter
=
1959 .dwSize
= sizeof(filter
),
1960 .dwHeaderSize
= sizeof(filter
),
1961 .dwHow
= DIPH_DEVICE
,
1963 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1964 DIDATAFORMAT data_format
=
1966 .dwSize
= sizeof(DIDATAFORMAT
),
1967 .dwObjSize
= sizeof(DIOBJECTDATAFORMAT
),
1968 .dwFlags
= DIDF_RELAXIS
,
1970 DIPROPDWORD prop_buffer
=
1974 .dwHeaderSize
= sizeof(DIPROPHEADER
),
1975 .dwSize
= sizeof(DIPROPDWORD
),
1976 .dwHow
= DIPH_DEVICE
,
1979 DIPROPRANGE prop_range
=
1983 .dwHeaderSize
= sizeof(DIPROPHEADER
),
1984 .dwSize
= sizeof(DIPROPRANGE
),
1985 .dwHow
= DIPH_DEVICE
,
1988 DIPROPSTRING prop_username
=
1992 .dwHeaderSize
= sizeof(DIPROPHEADER
),
1993 .dwSize
= sizeof(DIPROPSTRING
),
1994 .dwHow
= DIPH_DEVICE
,
1997 WCHAR username_buf
[MAX_PATH
];
1998 DWORD username_len
= MAX_PATH
;
1999 unsigned int offset
= 0;
2003 TRACE( "iface %p, format %p, username %s, flags %#lx\n", iface
, format
,
2004 debugstr_w(username
), flags
);
2006 if (!format
) return DIERR_INVALIDPARAM
;
2007 if (flags
!= DIDSAM_DEFAULT
&& flags
!= DIDSAM_FORCESAVE
&& flags
!= DIDSAM_NOUSER
) return DIERR_INVALIDPARAM
;
2009 TRACE( "format guid %s, genre %#lx, name %s\n", debugstr_guid(&format
->guidActionMap
),
2010 format
->dwGenre
, debugstr_w(format
->tszActionMap
) );
2011 for (i
= 0; i
< format
->dwNumActions
; i
++)
2013 DIACTIONW
*action
= format
->rgoAction
+ i
;
2014 TRACE( " %u: app_data %#Ix, semantic %#lx, flags %#lx, instance %s, obj_id %#lx, how %#lx, name %s\n",
2015 i
, action
->uAppData
, action
->dwSemantic
, action
->dwFlags
, debugstr_guid(&action
->guidInstance
),
2016 action
->dwObjID
, action
->dwHow
, debugstr_w(action
->lptszActionName
) );
2019 if (!(data_format
.rgodf
= malloc( sizeof(DIOBJECTDATAFORMAT
) * format
->dwNumActions
))) return DIERR_OUTOFMEMORY
;
2020 data_format
.dwDataSize
= format
->dwDataSize
;
2022 for (i
= 0; i
< format
->dwNumActions
; i
++, offset
+= sizeof(ULONG
))
2024 if (format
->rgoAction
[i
].dwFlags
& DIA_APPNOMAP
) continue;
2025 if (!IsEqualGUID( &impl
->guid
, &format
->rgoAction
[i
].guidInstance
)) continue;
2026 if ((index
= dinput_device_object_index_from_id( iface
, format
->rgoAction
[i
].dwObjID
)) < 0) continue;
2028 data_format
.rgodf
[data_format
.dwNumObjs
] = impl
->device_format
.rgodf
[index
];
2029 data_format
.rgodf
[data_format
.dwNumObjs
].dwOfs
= offset
;
2030 data_format
.dwNumObjs
++;
2033 EnterCriticalSection( &impl
->crit
);
2035 if (FAILED(hr
= IDirectInputDevice8_SetDataFormat( iface
, &data_format
)))
2036 WARN( "Failed to set data format from action map, hr %#lx\n", hr
);
2039 if (FAILED(impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_ALL
, init_object_app_data
, format
)))
2040 WARN( "Failed to initialize action map app data\n" );
2042 if (format
->lAxisMin
!= format
->lAxisMax
)
2044 prop_range
.lMin
= format
->lAxisMin
;
2045 prop_range
.lMax
= format
->lAxisMax
;
2046 IDirectInputDevice8_SetProperty( iface
, DIPROP_RANGE
, &prop_range
.diph
);
2049 prop_buffer
.dwData
= format
->dwBufferSize
;
2050 IDirectInputDevice8_SetProperty( iface
, DIPROP_BUFFERSIZE
, &prop_buffer
.diph
);
2052 if (username
== NULL
) GetUserNameW( username_buf
, &username_len
);
2053 else lstrcpynW( username_buf
, username
, MAX_PATH
);
2055 if (flags
& DIDSAM_NOUSER
) prop_username
.wsz
[0] = '\0';
2056 else lstrcpynW( prop_username
.wsz
, username_buf
, ARRAY_SIZE(prop_username
.wsz
) );
2057 dinput_device_set_username( impl
, &prop_username
);
2059 save_mapping_settings( iface
, format
, username_buf
);
2062 LeaveCriticalSection( &impl
->crit
);
2064 free( data_format
.rgodf
);
2066 if (FAILED(hr
)) return hr
;
2067 if (flags
== DIDSAM_FORCESAVE
) return DI_SETTINGSNOTSAVED
;
2068 if (!data_format
.dwNumObjs
) return DI_NOEFFECT
;
2072 static HRESULT WINAPI
dinput_device_GetImageInfo( IDirectInputDevice8W
*iface
, DIDEVICEIMAGEINFOHEADERW
*header
)
2074 FIXME( "iface %p, header %p stub!\n", iface
, header
);
2078 extern const IDirectInputDevice8AVtbl dinput_device_a_vtbl
;
2079 static const IDirectInputDevice8WVtbl dinput_device_w_vtbl
=
2081 /*** IUnknown methods ***/
2082 dinput_device_QueryInterface
,
2083 dinput_device_AddRef
,
2084 dinput_device_Release
,
2085 /*** IDirectInputDevice methods ***/
2086 dinput_device_GetCapabilities
,
2087 dinput_device_EnumObjects
,
2088 dinput_device_GetProperty
,
2089 dinput_device_SetProperty
,
2090 dinput_device_Acquire
,
2091 dinput_device_Unacquire
,
2092 dinput_device_GetDeviceState
,
2093 dinput_device_GetDeviceData
,
2094 dinput_device_SetDataFormat
,
2095 dinput_device_SetEventNotification
,
2096 dinput_device_SetCooperativeLevel
,
2097 dinput_device_GetObjectInfo
,
2098 dinput_device_GetDeviceInfo
,
2099 dinput_device_RunControlPanel
,
2100 dinput_device_Initialize
,
2101 /*** IDirectInputDevice2 methods ***/
2102 dinput_device_CreateEffect
,
2103 dinput_device_EnumEffects
,
2104 dinput_device_GetEffectInfo
,
2105 dinput_device_GetForceFeedbackState
,
2106 dinput_device_SendForceFeedbackCommand
,
2107 dinput_device_EnumCreatedEffectObjects
,
2108 dinput_device_Escape
,
2110 dinput_device_SendDeviceData
,
2111 /*** IDirectInputDevice7 methods ***/
2112 dinput_device_EnumEffectsInFile
,
2113 dinput_device_WriteEffectToFile
,
2114 /*** IDirectInputDevice8 methods ***/
2115 dinput_device_BuildActionMap
,
2116 dinput_device_SetActionMap
,
2117 dinput_device_GetImageInfo
,
2120 void dinput_device_init( struct dinput_device
*device
, const struct dinput_device_vtbl
*vtbl
,
2121 const GUID
*guid
, struct dinput
*dinput
)
2123 device
->IDirectInputDevice8A_iface
.lpVtbl
= &dinput_device_a_vtbl
;
2124 device
->IDirectInputDevice8W_iface
.lpVtbl
= &dinput_device_w_vtbl
;
2125 device
->internal_ref
= 1;
2127 device
->guid
= *guid
;
2128 device
->instance
.dwSize
= sizeof(DIDEVICEINSTANCEW
);
2129 device
->caps
.dwSize
= sizeof(DIDEVCAPS
);
2130 device
->caps
.dwFlags
= DIDC_ATTACHED
| DIDC_EMULATED
;
2131 device
->device_gain
= 10000;
2132 device
->autocenter
= DIPROPAUTOCENTER_ON
;
2133 device
->force_feedback_state
= DIGFFS_STOPPED
| DIGFFS_EMPTY
;
2134 InitializeCriticalSectionEx( &device
->crit
, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO
);
2135 dinput_internal_addref( (device
->dinput
= dinput
) );
2136 device
->vtbl
= vtbl
;
2138 input_thread_add_user();
2141 static const GUID
*object_instance_guid( const DIDEVICEOBJECTINSTANCEW
*instance
)
2143 if (IsEqualGUID( &instance
->guidType
, &GUID_XAxis
)) return &GUID_XAxis
;
2144 if (IsEqualGUID( &instance
->guidType
, &GUID_YAxis
)) return &GUID_YAxis
;
2145 if (IsEqualGUID( &instance
->guidType
, &GUID_ZAxis
)) return &GUID_ZAxis
;
2146 if (IsEqualGUID( &instance
->guidType
, &GUID_RxAxis
)) return &GUID_RxAxis
;
2147 if (IsEqualGUID( &instance
->guidType
, &GUID_RyAxis
)) return &GUID_RyAxis
;
2148 if (IsEqualGUID( &instance
->guidType
, &GUID_RzAxis
)) return &GUID_RzAxis
;
2149 if (IsEqualGUID( &instance
->guidType
, &GUID_Slider
)) return &GUID_Slider
;
2150 if (IsEqualGUID( &instance
->guidType
, &GUID_Button
)) return &GUID_Button
;
2151 if (IsEqualGUID( &instance
->guidType
, &GUID_Key
)) return &GUID_Key
;
2152 if (IsEqualGUID( &instance
->guidType
, &GUID_POV
)) return &GUID_POV
;
2153 return &GUID_Unknown
;
2156 static BOOL
enum_objects_count( struct dinput_device
*impl
, UINT index
, struct hid_value_caps
*caps
,
2157 const DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
2159 DIDATAFORMAT
*format
= &impl
->device_format
;
2161 if (index
== -1) return DIENUM_STOP
;
2162 format
->dwNumObjs
++;
2163 if (instance
->wUsagePage
== HID_USAGE_PAGE_PID
) return DIENUM_CONTINUE
;
2165 format
->dwDataSize
= max( format
->dwDataSize
, instance
->dwOfs
+ sizeof(LONG
) );
2166 if (instance
->dwType
& DIDFT_BUTTON
) impl
->caps
.dwButtons
++;
2167 if (instance
->dwType
& DIDFT_AXIS
) impl
->caps
.dwAxes
++;
2168 if (instance
->dwType
& DIDFT_POV
) impl
->caps
.dwPOVs
++;
2169 if (instance
->dwType
& (DIDFT_BUTTON
|DIDFT_AXIS
|DIDFT_POV
))
2171 if (!impl
->device_state_report_id
)
2172 impl
->device_state_report_id
= instance
->wReportId
;
2173 else if (impl
->device_state_report_id
!= instance
->wReportId
)
2174 FIXME( "multiple device state reports found!\n" );
2177 return DIENUM_CONTINUE
;
2180 static BOOL
enum_objects_init( struct dinput_device
*impl
, UINT index
, struct hid_value_caps
*caps
,
2181 const DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
2183 static const struct object_properties default_properties
=
2185 .range_min
= DIPROPRANGE_NOMIN
,
2186 .range_max
= DIPROPRANGE_NOMAX
,
2190 DIDATAFORMAT
*format
= &impl
->device_format
;
2191 DIOBJECTDATAFORMAT
*object_format
;
2193 if (index
== -1) return DIENUM_STOP
;
2194 if (instance
->wUsagePage
== HID_USAGE_PAGE_PID
) return DIENUM_CONTINUE
;
2196 object_format
= format
->rgodf
+ index
;
2197 object_format
->pguid
= object_instance_guid( instance
);
2198 object_format
->dwOfs
= instance
->dwOfs
;
2199 object_format
->dwType
= instance
->dwType
;
2200 object_format
->dwFlags
= instance
->dwFlags
;
2202 impl
->object_properties
[index
] = default_properties
;
2203 if (instance
->dwType
& (DIDFT_AXIS
| DIDFT_POV
)) reset_object_value( impl
, index
, caps
, instance
, NULL
);
2205 return DIENUM_CONTINUE
;
2208 HRESULT
dinput_device_init_device_format( IDirectInputDevice8W
*iface
)
2210 static const DIPROPHEADER filter
=
2212 .dwSize
= sizeof(filter
),
2213 .dwHeaderSize
= sizeof(filter
),
2214 .dwHow
= DIPH_DEVICE
,
2216 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
2217 DIDATAFORMAT
*format
= &impl
->device_format
;
2221 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_ALL
, enum_objects_count
, NULL
);
2222 if (FAILED(hr
)) return hr
;
2224 if (format
->dwDataSize
> DEVICE_STATE_MAX_SIZE
)
2226 FIXME( "unable to create device, state is too large\n" );
2227 return DIERR_OUTOFMEMORY
;
2230 if (!(impl
->object_properties
= calloc( format
->dwNumObjs
, sizeof(*impl
->object_properties
) ))) return DIERR_OUTOFMEMORY
;
2231 if (!(format
->rgodf
= calloc( format
->dwNumObjs
, sizeof(*format
->rgodf
) ))) return DIERR_OUTOFMEMORY
;
2233 format
->dwSize
= sizeof(*format
);
2234 format
->dwObjSize
= sizeof(*format
->rgodf
);
2235 format
->dwFlags
= DIDF_ABSAXIS
;
2237 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_AXIS
, enum_objects_init
, NULL
);
2238 if (FAILED(hr
)) return hr
;
2239 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_POV
, enum_objects_init
, NULL
);
2240 if (FAILED(hr
)) return hr
;
2241 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_BUTTON
, enum_objects_init
, NULL
);
2242 if (FAILED(hr
)) return hr
;
2243 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_NODATA
, enum_objects_init
, NULL
);
2244 if (FAILED(hr
)) return hr
;
2246 if (TRACE_ON( dinput
))
2248 TRACE( "device format %s\n", debugstr_didataformat( format
) );
2249 for (i
= 0; i
< format
->dwNumObjs
; ++i
) TRACE( " %lu: object %s\n", i
, debugstr_diobjectdataformat( format
->rgodf
+ i
) );