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
22 /* This file contains all the Device specific functions that can be used as stubs
23 by real device implementations.
25 It also contains all the helper functions.
42 #include "device_private.h"
43 #include "dinput_private.h"
45 #include "wine/debug.h"
47 #define WM_WINE_NOTIFY_ACTIVITY WM_USER
49 WINE_DEFAULT_DEBUG_CHANNEL(dinput
);
51 /* Windows uses this GUID for guidProduct on non-keyboard/mouse devices.
52 * Data1 contains the device VID (low word) and PID (high word).
53 * Data4 ends with the ASCII bytes "PIDVID".
55 DEFINE_GUID( dinput_pidvid_guid
, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 'P', 'I', 'D', 'V', 'I', 'D' );
57 static inline struct dinput_device
*impl_from_IDirectInputDevice8W( IDirectInputDevice8W
*iface
)
59 return CONTAINING_RECORD( iface
, struct dinput_device
, IDirectInputDevice8W_iface
);
62 static inline IDirectInputDevice8A
*IDirectInputDevice8A_from_impl( struct dinput_device
*This
)
64 return &This
->IDirectInputDevice8A_iface
;
66 static inline IDirectInputDevice8W
*IDirectInputDevice8W_from_impl( struct dinput_device
*This
)
68 return &This
->IDirectInputDevice8W_iface
;
71 static inline const char *debugstr_didataformat( const DIDATAFORMAT
*data
)
73 if (!data
) return "(null)";
74 return wine_dbg_sprintf( "%p dwSize %lu, dwObjsize %lu, dwFlags %#lx, dwDataSize %lu, dwNumObjs %lu, rgodf %p",
75 data
, data
->dwSize
, data
->dwObjSize
, data
->dwFlags
, data
->dwDataSize
, data
->dwNumObjs
, data
->rgodf
);
78 static inline const char *debugstr_diobjectdataformat( const DIOBJECTDATAFORMAT
*data
)
80 if (!data
) return "(null)";
81 return wine_dbg_sprintf( "%p pguid %s, dwOfs %#lx, dwType %#lx, dwFlags %#lx", data
,
82 debugstr_guid( data
->pguid
), data
->dwOfs
, data
->dwType
, data
->dwFlags
);
85 static inline BOOL
is_exclusively_acquired( struct dinput_device
*device
)
87 return device
->status
== STATUS_ACQUIRED
&& (device
->dwCoopLevel
& DISCL_EXCLUSIVE
);
90 /******************************************************************************
91 * Various debugging tools
93 static void _dump_cooperativelevel_DI(DWORD dwFlags
) {
94 if (TRACE_ON(dinput
)) {
100 #define FE(x) { x, #x}
101 FE(DISCL_BACKGROUND
),
103 FE(DISCL_FOREGROUND
),
104 FE(DISCL_NONEXCLUSIVE
),
108 TRACE(" cooperative level : ");
109 for (i
= 0; i
< ARRAY_SIZE(flags
); i
++)
110 if (flags
[i
].mask
& dwFlags
)
111 TRACE("%s ",flags
[i
].name
);
116 /******************************************************************************
117 * Get the default and the app-specific config keys.
119 BOOL
get_app_key(HKEY
*defkey
, HKEY
*appkey
)
121 char buffer
[MAX_PATH
+16];
126 /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */
127 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\DirectInput", defkey
))
130 len
= GetModuleFileNameA(0, buffer
, MAX_PATH
);
131 if (len
&& len
< MAX_PATH
)
135 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */
136 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\AppDefaults", &tmpkey
))
138 char *p
, *appname
= buffer
;
139 if ((p
= strrchr(appname
, '/'))) appname
= p
+ 1;
140 if ((p
= strrchr(appname
, '\\'))) appname
= p
+ 1;
141 strcat(appname
, "\\DirectInput");
143 if (RegOpenKeyA(tmpkey
, appname
, appkey
)) *appkey
= 0;
148 return *defkey
|| *appkey
;
151 /******************************************************************************
152 * Get a config key from either the app-specific or the default config
154 DWORD
get_config_key( HKEY defkey
, HKEY appkey
, const WCHAR
*name
, WCHAR
*buffer
, DWORD size
)
156 if (appkey
&& !RegQueryValueExW( appkey
, name
, 0, NULL
, (LPBYTE
)buffer
, &size
)) return 0;
158 if (defkey
&& !RegQueryValueExW( defkey
, name
, 0, NULL
, (LPBYTE
)buffer
, &size
)) return 0;
160 return ERROR_FILE_NOT_FOUND
;
163 BOOL
device_instance_is_disabled( DIDEVICEINSTANCEW
*instance
, BOOL
*override
)
165 static const WCHAR disabled_str
[] = {'d', 'i', 's', 'a', 'b', 'l', 'e', 'd', 0};
166 static const WCHAR override_str
[] = {'o', 'v', 'e', 'r', 'r', 'i', 'd', 'e', 0};
167 static const WCHAR joystick_key
[] = {'J', 'o', 'y', 's', 't', 'i', 'c', 'k', 's', 0};
168 WCHAR buffer
[MAX_PATH
];
169 HKEY hkey
, appkey
, temp
;
170 BOOL disable
= FALSE
;
172 get_app_key( &hkey
, &appkey
);
173 if (override
) *override
= FALSE
;
175 /* Joystick settings are in the 'joysticks' subkey */
178 if (RegOpenKeyW( appkey
, joystick_key
, &temp
)) temp
= 0;
179 RegCloseKey( appkey
);
185 if (RegOpenKeyW( hkey
, joystick_key
, &temp
)) temp
= 0;
190 /* Look for the "controllername"="disabled" key */
191 if (!get_config_key( hkey
, appkey
, instance
->tszInstanceName
, buffer
, sizeof(buffer
) ))
193 if (!wcscmp( disabled_str
, buffer
))
195 TRACE( "Disabling joystick '%s' based on registry key.\n", debugstr_w(instance
->tszInstanceName
) );
198 else if (override
&& !wcscmp( override_str
, buffer
))
200 TRACE( "Force enabling joystick '%s' based on registry key.\n", debugstr_w(instance
->tszInstanceName
) );
205 if (appkey
) RegCloseKey( appkey
);
206 if (hkey
) RegCloseKey( hkey
);
211 static void dinput_device_release_user_format( struct dinput_device
*impl
)
213 if (impl
->user_format
) free( impl
->user_format
->rgodf
);
214 free( impl
->user_format
);
215 impl
->user_format
= NULL
;
218 static inline LPDIOBJECTDATAFORMAT
dataformat_to_odf(LPCDIDATAFORMAT df
, int idx
)
220 if (idx
< 0 || idx
>= df
->dwNumObjs
) return NULL
;
221 return (LPDIOBJECTDATAFORMAT
)((LPBYTE
)df
->rgodf
+ idx
* df
->dwObjSize
);
224 /* dataformat_to_odf_by_type
225 * Find the Nth object of the selected type in the DataFormat
227 LPDIOBJECTDATAFORMAT
dataformat_to_odf_by_type(LPCDIDATAFORMAT df
, int n
, DWORD type
)
231 for (i
=0; i
< df
->dwNumObjs
; i
++)
233 LPDIOBJECTDATAFORMAT odf
= dataformat_to_odf(df
, i
);
235 if (odf
->dwType
& type
)
247 static BOOL
match_device_object( DIDATAFORMAT
*device_format
, DIDATAFORMAT
*user_format
,
248 const DIDATAFORMAT
*format
, const DIOBJECTDATAFORMAT
*match_obj
, DWORD version
)
250 DWORD i
, device_instance
, instance
= DIDFT_GETINSTANCE( match_obj
->dwType
);
251 DIOBJECTDATAFORMAT
*device_obj
, *user_obj
;
253 if (version
< 0x0700 && instance
== 0xff) instance
= 0xffff;
255 for (i
= 0; i
< device_format
->dwNumObjs
; i
++)
257 user_obj
= user_format
->rgodf
+ i
;
258 device_obj
= device_format
->rgodf
+ i
;
259 device_instance
= DIDFT_GETINSTANCE( device_obj
->dwType
);
261 if (!(user_obj
->dwType
& DIDFT_OPTIONAL
)) continue; /* already matched */
262 if (match_obj
->pguid
&& device_obj
->pguid
&& !IsEqualGUID( device_obj
->pguid
, match_obj
->pguid
)) continue;
263 if (instance
!= DIDFT_GETINSTANCE( DIDFT_ANYINSTANCE
) && instance
!= device_instance
) continue;
264 if (!(DIDFT_GETTYPE( match_obj
->dwType
) & DIDFT_GETTYPE( device_obj
->dwType
))) continue;
266 TRACE( "match %s with device %s\n", debugstr_diobjectdataformat( match_obj
),
267 debugstr_diobjectdataformat( device_obj
) );
269 *user_obj
= *device_obj
;
270 user_obj
->dwOfs
= match_obj
->dwOfs
;
277 static HRESULT
dinput_device_init_user_format( struct dinput_device
*impl
, const DIDATAFORMAT
*format
)
279 DIDATAFORMAT
*user_format
, *device_format
= impl
->device_format
;
280 DIOBJECTDATAFORMAT
*user_obj
, *match_obj
;
283 if (!device_format
) return DIERR_INVALIDPARAM
;
284 if (!(user_format
= malloc( sizeof(DIDATAFORMAT
) ))) return DIERR_OUTOFMEMORY
;
285 *user_format
= *device_format
;
286 user_format
->dwFlags
= format
->dwFlags
;
287 user_format
->dwDataSize
= format
->dwDataSize
;
288 user_format
->dwNumObjs
+= format
->dwNumObjs
;
289 if (!(user_format
->rgodf
= calloc( user_format
->dwNumObjs
, sizeof(DIOBJECTDATAFORMAT
) )))
292 return DIERR_OUTOFMEMORY
;
295 user_obj
= user_format
->rgodf
+ user_format
->dwNumObjs
;
296 while (user_obj
-- > user_format
->rgodf
) user_obj
->dwType
|= DIDFT_OPTIONAL
;
298 for (i
= 0; i
< format
->dwNumObjs
; ++i
)
300 match_obj
= format
->rgodf
+ i
;
302 if (!match_device_object( device_format
, user_format
, format
, match_obj
, impl
->dinput
->dwVersion
))
304 WARN( "object %s not found\n", debugstr_diobjectdataformat( match_obj
) );
305 if (!(match_obj
->dwType
& DIDFT_OPTIONAL
)) goto failed
;
306 user_obj
= user_format
->rgodf
+ device_format
->dwNumObjs
+ i
;
307 *user_obj
= *match_obj
;
311 user_obj
= user_format
->rgodf
+ user_format
->dwNumObjs
;
312 while (user_obj
-- > user_format
->rgodf
) user_obj
->dwType
&= ~DIDFT_OPTIONAL
;
314 impl
->user_format
= user_format
;
318 free( user_format
->rgodf
);
320 return DIERR_INVALIDPARAM
;
323 static int id_to_offset( struct dinput_device
*impl
, int id
)
325 DIDATAFORMAT
*device_format
= impl
->device_format
, *user_format
= impl
->user_format
;
326 DIOBJECTDATAFORMAT
*user_obj
;
328 if (!user_format
) return -1;
330 user_obj
= user_format
->rgodf
+ device_format
->dwNumObjs
;
331 while (user_obj
-- > user_format
->rgodf
)
333 if (!user_obj
->dwType
) continue;
334 if ((user_obj
->dwType
& 0x00ffffff) == (id
& 0x00ffffff)) return user_obj
->dwOfs
;
340 static DWORD
semantic_to_obj_id( struct dinput_device
*This
, DWORD dwSemantic
)
342 DWORD type
= (0x0000ff00 & dwSemantic
) >> 8;
343 BOOL byofs
= (dwSemantic
& 0x80000000) != 0;
344 DWORD value
= (dwSemantic
& 0x000000ff);
349 for (i
= 0; i
< This
->device_format
->dwNumObjs
&& !found
; i
++)
351 LPDIOBJECTDATAFORMAT odf
= dataformat_to_odf( This
->device_format
, i
);
353 if (byofs
&& value
!= odf
->dwOfs
) continue;
354 if (!byofs
&& value
!= DIDFT_GETINSTANCE(odf
->dwType
)) continue;
355 instance
= DIDFT_GETINSTANCE(odf
->dwType
);
359 if (!found
) return 0;
361 if (type
& DIDFT_AXIS
) type
= DIDFT_RELAXIS
;
362 if (type
& DIDFT_BUTTON
) type
= DIDFT_PSHBUTTON
;
364 return type
| (0x0000ff00 & (instance
<< 8));
369 * Retrieves an open registry key to save the mapping, parametrized for an username,
370 * specific device and specific action mapping guid.
372 static HKEY
get_mapping_key(const WCHAR
*device
, const WCHAR
*username
, const WCHAR
*guid
)
374 static const WCHAR
*subkey
= L
"Software\\Wine\\DirectInput\\Mappings\\%s\\%s\\%s";
378 SIZE_T len
= wcslen( subkey
) + wcslen( username
) + wcslen( device
) + wcslen( guid
) + 1;
379 keyname
= malloc( sizeof(WCHAR
) * len
);
380 swprintf( keyname
, len
, subkey
, username
, device
, guid
);
382 /* The key used is HKCU\Software\Wine\DirectInput\Mappings\[username]\[device]\[mapping_guid] */
383 if (RegCreateKeyW(HKEY_CURRENT_USER
, keyname
, &hkey
))
391 static HRESULT
save_mapping_settings(IDirectInputDevice8W
*iface
, LPDIACTIONFORMATW lpdiaf
, LPCWSTR lpszUsername
)
393 WCHAR
*guid_str
= NULL
;
394 DIDEVICEINSTANCEW didev
;
398 didev
.dwSize
= sizeof(didev
);
399 IDirectInputDevice8_GetDeviceInfo(iface
, &didev
);
401 if (StringFromCLSID(&lpdiaf
->guidActionMap
, &guid_str
) != S_OK
)
402 return DI_SETTINGSNOTSAVED
;
404 hkey
= get_mapping_key(didev
.tszInstanceName
, lpszUsername
, guid_str
);
408 CoTaskMemFree(guid_str
);
409 return DI_SETTINGSNOTSAVED
;
412 /* Write each of the actions mapped for this device.
413 Format is "dwSemantic"="dwObjID" and key is of type REG_DWORD
415 for (i
= 0; i
< lpdiaf
->dwNumActions
; i
++)
419 if (IsEqualGUID(&didev
.guidInstance
, &lpdiaf
->rgoAction
[i
].guidInstance
) &&
420 lpdiaf
->rgoAction
[i
].dwHow
!= DIAH_UNMAPPED
)
422 swprintf( label
, 9, L
"%x", lpdiaf
->rgoAction
[i
].dwSemantic
);
423 RegSetValueExW( hkey
, label
, 0, REG_DWORD
, (const BYTE
*)&lpdiaf
->rgoAction
[i
].dwObjID
,
429 CoTaskMemFree(guid_str
);
434 static BOOL
load_mapping_settings( struct dinput_device
*This
, LPDIACTIONFORMATW lpdiaf
, const WCHAR
*username
)
438 DIDEVICEINSTANCEW didev
;
441 didev
.dwSize
= sizeof(didev
);
442 IDirectInputDevice8_GetDeviceInfo(&This
->IDirectInputDevice8W_iface
, &didev
);
444 if (StringFromCLSID(&lpdiaf
->guidActionMap
, &guid_str
) != S_OK
)
447 hkey
= get_mapping_key(didev
.tszInstanceName
, username
, guid_str
);
451 CoTaskMemFree(guid_str
);
455 /* Try to read each action in the DIACTIONFORMAT from registry */
456 for (i
= 0; i
< lpdiaf
->dwNumActions
; i
++)
458 DWORD id
, size
= sizeof(DWORD
);
461 swprintf( label
, 9, L
"%x", lpdiaf
->rgoAction
[i
].dwSemantic
);
463 if (!RegQueryValueExW(hkey
, label
, 0, NULL
, (LPBYTE
) &id
, &size
))
465 lpdiaf
->rgoAction
[i
].dwObjID
= id
;
466 lpdiaf
->rgoAction
[i
].guidInstance
= didev
.guidInstance
;
467 lpdiaf
->rgoAction
[i
].dwHow
= DIAH_DEFAULT
;
473 CoTaskMemFree(guid_str
);
478 static BOOL
set_app_data( struct dinput_device
*dev
, int offset
, UINT_PTR app_data
)
480 int num_actions
= dev
->num_actions
;
481 ActionMap
*action_map
= dev
->action_map
, *target_map
= NULL
;
483 if (num_actions
== 0)
486 action_map
= malloc( sizeof(ActionMap
) );
487 if (!action_map
) return FALSE
;
488 target_map
= &action_map
[0];
493 for (i
= 0; i
< num_actions
; i
++)
495 if (dev
->action_map
[i
].offset
!= offset
) continue;
496 target_map
= &dev
->action_map
[i
];
503 action_map
= realloc( action_map
, sizeof(ActionMap
) * num_actions
);
504 if (!action_map
) return FALSE
;
505 target_map
= &action_map
[num_actions
-1];
509 target_map
->offset
= offset
;
510 target_map
->uAppData
= app_data
;
512 dev
->action_map
= action_map
;
513 dev
->num_actions
= num_actions
;
518 /******************************************************************************
519 * queue_event - add new event to the ring queue
522 void queue_event( IDirectInputDevice8W
*iface
, int inst_id
, DWORD data
, DWORD time
, DWORD seq
)
524 static ULONGLONG notify_ms
= 0;
525 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
526 int next_pos
, ofs
= id_to_offset( This
, inst_id
);
527 ULONGLONG time_ms
= GetTickCount64();
529 if (time_ms
- notify_ms
> 1000)
531 PostMessageW(GetDesktopWindow(), WM_WINE_NOTIFY_ACTIVITY
, 0, 0);
535 if (!This
->queue_len
|| This
->overflow
|| ofs
< 0) return;
537 next_pos
= (This
->queue_head
+ 1) % This
->queue_len
;
538 if (next_pos
== This
->queue_tail
)
540 TRACE(" queue overflowed\n");
541 This
->overflow
= TRUE
;
545 TRACE( " queueing %lu at offset %u (queue head %u / size %u)\n", data
, ofs
, This
->queue_head
, This
->queue_len
);
547 This
->data_queue
[This
->queue_head
].dwOfs
= ofs
;
548 This
->data_queue
[This
->queue_head
].dwData
= data
;
549 This
->data_queue
[This
->queue_head
].dwTimeStamp
= time
;
550 This
->data_queue
[This
->queue_head
].dwSequence
= seq
;
551 This
->data_queue
[This
->queue_head
].uAppData
= -1;
553 /* Set uAppData by means of action mapping */
554 if (This
->num_actions
> 0)
557 for (i
=0; i
< This
->num_actions
; i
++)
559 if (This
->action_map
[i
].offset
== ofs
)
561 TRACE( "Offset %d mapped to uAppData %#Ix\n", ofs
, This
->action_map
[i
].uAppData
);
562 This
->data_queue
[This
->queue_head
].uAppData
= This
->action_map
[i
].uAppData
;
568 This
->queue_head
= next_pos
;
569 /* Send event if asked */
572 /******************************************************************************
576 static HRESULT WINAPI
dinput_device_Acquire( IDirectInputDevice8W
*iface
)
578 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
581 TRACE( "iface %p.\n", iface
);
583 EnterCriticalSection( &impl
->crit
);
584 if (impl
->status
== STATUS_ACQUIRED
)
586 else if (!impl
->user_format
)
587 hr
= DIERR_INVALIDPARAM
;
588 else if ((impl
->dwCoopLevel
& DISCL_FOREGROUND
) && impl
->win
!= GetForegroundWindow())
589 hr
= DIERR_OTHERAPPHASPRIO
;
592 impl
->status
= STATUS_ACQUIRED
;
593 if (FAILED(hr
= impl
->vtbl
->acquire( iface
))) impl
->status
= STATUS_UNACQUIRED
;
595 LeaveCriticalSection( &impl
->crit
);
596 if (hr
!= DI_OK
) return hr
;
598 dinput_hooks_acquire_device( iface
);
599 check_dinput_hooks( iface
, TRUE
);
604 /******************************************************************************
608 static HRESULT WINAPI
dinput_device_Unacquire( IDirectInputDevice8W
*iface
)
610 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
613 TRACE( "iface %p.\n", iface
);
615 EnterCriticalSection( &impl
->crit
);
616 if (impl
->status
!= STATUS_ACQUIRED
) hr
= DI_NOEFFECT
;
617 else hr
= impl
->vtbl
->unacquire( iface
);
618 impl
->status
= STATUS_UNACQUIRED
;
619 LeaveCriticalSection( &impl
->crit
);
620 if (hr
!= DI_OK
) return hr
;
622 dinput_hooks_unacquire_device( iface
);
623 check_dinput_hooks( iface
, FALSE
);
628 /******************************************************************************
629 * IDirectInputDeviceA
632 static HRESULT WINAPI
dinput_device_SetDataFormat( IDirectInputDevice8W
*iface
, const DIDATAFORMAT
*format
)
634 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
638 TRACE( "iface %p, format %p.\n", iface
, format
);
640 if (!format
) return E_POINTER
;
641 if (TRACE_ON( dinput
))
643 TRACE( "user format %s\n", debugstr_didataformat( format
) );
644 for (i
= 0; i
< format
->dwNumObjs
; ++i
) TRACE( " %lu: object %s\n", i
, debugstr_diobjectdataformat( format
->rgodf
+ i
) );
647 if (format
->dwSize
!= sizeof(DIDATAFORMAT
)) return DIERR_INVALIDPARAM
;
648 if (format
->dwObjSize
!= sizeof(DIOBJECTDATAFORMAT
)) return DIERR_INVALIDPARAM
;
649 if (This
->status
== STATUS_ACQUIRED
) return DIERR_ACQUIRED
;
651 EnterCriticalSection(&This
->crit
);
653 free( This
->action_map
);
654 This
->action_map
= NULL
;
655 This
->num_actions
= 0;
657 dinput_device_release_user_format( This
);
658 res
= dinput_device_init_user_format( This
, format
);
660 LeaveCriticalSection(&This
->crit
);
664 /******************************************************************************
665 * SetCooperativeLevel
667 * Set cooperative level and the source window for the events.
669 static HRESULT WINAPI
dinput_device_SetCooperativeLevel( IDirectInputDevice8W
*iface
, HWND hwnd
, DWORD flags
)
671 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
674 TRACE( "iface %p, hwnd %p, flags %#lx.\n", iface
, hwnd
, flags
);
676 _dump_cooperativelevel_DI( flags
);
678 if ((flags
& (DISCL_EXCLUSIVE
| DISCL_NONEXCLUSIVE
)) == 0 ||
679 (flags
& (DISCL_EXCLUSIVE
| DISCL_NONEXCLUSIVE
)) == (DISCL_EXCLUSIVE
| DISCL_NONEXCLUSIVE
) ||
680 (flags
& (DISCL_FOREGROUND
| DISCL_BACKGROUND
)) == 0 ||
681 (flags
& (DISCL_FOREGROUND
| DISCL_BACKGROUND
)) == (DISCL_FOREGROUND
| DISCL_BACKGROUND
))
682 return DIERR_INVALIDPARAM
;
684 if (hwnd
&& GetWindowLongW(hwnd
, GWL_STYLE
) & WS_CHILD
) return E_HANDLE
;
686 if (!hwnd
&& flags
== (DISCL_NONEXCLUSIVE
| DISCL_BACKGROUND
)) hwnd
= GetDesktopWindow();
688 if (!IsWindow(hwnd
)) return E_HANDLE
;
690 /* For security reasons native does not allow exclusive background level
691 for mouse and keyboard only */
692 if (flags
& DISCL_EXCLUSIVE
&& flags
& DISCL_BACKGROUND
&&
693 (IsEqualGUID( &This
->guid
, &GUID_SysMouse
) || IsEqualGUID( &This
->guid
, &GUID_SysKeyboard
)))
694 return DIERR_UNSUPPORTED
;
696 /* Store the window which asks for the mouse */
697 EnterCriticalSection(&This
->crit
);
698 if (This
->status
== STATUS_ACQUIRED
) hr
= DIERR_ACQUIRED
;
702 This
->dwCoopLevel
= flags
;
705 LeaveCriticalSection(&This
->crit
);
710 static HRESULT WINAPI
dinput_device_GetDeviceInfo( IDirectInputDevice8W
*iface
, DIDEVICEINSTANCEW
*instance
)
712 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
715 TRACE( "iface %p, instance %p.\n", iface
, instance
);
717 if (!instance
) return E_POINTER
;
718 if (instance
->dwSize
!= sizeof(DIDEVICEINSTANCE_DX3W
) &&
719 instance
->dwSize
!= sizeof(DIDEVICEINSTANCEW
))
720 return DIERR_INVALIDPARAM
;
722 size
= instance
->dwSize
;
723 memcpy( instance
, &impl
->instance
, size
);
724 instance
->dwSize
= size
;
729 /******************************************************************************
730 * SetEventNotification : specifies event to be sent on state change
732 static HRESULT WINAPI
dinput_device_SetEventNotification( IDirectInputDevice8W
*iface
, HANDLE event
)
734 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
736 TRACE( "iface %p, event %p.\n", iface
, event
);
738 EnterCriticalSection(&This
->crit
);
739 This
->hEvent
= event
;
740 LeaveCriticalSection(&This
->crit
);
744 void dinput_device_destroy( IDirectInputDevice8W
*iface
)
746 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
748 TRACE( "iface %p.\n", iface
);
750 free( This
->object_properties
);
751 free( This
->data_queue
);
753 /* Free data format */
754 free( This
->device_format
->rgodf
);
755 free( This
->device_format
);
756 dinput_device_release_user_format( This
);
758 /* Free action mapping */
759 free( This
->action_map
);
761 IDirectInput_Release(&This
->dinput
->IDirectInput7A_iface
);
762 This
->crit
.DebugInfo
->Spare
[0] = 0;
763 DeleteCriticalSection(&This
->crit
);
768 static ULONG WINAPI
dinput_device_Release( IDirectInputDevice8W
*iface
)
770 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
771 ULONG ref
= InterlockedDecrement( &impl
->ref
);
773 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
777 IDirectInputDevice_Unacquire( iface
);
778 if (impl
->vtbl
->release
) impl
->vtbl
->release( iface
);
779 else dinput_device_destroy( iface
);
785 static HRESULT WINAPI
dinput_device_GetCapabilities( IDirectInputDevice8W
*iface
, DIDEVCAPS
*caps
)
787 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
790 TRACE( "iface %p, caps %p.\n", iface
, caps
);
792 if (!caps
) return E_POINTER
;
793 if (caps
->dwSize
!= sizeof(DIDEVCAPS_DX3
) &&
794 caps
->dwSize
!= sizeof(DIDEVCAPS
))
795 return DIERR_INVALIDPARAM
;
798 memcpy( caps
, &impl
->caps
, size
);
804 static HRESULT WINAPI
dinput_device_QueryInterface( IDirectInputDevice8W
*iface
, const GUID
*iid
, void **out
)
806 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
808 TRACE( "iface %p, iid %s, out %p.\n", iface
, debugstr_guid( iid
), out
);
810 if (IsEqualGUID( &IID_IDirectInputDeviceA
, iid
) ||
811 IsEqualGUID( &IID_IDirectInputDevice2A
, iid
) ||
812 IsEqualGUID( &IID_IDirectInputDevice7A
, iid
) ||
813 IsEqualGUID( &IID_IDirectInputDevice8A
, iid
))
815 IDirectInputDevice2_AddRef(iface
);
816 *out
= IDirectInputDevice8A_from_impl( This
);
820 if (IsEqualGUID( &IID_IUnknown
, iid
) ||
821 IsEqualGUID( &IID_IDirectInputDeviceW
, iid
) ||
822 IsEqualGUID( &IID_IDirectInputDevice2W
, iid
) ||
823 IsEqualGUID( &IID_IDirectInputDevice7W
, iid
) ||
824 IsEqualGUID( &IID_IDirectInputDevice8W
, iid
))
826 IDirectInputDevice2_AddRef(iface
);
827 *out
= IDirectInputDevice8W_from_impl( This
);
831 WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid
) );
832 return E_NOINTERFACE
;
835 static ULONG WINAPI
dinput_device_AddRef( IDirectInputDevice8W
*iface
)
837 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
838 ULONG ref
= InterlockedIncrement( &impl
->ref
);
839 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
843 static HRESULT WINAPI
dinput_device_EnumObjects( IDirectInputDevice8W
*iface
,
844 LPDIENUMDEVICEOBJECTSCALLBACKW callback
,
845 void *context
, DWORD flags
)
847 static const DIPROPHEADER filter
=
849 .dwSize
= sizeof(filter
),
850 .dwHeaderSize
= sizeof(filter
),
851 .dwHow
= DIPH_DEVICE
,
853 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
856 TRACE( "iface %p, callback %p, context %p, flags %#lx.\n", iface
, callback
, context
, flags
);
858 if (!callback
) return DIERR_INVALIDPARAM
;
859 if (flags
& ~(DIDFT_AXIS
| DIDFT_POV
| DIDFT_BUTTON
| DIDFT_NODATA
| DIDFT_COLLECTION
))
860 return DIERR_INVALIDPARAM
;
862 if (flags
== DIDFT_ALL
|| (flags
& DIDFT_AXIS
))
864 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_AXIS
, callback
, context
);
865 if (FAILED(hr
)) return hr
;
866 if (hr
!= DIENUM_CONTINUE
) return DI_OK
;
868 if (flags
== DIDFT_ALL
|| (flags
& DIDFT_POV
))
870 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_POV
, callback
, context
);
871 if (FAILED(hr
)) return hr
;
872 if (hr
!= DIENUM_CONTINUE
) return DI_OK
;
874 if (flags
== DIDFT_ALL
|| (flags
& DIDFT_BUTTON
))
876 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_BUTTON
, callback
, context
);
877 if (FAILED(hr
)) return hr
;
878 if (hr
!= DIENUM_CONTINUE
) return DI_OK
;
880 if (flags
== DIDFT_ALL
|| (flags
& (DIDFT_NODATA
| DIDFT_COLLECTION
)))
882 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_NODATA
, callback
, context
);
883 if (FAILED(hr
)) return hr
;
884 if (hr
!= DIENUM_CONTINUE
) return DI_OK
;
890 static HRESULT
enum_object_filter_init( struct dinput_device
*impl
, DIPROPHEADER
*filter
)
892 DIDATAFORMAT
*device_format
= impl
->device_format
, *user_format
= impl
->user_format
;
893 DIOBJECTDATAFORMAT
*device_obj
, *user_obj
;
895 if (filter
->dwHow
> DIPH_BYUSAGE
) return DIERR_INVALIDPARAM
;
896 if (filter
->dwHow
== DIPH_BYUSAGE
&& !(impl
->instance
.dwDevType
& DIDEVTYPE_HID
)) return DIERR_UNSUPPORTED
;
897 if (filter
->dwHow
!= DIPH_BYOFFSET
) return DI_OK
;
899 if (!impl
->user_format
) return DIERR_NOTFOUND
;
901 user_obj
= user_format
->rgodf
+ device_format
->dwNumObjs
;
902 device_obj
= device_format
->rgodf
+ device_format
->dwNumObjs
;
903 while (user_obj
-- > user_format
->rgodf
&& device_obj
-- > device_format
->rgodf
)
905 if (!user_obj
->dwType
) continue;
906 if (user_obj
->dwOfs
== filter
->dwObj
) break;
908 if (user_obj
< user_format
->rgodf
) return DIERR_NOTFOUND
;
910 filter
->dwObj
= device_obj
->dwOfs
;
914 static HRESULT
check_property( struct dinput_device
*impl
, const GUID
*guid
, const DIPROPHEADER
*header
, BOOL set
)
916 switch (LOWORD( guid
))
918 case (DWORD_PTR
)DIPROP_VIDPID
:
919 case (DWORD_PTR
)DIPROP_TYPENAME
:
920 case (DWORD_PTR
)DIPROP_USERNAME
:
921 case (DWORD_PTR
)DIPROP_KEYNAME
:
922 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
923 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
924 case (DWORD_PTR
)DIPROP_APPDATA
:
925 if (impl
->dinput
->dwVersion
< 0x0800) return DIERR_UNSUPPORTED
;
929 switch (LOWORD( guid
))
931 case (DWORD_PTR
)DIPROP_INSTANCENAME
:
932 case (DWORD_PTR
)DIPROP_KEYNAME
:
933 case (DWORD_PTR
)DIPROP_PRODUCTNAME
:
934 case (DWORD_PTR
)DIPROP_TYPENAME
:
935 case (DWORD_PTR
)DIPROP_USERNAME
:
936 if (header
->dwSize
!= sizeof(DIPROPSTRING
)) return DIERR_INVALIDPARAM
;
939 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
940 case (DWORD_PTR
)DIPROP_AXISMODE
:
941 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
942 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
943 case (DWORD_PTR
)DIPROP_DEADZONE
:
944 case (DWORD_PTR
)DIPROP_FFGAIN
:
945 case (DWORD_PTR
)DIPROP_FFLOAD
:
946 case (DWORD_PTR
)DIPROP_GRANULARITY
:
947 case (DWORD_PTR
)DIPROP_JOYSTICKID
:
948 case (DWORD_PTR
)DIPROP_SATURATION
:
949 case (DWORD_PTR
)DIPROP_SCANCODE
:
950 case (DWORD_PTR
)DIPROP_VIDPID
:
951 if (header
->dwSize
!= sizeof(DIPROPDWORD
)) return DIERR_INVALIDPARAM
;
954 case (DWORD_PTR
)DIPROP_APPDATA
:
955 if (header
->dwSize
!= sizeof(DIPROPPOINTER
)) return DIERR_INVALIDPARAM
;
958 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
959 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
960 case (DWORD_PTR
)DIPROP_RANGE
:
961 if (header
->dwSize
!= sizeof(DIPROPRANGE
)) return DIERR_INVALIDPARAM
;
964 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
965 if (header
->dwSize
!= sizeof(DIPROPGUIDANDPATH
)) return DIERR_INVALIDPARAM
;
969 switch (LOWORD( guid
))
971 case (DWORD_PTR
)DIPROP_PRODUCTNAME
:
972 case (DWORD_PTR
)DIPROP_INSTANCENAME
:
973 case (DWORD_PTR
)DIPROP_VIDPID
:
974 case (DWORD_PTR
)DIPROP_JOYSTICKID
:
975 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
976 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
977 case (DWORD_PTR
)DIPROP_FFGAIN
:
978 case (DWORD_PTR
)DIPROP_TYPENAME
:
979 case (DWORD_PTR
)DIPROP_USERNAME
:
980 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
981 case (DWORD_PTR
)DIPROP_AXISMODE
:
982 case (DWORD_PTR
)DIPROP_FFLOAD
:
983 if (header
->dwHow
!= DIPH_DEVICE
) return DIERR_UNSUPPORTED
;
984 if (header
->dwObj
) return DIERR_INVALIDPARAM
;
987 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
988 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
989 case (DWORD_PTR
)DIPROP_RANGE
:
990 case (DWORD_PTR
)DIPROP_DEADZONE
:
991 case (DWORD_PTR
)DIPROP_SATURATION
:
992 case (DWORD_PTR
)DIPROP_GRANULARITY
:
993 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
994 if (header
->dwHow
== DIPH_DEVICE
&& !set
) return DIERR_UNSUPPORTED
;
997 case (DWORD_PTR
)DIPROP_KEYNAME
:
998 if (header
->dwHow
== DIPH_DEVICE
) return DIERR_INVALIDPARAM
;
1001 case (DWORD_PTR
)DIPROP_SCANCODE
:
1002 case (DWORD_PTR
)DIPROP_APPDATA
:
1003 if (header
->dwHow
== DIPH_DEVICE
) return DIERR_UNSUPPORTED
;
1009 switch (LOWORD( guid
))
1011 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
1012 if (impl
->status
== STATUS_ACQUIRED
&& !is_exclusively_acquired( impl
)) return DIERR_ACQUIRED
;
1014 case (DWORD_PTR
)DIPROP_AXISMODE
:
1015 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
1016 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
1017 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
1018 if (impl
->status
== STATUS_ACQUIRED
) return DIERR_ACQUIRED
;
1020 case (DWORD_PTR
)DIPROP_FFLOAD
:
1021 case (DWORD_PTR
)DIPROP_GRANULARITY
:
1022 case (DWORD_PTR
)DIPROP_VIDPID
:
1023 case (DWORD_PTR
)DIPROP_TYPENAME
:
1024 case (DWORD_PTR
)DIPROP_USERNAME
:
1025 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
1026 return DIERR_READONLY
;
1029 switch (LOWORD( guid
))
1031 case (DWORD_PTR
)DIPROP_RANGE
:
1033 const DIPROPRANGE
*value
= (const DIPROPRANGE
*)header
;
1034 if (value
->lMin
> value
->lMax
) return DIERR_INVALIDPARAM
;
1037 case (DWORD_PTR
)DIPROP_DEADZONE
:
1038 case (DWORD_PTR
)DIPROP_SATURATION
:
1039 case (DWORD_PTR
)DIPROP_FFGAIN
:
1041 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1042 if (value
->dwData
> 10000) return DIERR_INVALIDPARAM
;
1045 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
1046 case (DWORD_PTR
)DIPROP_AXISMODE
:
1047 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1049 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1050 if (value
->dwData
> 1) return DIERR_INVALIDPARAM
;
1053 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
1054 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
1055 return DIERR_UNSUPPORTED
;
1060 switch (LOWORD( guid
))
1062 case (DWORD_PTR
)DIPROP_RANGE
:
1063 case (DWORD_PTR
)DIPROP_GRANULARITY
:
1064 if (!impl
->caps
.dwAxes
) return DIERR_UNSUPPORTED
;
1067 case (DWORD_PTR
)DIPROP_KEYNAME
:
1068 /* not supported on the mouse */
1069 if (impl
->caps
.dwAxes
&& !(impl
->caps
.dwDevType
& DIDEVTYPE_HID
)) return DIERR_UNSUPPORTED
;
1072 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
1073 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
1074 case (DWORD_PTR
)DIPROP_DEADZONE
:
1075 case (DWORD_PTR
)DIPROP_SATURATION
:
1076 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1077 if (!impl
->object_properties
) return DIERR_UNSUPPORTED
;
1080 case (DWORD_PTR
)DIPROP_FFLOAD
:
1081 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1082 if (!is_exclusively_acquired( impl
)) return DIERR_NOTEXCLUSIVEACQUIRED
;
1084 case (DWORD_PTR
)DIPROP_PRODUCTNAME
:
1085 case (DWORD_PTR
)DIPROP_INSTANCENAME
:
1086 case (DWORD_PTR
)DIPROP_VIDPID
:
1087 case (DWORD_PTR
)DIPROP_JOYSTICKID
:
1088 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
1089 if (!impl
->vtbl
->get_property
) return DIERR_UNSUPPORTED
;
1097 static BOOL CALLBACK
find_object( const DIDEVICEOBJECTINSTANCEW
*instance
, void *context
)
1099 *(DIDEVICEOBJECTINSTANCEW
*)context
= *instance
;
1103 struct get_object_property_params
1105 IDirectInputDevice8W
*iface
;
1106 DIPROPHEADER
*header
;
1110 static BOOL CALLBACK
get_object_property( const DIDEVICEOBJECTINSTANCEW
*instance
, void *context
)
1112 static const struct object_properties default_properties
=
1114 .range_min
= DIPROPRANGE_NOMIN
,
1115 .range_max
= DIPROPRANGE_NOMAX
,
1117 struct get_object_property_params
*params
= context
;
1118 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( params
->iface
);
1119 const struct object_properties
*properties
= NULL
;
1121 if (!impl
->object_properties
) properties
= &default_properties
;
1122 else properties
= impl
->object_properties
+ instance
->dwOfs
/ sizeof(LONG
);
1124 switch (params
->property
)
1126 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
1128 DIPROPRANGE
*value
= (DIPROPRANGE
*)params
->header
;
1129 value
->lMin
= properties
->physical_min
;
1130 value
->lMax
= properties
->physical_max
;
1133 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
1135 DIPROPRANGE
*value
= (DIPROPRANGE
*)params
->header
;
1136 value
->lMin
= properties
->logical_min
;
1137 value
->lMax
= properties
->logical_max
;
1140 case (DWORD_PTR
)DIPROP_RANGE
:
1142 DIPROPRANGE
*value
= (DIPROPRANGE
*)params
->header
;
1143 value
->lMin
= properties
->range_min
;
1144 value
->lMax
= properties
->range_max
;
1147 case (DWORD_PTR
)DIPROP_DEADZONE
:
1149 DIPROPDWORD
*value
= (DIPROPDWORD
*)params
->header
;
1150 value
->dwData
= properties
->deadzone
;
1153 case (DWORD_PTR
)DIPROP_SATURATION
:
1155 DIPROPDWORD
*value
= (DIPROPDWORD
*)params
->header
;
1156 value
->dwData
= properties
->saturation
;
1159 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1161 DIPROPDWORD
*value
= (DIPROPDWORD
*)params
->header
;
1162 value
->dwData
= properties
->calibration_mode
;
1165 case (DWORD_PTR
)DIPROP_GRANULARITY
:
1167 DIPROPDWORD
*value
= (DIPROPDWORD
*)params
->header
;
1171 case (DWORD_PTR
)DIPROP_KEYNAME
:
1173 DIPROPSTRING
*value
= (DIPROPSTRING
*)params
->header
;
1174 lstrcpynW( value
->wsz
, instance
->tszName
, ARRAY_SIZE(value
->wsz
) );
1182 static HRESULT
dinput_device_get_property( IDirectInputDevice8W
*iface
, const GUID
*guid
, DIPROPHEADER
*header
)
1184 struct get_object_property_params params
= {.iface
= iface
, .header
= header
, .property
= LOWORD( guid
)};
1185 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1186 DWORD object_mask
= DIDFT_AXIS
| DIDFT_BUTTON
| DIDFT_POV
;
1187 DIPROPHEADER filter
;
1191 if (FAILED(hr
= enum_object_filter_init( impl
, &filter
))) return hr
;
1192 if (FAILED(hr
= check_property( impl
, guid
, header
, FALSE
))) return hr
;
1194 switch (LOWORD( guid
))
1196 case (DWORD_PTR
)DIPROP_PRODUCTNAME
:
1197 case (DWORD_PTR
)DIPROP_INSTANCENAME
:
1198 case (DWORD_PTR
)DIPROP_VIDPID
:
1199 case (DWORD_PTR
)DIPROP_JOYSTICKID
:
1200 case (DWORD_PTR
)DIPROP_GUIDANDPATH
:
1201 case (DWORD_PTR
)DIPROP_FFLOAD
:
1202 return impl
->vtbl
->get_property( iface
, LOWORD( guid
), header
, NULL
);
1204 case (DWORD_PTR
)DIPROP_RANGE
:
1205 case (DWORD_PTR
)DIPROP_PHYSICALRANGE
:
1206 case (DWORD_PTR
)DIPROP_LOGICALRANGE
:
1207 case (DWORD_PTR
)DIPROP_DEADZONE
:
1208 case (DWORD_PTR
)DIPROP_SATURATION
:
1209 case (DWORD_PTR
)DIPROP_GRANULARITY
:
1210 case (DWORD_PTR
)DIPROP_KEYNAME
:
1211 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1212 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, object_mask
, get_object_property
, ¶ms
);
1213 if (FAILED(hr
)) return hr
;
1214 if (hr
== DIENUM_CONTINUE
) return DIERR_NOTFOUND
;
1217 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
1219 DIPROPDWORD
*value
= (DIPROPDWORD
*)header
;
1220 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1221 value
->dwData
= impl
->autocenter
;
1224 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
1226 DIPROPDWORD
*value
= (DIPROPDWORD
*)header
;
1227 value
->dwData
= impl
->buffersize
;
1230 case (DWORD_PTR
)DIPROP_USERNAME
:
1232 DIPROPSTRING
*value
= (DIPROPSTRING
*)header
;
1233 struct DevicePlayer
*device_player
;
1234 LIST_FOR_EACH_ENTRY( device_player
, &impl
->dinput
->device_players
, struct DevicePlayer
, entry
)
1236 if (IsEqualGUID( &device_player
->instance_guid
, &impl
->guid
))
1238 if (!*device_player
->username
) break;
1239 lstrcpynW( value
->wsz
, device_player
->username
, ARRAY_SIZE(value
->wsz
) );
1245 case (DWORD_PTR
)DIPROP_FFGAIN
:
1247 DIPROPDWORD
*value
= (DIPROPDWORD
*)header
;
1248 value
->dwData
= impl
->device_gain
;
1251 case (DWORD_PTR
)DIPROP_CALIBRATION
:
1252 return DIERR_INVALIDPARAM
;
1254 FIXME( "Unknown property %s\n", debugstr_guid( guid
) );
1255 return DIERR_UNSUPPORTED
;
1261 static HRESULT WINAPI
dinput_device_GetProperty( IDirectInputDevice8W
*iface
, const GUID
*guid
, DIPROPHEADER
*header
)
1263 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1266 TRACE( "iface %p, guid %s, header %p\n", iface
, debugstr_guid( guid
), header
);
1268 if (!header
) return DIERR_INVALIDPARAM
;
1269 if (header
->dwHeaderSize
!= sizeof(DIPROPHEADER
)) return DIERR_INVALIDPARAM
;
1270 if (!IS_DIPROP( guid
)) return DI_OK
;
1272 EnterCriticalSection( &impl
->crit
);
1273 hr
= dinput_device_get_property( iface
, guid
, header
);
1274 LeaveCriticalSection( &impl
->crit
);
1279 struct set_object_property_params
1281 IDirectInputDevice8W
*iface
;
1282 const DIPROPHEADER
*header
;
1286 static BOOL CALLBACK
set_object_property( const DIDEVICEOBJECTINSTANCEW
*instance
, void *context
)
1288 struct set_object_property_params
*params
= context
;
1289 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( params
->iface
);
1290 struct object_properties
*properties
= NULL
;
1292 if (!impl
->object_properties
) return DIENUM_STOP
;
1293 properties
= impl
->object_properties
+ instance
->dwOfs
/ sizeof(LONG
);
1295 switch (params
->property
)
1297 case (DWORD_PTR
)DIPROP_RANGE
:
1299 const DIPROPRANGE
*value
= (const DIPROPRANGE
*)params
->header
;
1300 properties
->range_min
= value
->lMin
;
1301 properties
->range_max
= value
->lMax
;
1302 return DIENUM_CONTINUE
;
1304 case (DWORD_PTR
)DIPROP_DEADZONE
:
1306 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)params
->header
;
1307 properties
->deadzone
= value
->dwData
;
1308 return DIENUM_CONTINUE
;
1310 case (DWORD_PTR
)DIPROP_SATURATION
:
1312 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)params
->header
;
1313 properties
->saturation
= value
->dwData
;
1314 return DIENUM_CONTINUE
;
1316 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1318 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)params
->header
;
1319 properties
->calibration_mode
= value
->dwData
;
1320 return DIENUM_CONTINUE
;
1327 static BOOL CALLBACK
reset_object_value( const DIDEVICEOBJECTINSTANCEW
*instance
, void *context
)
1329 struct dinput_device
*impl
= context
;
1330 struct object_properties
*properties
;
1333 if (!impl
->object_properties
) return DIENUM_STOP
;
1334 properties
= impl
->object_properties
+ instance
->dwOfs
/ sizeof(LONG
);
1336 if (instance
->dwType
& DIDFT_AXIS
)
1338 if (!properties
->range_min
) tmp
= properties
->range_max
/ 2;
1339 else tmp
= round( (properties
->range_min
+ properties
->range_max
) / 2.0 );
1342 *(LONG
*)(impl
->device_state
+ instance
->dwOfs
) = tmp
;
1343 return DIENUM_CONTINUE
;
1346 static void reset_device_state( IDirectInputDevice8W
*iface
)
1348 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1349 DIPROPHEADER filter
=
1351 .dwHeaderSize
= sizeof(DIPROPHEADER
),
1352 .dwSize
= sizeof(DIPROPHEADER
),
1353 .dwHow
= DIPH_DEVICE
,
1357 impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_AXIS
| DIDFT_POV
, reset_object_value
, impl
);
1360 static HRESULT WINAPI
dinput_device_set_property( IDirectInputDevice8W
*iface
, const GUID
*guid
,
1361 const DIPROPHEADER
*header
)
1363 struct set_object_property_params params
= {.iface
= iface
, .header
= header
, .property
= LOWORD( guid
)};
1364 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1365 DWORD object_mask
= DIDFT_AXIS
| DIDFT_BUTTON
| DIDFT_POV
;
1366 DIDEVICEOBJECTINSTANCEW instance
;
1367 DIPROPHEADER filter
;
1371 if (FAILED(hr
= enum_object_filter_init( impl
, &filter
))) return hr
;
1372 if (FAILED(hr
= check_property( impl
, guid
, header
, TRUE
))) return hr
;
1374 switch (LOWORD( guid
))
1376 case (DWORD_PTR
)DIPROP_RANGE
:
1377 case (DWORD_PTR
)DIPROP_DEADZONE
:
1378 case (DWORD_PTR
)DIPROP_SATURATION
:
1380 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_AXIS
, set_object_property
, ¶ms
);
1381 if (FAILED(hr
)) return hr
;
1382 reset_device_state( iface
);
1385 case (DWORD_PTR
)DIPROP_CALIBRATIONMODE
:
1387 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1388 if (value
->dwData
> DIPROPCALIBRATIONMODE_RAW
) return DIERR_INVALIDPARAM
;
1389 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_AXIS
, set_object_property
, ¶ms
);
1390 if (FAILED(hr
)) return hr
;
1391 reset_device_state( iface
);
1394 case (DWORD_PTR
)DIPROP_AUTOCENTER
:
1396 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1397 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1399 FIXME( "DIPROP_AUTOCENTER stub!\n" );
1400 impl
->autocenter
= value
->dwData
;
1403 case (DWORD_PTR
)DIPROP_FFGAIN
:
1405 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1406 if (!impl
->vtbl
->send_device_gain
) return DIERR_UNSUPPORTED
;
1407 impl
->device_gain
= value
->dwData
;
1408 if (!is_exclusively_acquired( impl
)) return DI_OK
;
1409 return impl
->vtbl
->send_device_gain( iface
, impl
->device_gain
);
1411 case (DWORD_PTR
)DIPROP_AXISMODE
:
1413 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1415 TRACE( "Axis mode: %s\n", value
->dwData
== DIPROPAXISMODE_ABS
? "absolute" : "relative" );
1416 if (impl
->user_format
)
1418 impl
->user_format
->dwFlags
&= ~DIDFT_AXIS
;
1419 impl
->user_format
->dwFlags
|= value
->dwData
== DIPROPAXISMODE_ABS
? DIDF_ABSAXIS
: DIDF_RELAXIS
;
1423 case (DWORD_PTR
)DIPROP_BUFFERSIZE
:
1425 const DIPROPDWORD
*value
= (const DIPROPDWORD
*)header
;
1427 TRACE( "buffersize %lu\n", value
->dwData
);
1429 impl
->buffersize
= value
->dwData
;
1430 impl
->queue_len
= min( impl
->buffersize
, 1024 );
1431 free( impl
->data_queue
);
1433 impl
->data_queue
= impl
->queue_len
? malloc( impl
->queue_len
* sizeof(DIDEVICEOBJECTDATA
) ) : NULL
;
1434 impl
->queue_head
= impl
->queue_tail
= impl
->overflow
= 0;
1437 case (DWORD_PTR
)DIPROP_APPDATA
:
1439 const DIPROPPOINTER
*value
= (const DIPROPPOINTER
*)header
;
1441 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, object_mask
, find_object
, &instance
);
1442 if (FAILED(hr
)) return hr
;
1443 if (hr
== DIENUM_CONTINUE
) return DIERR_OBJECTNOTFOUND
;
1444 if ((user_offset
= id_to_offset( impl
, instance
.dwType
)) < 0) return DIERR_OBJECTNOTFOUND
;
1445 if (!set_app_data( impl
, user_offset
, value
->uData
)) return DIERR_OUTOFMEMORY
;
1449 FIXME( "Unknown property %s\n", debugstr_guid( guid
) );
1450 return DIERR_UNSUPPORTED
;
1456 static HRESULT WINAPI
dinput_device_SetProperty( IDirectInputDevice8W
*iface
, const GUID
*guid
,
1457 const DIPROPHEADER
*header
)
1459 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1462 TRACE( "iface %p, guid %s, header %p\n", iface
, debugstr_guid( guid
), header
);
1464 if (!header
) return DIERR_INVALIDPARAM
;
1465 if (header
->dwHeaderSize
!= sizeof(DIPROPHEADER
)) return DIERR_INVALIDPARAM
;
1466 if (!IS_DIPROP( guid
)) return DI_OK
;
1468 EnterCriticalSection( &impl
->crit
);
1469 hr
= dinput_device_set_property( iface
, guid
, header
);
1470 LeaveCriticalSection( &impl
->crit
);
1475 static void dinput_device_set_username( struct dinput_device
*impl
, const DIPROPSTRING
*value
)
1477 struct DevicePlayer
*device_player
;
1480 LIST_FOR_EACH_ENTRY( device_player
, &impl
->dinput
->device_players
, struct DevicePlayer
, entry
)
1482 if (IsEqualGUID( &device_player
->instance_guid
, &impl
->guid
))
1488 if (!found
&& (device_player
= malloc( sizeof(struct DevicePlayer
) )))
1490 list_add_tail( &impl
->dinput
->device_players
, &device_player
->entry
);
1491 device_player
->instance_guid
= impl
->guid
;
1494 lstrcpynW( device_player
->username
, value
->wsz
, ARRAY_SIZE(device_player
->username
) );
1497 static BOOL CALLBACK
get_object_info( const DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
1499 DIDEVICEOBJECTINSTANCEW
*dest
= data
;
1500 DWORD size
= dest
->dwSize
;
1502 memcpy( dest
, instance
, size
);
1503 dest
->dwSize
= size
;
1508 static HRESULT WINAPI
dinput_device_GetObjectInfo( IDirectInputDevice8W
*iface
,
1509 DIDEVICEOBJECTINSTANCEW
*instance
, DWORD obj
, DWORD how
)
1511 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1512 DIPROPHEADER filter
=
1514 .dwSize
= sizeof(filter
),
1515 .dwHeaderSize
= sizeof(filter
),
1521 TRACE( "iface %p, instance %p, obj %#lx, how %#lx.\n", iface
, instance
, obj
, how
);
1523 if (!instance
) return E_POINTER
;
1524 if (instance
->dwSize
!= sizeof(DIDEVICEOBJECTINSTANCE_DX3W
) && instance
->dwSize
!= sizeof(DIDEVICEOBJECTINSTANCEW
))
1525 return DIERR_INVALIDPARAM
;
1526 if (how
== DIPH_DEVICE
) return DIERR_INVALIDPARAM
;
1527 if (FAILED(hr
= enum_object_filter_init( impl
, &filter
))) return hr
;
1529 hr
= impl
->vtbl
->enum_objects( iface
, &filter
, DIDFT_ALL
, get_object_info
, instance
);
1530 if (FAILED(hr
)) return hr
;
1531 if (hr
== DIENUM_CONTINUE
) return DIERR_NOTFOUND
;
1535 static HRESULT WINAPI
dinput_device_GetDeviceState( IDirectInputDevice8W
*iface
, DWORD size
, void *data
)
1537 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1538 DIDATAFORMAT
*device_format
= impl
->device_format
, *user_format
;
1539 DIOBJECTDATAFORMAT
*device_obj
, *user_obj
;
1540 BYTE
*user_state
= data
;
1541 DIPROPHEADER filter
=
1543 .dwSize
= sizeof(filter
),
1544 .dwHeaderSize
= sizeof(filter
),
1545 .dwHow
= DIPH_DEVICE
,
1550 TRACE( "iface %p, size %lu, data %p.\n", iface
, size
, data
);
1552 if (!data
) return DIERR_INVALIDPARAM
;
1554 IDirectInputDevice2_Poll( iface
);
1556 EnterCriticalSection( &impl
->crit
);
1557 if (impl
->status
== STATUS_UNPLUGGED
)
1558 hr
= DIERR_INPUTLOST
;
1559 else if (impl
->status
!= STATUS_ACQUIRED
)
1560 hr
= DIERR_NOTACQUIRED
;
1561 else if (!(user_format
= impl
->user_format
))
1562 hr
= DIERR_INVALIDPARAM
;
1563 else if (size
!= user_format
->dwDataSize
)
1564 hr
= DIERR_INVALIDPARAM
;
1567 memset( user_state
, 0, size
);
1569 user_obj
= user_format
->rgodf
+ device_format
->dwNumObjs
;
1570 device_obj
= device_format
->rgodf
+ device_format
->dwNumObjs
;
1571 while (user_obj
-- > user_format
->rgodf
&& device_obj
-- > device_format
->rgodf
)
1573 if (user_obj
->dwType
& DIDFT_BUTTON
)
1574 user_state
[user_obj
->dwOfs
] = impl
->device_state
[device_obj
->dwOfs
];
1577 /* reset optional POVs to their default */
1578 user_obj
= user_format
->rgodf
+ user_format
->dwNumObjs
;
1579 while (user_obj
-- > user_format
->rgodf
+ device_format
->dwNumObjs
)
1580 if (user_obj
->dwType
& DIDFT_POV
) *(ULONG
*)(user_state
+ user_obj
->dwOfs
) = 0xffffffff;
1582 user_obj
= user_format
->rgodf
+ device_format
->dwNumObjs
;
1583 device_obj
= device_format
->rgodf
+ device_format
->dwNumObjs
;
1584 while (user_obj
-- > user_format
->rgodf
&& device_obj
-- > device_format
->rgodf
)
1586 if (user_obj
->dwType
& (DIDFT_POV
| DIDFT_AXIS
))
1587 *(ULONG
*)(user_state
+ user_obj
->dwOfs
) = *(ULONG
*)(impl
->device_state
+ device_obj
->dwOfs
);
1588 if (!(user_format
->dwFlags
& DIDF_ABSAXIS
) && (device_obj
->dwType
& DIDFT_RELAXIS
))
1589 *(ULONG
*)(impl
->device_state
+ device_obj
->dwOfs
) = 0;
1594 LeaveCriticalSection( &impl
->crit
);
1599 static HRESULT WINAPI
dinput_device_GetDeviceData( IDirectInputDevice8W
*iface
, DWORD size
, DIDEVICEOBJECTDATA
*data
,
1600 DWORD
*count
, DWORD flags
)
1602 struct dinput_device
*This
= impl_from_IDirectInputDevice8W( iface
);
1603 HRESULT ret
= DI_OK
;
1606 TRACE( "iface %p, size %lu, data %p, count %p, flags %#lx.\n", iface
, size
, data
, count
, flags
);
1608 if (This
->dinput
->dwVersion
== 0x0800 || size
== sizeof(DIDEVICEOBJECTDATA_DX3
))
1610 if (!This
->queue_len
) return DIERR_NOTBUFFERED
;
1611 if (This
->status
== STATUS_UNPLUGGED
) return DIERR_INPUTLOST
;
1612 if (This
->status
!= STATUS_ACQUIRED
) return DIERR_NOTACQUIRED
;
1615 if (!This
->queue_len
)
1617 if (size
< sizeof(DIDEVICEOBJECTDATA_DX3
)) return DIERR_INVALIDPARAM
;
1619 IDirectInputDevice2_Poll(iface
);
1620 EnterCriticalSection(&This
->crit
);
1622 len
= This
->queue_head
- This
->queue_tail
;
1623 if (len
< 0) len
+= This
->queue_len
;
1625 if ((*count
!= INFINITE
) && (len
> *count
)) len
= *count
;
1630 for (i
= 0; i
< len
; i
++)
1632 int n
= (This
->queue_tail
+ i
) % This
->queue_len
;
1633 memcpy( (char *)data
+ size
* i
, This
->data_queue
+ n
, size
);
1638 if (This
->overflow
&& This
->dinput
->dwVersion
== 0x0800)
1639 ret
= DI_BUFFEROVERFLOW
;
1641 if (!(flags
& DIGDD_PEEK
))
1643 /* Advance reading position */
1644 This
->queue_tail
= (This
->queue_tail
+ len
) % This
->queue_len
;
1645 This
->overflow
= FALSE
;
1648 LeaveCriticalSection(&This
->crit
);
1650 TRACE( "Returning %lu events queued\n", *count
);
1654 static HRESULT WINAPI
dinput_device_RunControlPanel( IDirectInputDevice8W
*iface
, HWND hwnd
, DWORD flags
)
1656 FIXME( "iface %p, hwnd %p, flags %#lx stub!\n", iface
, hwnd
, flags
);
1660 static HRESULT WINAPI
dinput_device_Initialize( IDirectInputDevice8W
*iface
, HINSTANCE instance
,
1661 DWORD version
, const GUID
*guid
)
1663 FIXME( "iface %p, instance %p, version %#lx, guid %s stub!\n", iface
, instance
, version
,
1664 debugstr_guid( guid
) );
1668 static HRESULT WINAPI
dinput_device_CreateEffect( IDirectInputDevice8W
*iface
, const GUID
*guid
,
1669 const DIEFFECT
*params
, IDirectInputEffect
**out
,
1672 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1676 TRACE( "iface %p, guid %s, params %p, out %p, outer %p\n", iface
, debugstr_guid( guid
),
1677 params
, out
, outer
);
1679 if (!out
) return E_POINTER
;
1682 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1683 if (!impl
->vtbl
->create_effect
) return DIERR_UNSUPPORTED
;
1684 if (FAILED(hr
= impl
->vtbl
->create_effect( iface
, out
))) return hr
;
1686 hr
= IDirectInputEffect_Initialize( *out
, DINPUT_instance
, impl
->dinput
->dwVersion
, guid
);
1687 if (FAILED(hr
)) goto failed
;
1688 if (!params
) return DI_OK
;
1690 flags
= params
->dwSize
== sizeof(DIEFFECT_DX6
) ? DIEP_ALLPARAMS
: DIEP_ALLPARAMS_DX5
;
1691 if (!is_exclusively_acquired( impl
)) flags
|= DIEP_NODOWNLOAD
;
1692 hr
= IDirectInputEffect_SetParameters( *out
, params
, flags
);
1693 if (FAILED(hr
)) goto failed
;
1697 IDirectInputEffect_Release( *out
);
1702 static HRESULT WINAPI
dinput_device_EnumEffects( IDirectInputDevice8W
*iface
, LPDIENUMEFFECTSCALLBACKW callback
,
1703 void *context
, DWORD type
)
1705 DIEFFECTINFOW info
= {.dwSize
= sizeof(info
)};
1708 TRACE( "iface %p, callback %p, context %p, type %#lx.\n", iface
, callback
, context
, type
);
1710 if (!callback
) return DIERR_INVALIDPARAM
;
1712 type
= DIEFT_GETTYPE( type
);
1714 if (type
== DIEFT_ALL
|| type
== DIEFT_CONSTANTFORCE
)
1716 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_ConstantForce
);
1717 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1718 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1721 if (type
== DIEFT_ALL
|| type
== DIEFT_RAMPFORCE
)
1723 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_RampForce
);
1724 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1725 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1728 if (type
== DIEFT_ALL
|| type
== DIEFT_PERIODIC
)
1730 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Square
);
1731 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1732 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1734 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Sine
);
1735 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1736 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1738 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Triangle
);
1739 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1740 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1742 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_SawtoothUp
);
1743 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1744 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1746 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_SawtoothDown
);
1747 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1748 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1751 if (type
== DIEFT_ALL
|| type
== DIEFT_CONDITION
)
1753 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Spring
);
1754 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1755 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1757 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Damper
);
1758 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1759 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1761 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Inertia
);
1762 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1763 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1765 hr
= IDirectInputDevice8_GetEffectInfo( iface
, &info
, &GUID_Friction
);
1766 if (FAILED(hr
) && hr
!= DIERR_DEVICENOTREG
) return hr
;
1767 if (hr
== DI_OK
&& callback( &info
, context
) == DIENUM_STOP
) return DI_OK
;
1773 static HRESULT WINAPI
dinput_device_GetEffectInfo( IDirectInputDevice8W
*iface
, DIEFFECTINFOW
*info
,
1776 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1778 TRACE( "iface %p, info %p, guid %s.\n", iface
, info
, debugstr_guid( guid
) );
1780 if (!info
) return E_POINTER
;
1781 if (info
->dwSize
!= sizeof(DIEFFECTINFOW
)) return DIERR_INVALIDPARAM
;
1782 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_DEVICENOTREG
;
1783 if (!impl
->vtbl
->get_effect_info
) return DIERR_UNSUPPORTED
;
1784 return impl
->vtbl
->get_effect_info( iface
, info
, guid
);
1787 static HRESULT WINAPI
dinput_device_GetForceFeedbackState( IDirectInputDevice8W
*iface
, DWORD
*out
)
1789 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1792 TRACE( "iface %p, out %p.\n", iface
, out
);
1794 if (!out
) return E_POINTER
;
1797 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1799 EnterCriticalSection( &impl
->crit
);
1800 if (!is_exclusively_acquired( impl
)) hr
= DIERR_NOTEXCLUSIVEACQUIRED
;
1801 else *out
= impl
->force_feedback_state
;
1802 LeaveCriticalSection( &impl
->crit
);
1807 static HRESULT WINAPI
dinput_device_SendForceFeedbackCommand( IDirectInputDevice8W
*iface
, DWORD command
)
1809 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1812 TRACE( "iface %p, command %#lx.\n", iface
, command
);
1816 case DISFFC_RESET
: break;
1817 case DISFFC_STOPALL
: break;
1818 case DISFFC_PAUSE
: break;
1819 case DISFFC_CONTINUE
: break;
1820 case DISFFC_SETACTUATORSON
: break;
1821 case DISFFC_SETACTUATORSOFF
: break;
1822 default: return DIERR_INVALIDPARAM
;
1825 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DIERR_UNSUPPORTED
;
1826 if (!impl
->vtbl
->send_force_feedback_command
) return DIERR_UNSUPPORTED
;
1828 EnterCriticalSection( &impl
->crit
);
1829 if (!is_exclusively_acquired( impl
)) hr
= DIERR_NOTEXCLUSIVEACQUIRED
;
1830 else hr
= impl
->vtbl
->send_force_feedback_command( iface
, command
, FALSE
);
1831 LeaveCriticalSection( &impl
->crit
);
1836 static HRESULT WINAPI
dinput_device_EnumCreatedEffectObjects( IDirectInputDevice8W
*iface
,
1837 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK callback
,
1838 void *context
, DWORD flags
)
1840 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1842 TRACE( "iface %p, callback %p, context %p, flags %#lx.\n", iface
, callback
, context
, flags
);
1844 if (!callback
) return DIERR_INVALIDPARAM
;
1845 if (flags
) return DIERR_INVALIDPARAM
;
1846 if (!(impl
->caps
.dwFlags
& DIDC_FORCEFEEDBACK
)) return DI_OK
;
1847 if (!impl
->vtbl
->enum_created_effect_objects
) return DIERR_UNSUPPORTED
;
1849 return impl
->vtbl
->enum_created_effect_objects( iface
, callback
, context
, flags
);
1852 static HRESULT WINAPI
dinput_device_Escape( IDirectInputDevice8W
*iface
, DIEFFESCAPE
*escape
)
1854 FIXME( "iface %p, escape %p stub!\n", iface
, escape
);
1858 static HRESULT WINAPI
dinput_device_Poll( IDirectInputDevice8W
*iface
)
1860 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1861 HRESULT hr
= DI_NOEFFECT
;
1863 EnterCriticalSection( &impl
->crit
);
1864 if (impl
->status
== STATUS_UNPLUGGED
) hr
= DIERR_INPUTLOST
;
1865 else if (impl
->status
!= STATUS_ACQUIRED
) hr
= DIERR_NOTACQUIRED
;
1866 LeaveCriticalSection( &impl
->crit
);
1867 if (FAILED(hr
)) return hr
;
1869 if (impl
->vtbl
->poll
) return impl
->vtbl
->poll( iface
);
1873 static HRESULT WINAPI
dinput_device_SendDeviceData( IDirectInputDevice8W
*iface
, DWORD size
,
1874 const DIDEVICEOBJECTDATA
*data
, DWORD
*count
, DWORD flags
)
1876 FIXME( "iface %p, size %lu, data %p, count %p, flags %#lx stub!\n", iface
, size
, data
, count
, flags
);
1880 static HRESULT WINAPI
dinput_device_EnumEffectsInFile( IDirectInputDevice8W
*iface
, const WCHAR
*filename
,
1881 LPDIENUMEFFECTSINFILECALLBACK callback
,
1882 void *context
, DWORD flags
)
1884 FIXME( "iface %p, filename %s, callback %p, context %p, flags %#lx stub!\n", iface
,
1885 debugstr_w(filename
), callback
, context
, flags
);
1889 static HRESULT WINAPI
dinput_device_WriteEffectToFile( IDirectInputDevice8W
*iface
, const WCHAR
*filename
,
1890 DWORD count
, DIFILEEFFECT
*effects
, DWORD flags
)
1892 FIXME( "iface %p, filename %s, count %lu, effects %p, flags %#lx stub!\n", iface
,
1893 debugstr_w(filename
), count
, effects
, flags
);
1897 static HRESULT WINAPI
dinput_device_BuildActionMap( IDirectInputDevice8W
*iface
, DIACTIONFORMATW
*format
,
1898 const WCHAR
*username
, DWORD flags
)
1900 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1901 BOOL load_success
= FALSE
, has_actions
= FALSE
;
1902 DWORD genre
, username_len
= MAX_PATH
;
1903 WCHAR username_buf
[MAX_PATH
];
1904 const DIDATAFORMAT
*df
;
1908 FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface
, format
,
1909 debugstr_w(username
), flags
);
1911 if (!format
) return DIERR_INVALIDPARAM
;
1913 switch (GET_DIDEVICE_TYPE( impl
->instance
.dwDevType
))
1915 case DIDEVTYPE_KEYBOARD
:
1916 case DI8DEVTYPE_KEYBOARD
:
1917 devMask
= DIKEYBOARD_MASK
;
1918 df
= &c_dfDIKeyboard
;
1920 case DIDEVTYPE_MOUSE
:
1921 case DI8DEVTYPE_MOUSE
:
1922 devMask
= DIMOUSE_MASK
;
1926 devMask
= DIGENRE_ANY
;
1927 df
= impl
->device_format
;
1931 /* Unless asked the contrary by these flags, try to load a previous mapping */
1932 if (!(flags
& DIDBAM_HWDEFAULTS
))
1934 /* Retrieve logged user name if necessary */
1935 if (username
== NULL
) GetUserNameW( username_buf
, &username_len
);
1936 else lstrcpynW( username_buf
, username
, MAX_PATH
);
1937 load_success
= load_mapping_settings( impl
, format
, username_buf
);
1940 if (load_success
) return DI_OK
;
1942 for (i
= 0; i
< format
->dwNumActions
; i
++)
1944 /* Don't touch a user configured action */
1945 if (format
->rgoAction
[i
].dwHow
== DIAH_USERCONFIG
) continue;
1947 genre
= format
->rgoAction
[i
].dwSemantic
& DIGENRE_ANY
;
1948 if (devMask
== genre
|| (devMask
== DIGENRE_ANY
&& genre
!= DIMOUSE_MASK
&& genre
!= DIKEYBOARD_MASK
))
1950 DWORD obj_id
= semantic_to_obj_id( impl
, format
->rgoAction
[i
].dwSemantic
);
1951 DWORD type
= DIDFT_GETTYPE( obj_id
);
1952 DWORD inst
= DIDFT_GETINSTANCE( obj_id
);
1954 LPDIOBJECTDATAFORMAT odf
;
1956 if (type
== DIDFT_PSHBUTTON
) type
= DIDFT_BUTTON
;
1957 if (type
== DIDFT_RELAXIS
) type
= DIDFT_AXIS
;
1959 /* Make sure the object exists */
1960 odf
= dataformat_to_odf_by_type( df
, inst
, type
);
1964 format
->rgoAction
[i
].dwObjID
= obj_id
;
1965 format
->rgoAction
[i
].guidInstance
= impl
->guid
;
1966 format
->rgoAction
[i
].dwHow
= DIAH_DEFAULT
;
1970 else if (!(flags
& DIDBAM_PRESERVE
))
1972 /* We must clear action data belonging to other devices */
1973 memset( &format
->rgoAction
[i
].guidInstance
, 0, sizeof(GUID
) );
1974 format
->rgoAction
[i
].dwHow
= DIAH_UNMAPPED
;
1978 if (!has_actions
) return DI_NOEFFECT
;
1979 if (flags
& (DIDBAM_DEFAULT
|DIDBAM_PRESERVE
|DIDBAM_INITIALIZE
|DIDBAM_HWDEFAULTS
))
1980 FIXME( "Unimplemented flags %#lx\n", flags
);
1984 static HRESULT WINAPI
dinput_device_SetActionMap( IDirectInputDevice8W
*iface
, DIACTIONFORMATW
*format
,
1985 const WCHAR
*username
, DWORD flags
)
1987 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
1988 DIDATAFORMAT data_format
;
1989 DIOBJECTDATAFORMAT
*obj_df
= NULL
;
1993 WCHAR username_buf
[MAX_PATH
];
1994 DWORD username_len
= MAX_PATH
;
1995 int i
, action
= 0, num_actions
= 0;
1996 unsigned int offset
= 0;
1997 const DIDATAFORMAT
*df
;
1998 ActionMap
*action_map
;
2000 FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface
, format
,
2001 debugstr_w(username
), flags
);
2003 if (!format
) return DIERR_INVALIDPARAM
;
2005 switch (GET_DIDEVICE_TYPE( impl
->instance
.dwDevType
))
2007 case DIDEVTYPE_KEYBOARD
:
2008 case DI8DEVTYPE_KEYBOARD
:
2009 df
= &c_dfDIKeyboard
;
2011 case DIDEVTYPE_MOUSE
:
2012 case DI8DEVTYPE_MOUSE
:
2016 df
= impl
->device_format
;
2020 if (impl
->status
== STATUS_ACQUIRED
) return DIERR_ACQUIRED
;
2022 data_format
.dwSize
= sizeof(data_format
);
2023 data_format
.dwObjSize
= sizeof(DIOBJECTDATAFORMAT
);
2024 data_format
.dwFlags
= DIDF_RELAXIS
;
2025 data_format
.dwDataSize
= format
->dwDataSize
;
2027 /* Count the actions */
2028 for (i
= 0; i
< format
->dwNumActions
; i
++)
2029 if (IsEqualGUID( &impl
->guid
, &format
->rgoAction
[i
].guidInstance
))
2032 if (num_actions
== 0) return DI_NOEFFECT
;
2034 /* Construct the dataformat and actionmap */
2035 obj_df
= malloc( sizeof(DIOBJECTDATAFORMAT
) * num_actions
);
2036 data_format
.rgodf
= (LPDIOBJECTDATAFORMAT
)obj_df
;
2037 data_format
.dwNumObjs
= num_actions
;
2039 action_map
= malloc( sizeof(ActionMap
) * num_actions
);
2041 for (i
= 0; i
< format
->dwNumActions
; i
++)
2043 if (IsEqualGUID( &impl
->guid
, &format
->rgoAction
[i
].guidInstance
))
2045 DWORD inst
= DIDFT_GETINSTANCE( format
->rgoAction
[i
].dwObjID
);
2046 DWORD type
= DIDFT_GETTYPE( format
->rgoAction
[i
].dwObjID
);
2047 LPDIOBJECTDATAFORMAT obj
;
2049 if (type
== DIDFT_PSHBUTTON
) type
= DIDFT_BUTTON
;
2050 if (type
== DIDFT_RELAXIS
) type
= DIDFT_AXIS
;
2052 obj
= dataformat_to_odf_by_type( df
, inst
, type
);
2054 memcpy( &obj_df
[action
], obj
, df
->dwObjSize
);
2056 action_map
[action
].uAppData
= format
->rgoAction
[i
].uAppData
;
2057 action_map
[action
].offset
= offset
;
2058 obj_df
[action
].dwOfs
= offset
;
2059 offset
+= (type
& DIDFT_BUTTON
) ? 1 : 4;
2065 IDirectInputDevice8_SetDataFormat( iface
, &data_format
);
2067 impl
->action_map
= action_map
;
2068 impl
->num_actions
= num_actions
;
2072 /* Set the device properties according to the action format */
2073 dpr
.diph
.dwSize
= sizeof(DIPROPRANGE
);
2074 dpr
.lMin
= format
->lAxisMin
;
2075 dpr
.lMax
= format
->lAxisMax
;
2076 dpr
.diph
.dwHeaderSize
= sizeof(DIPROPHEADER
);
2078 dpr
.diph
.dwHow
= DIPH_DEVICE
;
2079 IDirectInputDevice8_SetProperty( iface
, DIPROP_RANGE
, &dpr
.diph
);
2081 if (format
->dwBufferSize
> 0)
2083 dp
.diph
.dwSize
= sizeof(DIPROPDWORD
);
2084 dp
.dwData
= format
->dwBufferSize
;
2085 dp
.diph
.dwHeaderSize
= sizeof(DIPROPHEADER
);
2087 dp
.diph
.dwHow
= DIPH_DEVICE
;
2088 IDirectInputDevice8_SetProperty( iface
, DIPROP_BUFFERSIZE
, &dp
.diph
);
2091 /* Retrieve logged user name if necessary */
2092 if (username
== NULL
) GetUserNameW( username_buf
, &username_len
);
2093 else lstrcpynW( username_buf
, username
, MAX_PATH
);
2095 dps
.diph
.dwSize
= sizeof(dps
);
2096 dps
.diph
.dwHeaderSize
= sizeof(DIPROPHEADER
);
2098 dps
.diph
.dwHow
= DIPH_DEVICE
;
2099 if (flags
& DIDSAM_NOUSER
) dps
.wsz
[0] = '\0';
2100 else lstrcpynW( dps
.wsz
, username_buf
, ARRAY_SIZE(dps
.wsz
) );
2101 dinput_device_set_username( impl
, &dps
);
2103 /* Save the settings to disk */
2104 save_mapping_settings( iface
, format
, username_buf
);
2109 static HRESULT WINAPI
dinput_device_GetImageInfo( IDirectInputDevice8W
*iface
, DIDEVICEIMAGEINFOHEADERW
*header
)
2111 FIXME( "iface %p, header %p stub!\n", iface
, header
);
2115 extern const IDirectInputDevice8AVtbl dinput_device_a_vtbl
;
2116 static const IDirectInputDevice8WVtbl dinput_device_w_vtbl
=
2118 /*** IUnknown methods ***/
2119 dinput_device_QueryInterface
,
2120 dinput_device_AddRef
,
2121 dinput_device_Release
,
2122 /*** IDirectInputDevice methods ***/
2123 dinput_device_GetCapabilities
,
2124 dinput_device_EnumObjects
,
2125 dinput_device_GetProperty
,
2126 dinput_device_SetProperty
,
2127 dinput_device_Acquire
,
2128 dinput_device_Unacquire
,
2129 dinput_device_GetDeviceState
,
2130 dinput_device_GetDeviceData
,
2131 dinput_device_SetDataFormat
,
2132 dinput_device_SetEventNotification
,
2133 dinput_device_SetCooperativeLevel
,
2134 dinput_device_GetObjectInfo
,
2135 dinput_device_GetDeviceInfo
,
2136 dinput_device_RunControlPanel
,
2137 dinput_device_Initialize
,
2138 /*** IDirectInputDevice2 methods ***/
2139 dinput_device_CreateEffect
,
2140 dinput_device_EnumEffects
,
2141 dinput_device_GetEffectInfo
,
2142 dinput_device_GetForceFeedbackState
,
2143 dinput_device_SendForceFeedbackCommand
,
2144 dinput_device_EnumCreatedEffectObjects
,
2145 dinput_device_Escape
,
2147 dinput_device_SendDeviceData
,
2148 /*** IDirectInputDevice7 methods ***/
2149 dinput_device_EnumEffectsInFile
,
2150 dinput_device_WriteEffectToFile
,
2151 /*** IDirectInputDevice8 methods ***/
2152 dinput_device_BuildActionMap
,
2153 dinput_device_SetActionMap
,
2154 dinput_device_GetImageInfo
,
2157 HRESULT
dinput_device_alloc( SIZE_T size
, const struct dinput_device_vtbl
*vtbl
, const GUID
*guid
,
2158 struct dinput
*dinput
, void **out
)
2160 struct dinput_device
*This
;
2161 DIDATAFORMAT
*format
;
2163 if (!(This
= calloc( 1, size
))) return DIERR_OUTOFMEMORY
;
2164 if (!(format
= calloc( 1, sizeof(*format
) )))
2167 return DIERR_OUTOFMEMORY
;
2170 This
->IDirectInputDevice8A_iface
.lpVtbl
= &dinput_device_a_vtbl
;
2171 This
->IDirectInputDevice8W_iface
.lpVtbl
= &dinput_device_w_vtbl
;
2174 This
->instance
.dwSize
= sizeof(DIDEVICEINSTANCEW
);
2175 This
->caps
.dwSize
= sizeof(DIDEVCAPS
);
2176 This
->caps
.dwFlags
= DIDC_ATTACHED
| DIDC_EMULATED
;
2177 This
->device_format
= format
;
2178 This
->device_gain
= 10000;
2179 This
->force_feedback_state
= DIGFFS_STOPPED
| DIGFFS_EMPTY
;
2180 InitializeCriticalSection( &This
->crit
);
2181 This
->dinput
= dinput
;
2182 IDirectInput_AddRef( &dinput
->IDirectInput7A_iface
);
2189 static const GUID
*object_instance_guid( const DIDEVICEOBJECTINSTANCEW
*instance
)
2191 if (IsEqualGUID( &instance
->guidType
, &GUID_XAxis
)) return &GUID_XAxis
;
2192 if (IsEqualGUID( &instance
->guidType
, &GUID_YAxis
)) return &GUID_YAxis
;
2193 if (IsEqualGUID( &instance
->guidType
, &GUID_ZAxis
)) return &GUID_ZAxis
;
2194 if (IsEqualGUID( &instance
->guidType
, &GUID_RxAxis
)) return &GUID_RxAxis
;
2195 if (IsEqualGUID( &instance
->guidType
, &GUID_RyAxis
)) return &GUID_RyAxis
;
2196 if (IsEqualGUID( &instance
->guidType
, &GUID_RzAxis
)) return &GUID_RzAxis
;
2197 if (IsEqualGUID( &instance
->guidType
, &GUID_Slider
)) return &GUID_Slider
;
2198 if (IsEqualGUID( &instance
->guidType
, &GUID_Button
)) return &GUID_Button
;
2199 if (IsEqualGUID( &instance
->guidType
, &GUID_Key
)) return &GUID_Key
;
2200 if (IsEqualGUID( &instance
->guidType
, &GUID_POV
)) return &GUID_POV
;
2201 return &GUID_Unknown
;
2204 static BOOL CALLBACK
enum_objects_init( const DIDEVICEOBJECTINSTANCEW
*instance
, void *data
)
2206 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( data
);
2207 DIDATAFORMAT
*format
= impl
->device_format
;
2208 DIOBJECTDATAFORMAT
*obj_format
;
2212 format
->dwDataSize
= max( format
->dwDataSize
, instance
->dwOfs
+ sizeof(LONG
) );
2213 if (instance
->dwType
& DIDFT_BUTTON
) impl
->caps
.dwButtons
++;
2214 if (instance
->dwType
& DIDFT_AXIS
) impl
->caps
.dwAxes
++;
2215 if (instance
->dwType
& DIDFT_POV
) impl
->caps
.dwPOVs
++;
2216 if (instance
->dwType
& (DIDFT_BUTTON
|DIDFT_AXIS
|DIDFT_POV
))
2218 if (!impl
->device_state_report_id
)
2219 impl
->device_state_report_id
= instance
->wReportId
;
2220 else if (impl
->device_state_report_id
!= instance
->wReportId
)
2221 FIXME( "multiple device state reports found!\n" );
2226 obj_format
= format
->rgodf
+ format
->dwNumObjs
;
2227 obj_format
->pguid
= object_instance_guid( instance
);
2228 obj_format
->dwOfs
= instance
->dwOfs
;
2229 obj_format
->dwType
= instance
->dwType
;
2230 obj_format
->dwFlags
= instance
->dwFlags
;
2233 if (impl
->object_properties
&& (instance
->dwType
& (DIDFT_AXIS
| DIDFT_POV
)))
2234 reset_object_value( instance
, impl
);
2236 format
->dwNumObjs
++;
2237 return DIENUM_CONTINUE
;
2240 HRESULT
dinput_device_init( IDirectInputDevice8W
*iface
)
2242 struct dinput_device
*impl
= impl_from_IDirectInputDevice8W( iface
);
2243 DIDATAFORMAT
*format
= impl
->device_format
;
2246 IDirectInputDevice8_EnumObjects( iface
, enum_objects_init
, iface
, DIDFT_ALL
);
2247 if (format
->dwDataSize
> DEVICE_STATE_MAX_SIZE
)
2249 FIXME( "unable to create device, state is too large\n" );
2250 return DIERR_OUTOFMEMORY
;
2253 size
= format
->dwNumObjs
* sizeof(*format
->rgodf
);
2254 if (!(format
->rgodf
= calloc( 1, size
))) return DIERR_OUTOFMEMORY
;
2256 format
->dwSize
= sizeof(*format
);
2257 format
->dwObjSize
= sizeof(*format
->rgodf
);
2258 format
->dwFlags
= DIDF_ABSAXIS
;
2259 format
->dwNumObjs
= 0;
2260 IDirectInputDevice8_EnumObjects( iface
, enum_objects_init
, iface
, DIDFT_ALL
);
2262 if (TRACE_ON( dinput
))
2264 TRACE( "device format %s\n", debugstr_didataformat( format
) );
2265 for (i
= 0; i
< format
->dwNumObjs
; ++i
) TRACE( " %lu: object %s\n", i
, debugstr_diobjectdataformat( format
->rgodf
+ i
) );