4 * Copyright 1997 Andreas Mohr
5 * Copyright 2000 Wolfgang Schwotzer
6 * Copyright 2000 Eric Pouech
7 * Copyright 2020 Zebediah Figura for CodeWeavers
8 * Copyright 2021 RĂ©mi Bernon for CodeWeavers
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(winmm
);
45 static CRITICAL_SECTION joystick_cs
;
46 static CRITICAL_SECTION_DEBUG critsect_debug
=
49 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
50 0, 0, { (DWORD_PTR
)(__FILE__
": joystick_cs") }
52 static CRITICAL_SECTION joystick_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
66 static const DIOBJECTDATAFORMAT object_formats
[] =
68 { &GUID_XAxis
, offsetof(struct joystick_state
, x
), DIDFT_OPTIONAL
|DIDFT_AXIS
|DIDFT_ANYINSTANCE
, DIDOI_ASPECTPOSITION
},
69 { &GUID_YAxis
, offsetof(struct joystick_state
, y
), DIDFT_OPTIONAL
|DIDFT_AXIS
|DIDFT_ANYINSTANCE
, DIDOI_ASPECTPOSITION
},
70 { &GUID_ZAxis
, offsetof(struct joystick_state
, z
), DIDFT_OPTIONAL
|DIDFT_AXIS
|DIDFT_ANYINSTANCE
, DIDOI_ASPECTPOSITION
},
71 { &GUID_RzAxis
, offsetof(struct joystick_state
, r
), DIDFT_OPTIONAL
|DIDFT_AXIS
|DIDFT_ANYINSTANCE
, DIDOI_ASPECTPOSITION
},
72 { &GUID_Slider
, offsetof(struct joystick_state
, u
), DIDFT_OPTIONAL
|DIDFT_AXIS
|DIDFT_ANYINSTANCE
, DIDOI_ASPECTPOSITION
},
73 { &GUID_RxAxis
, offsetof(struct joystick_state
, v
), DIDFT_OPTIONAL
|DIDFT_AXIS
|DIDFT_ANYINSTANCE
, DIDOI_ASPECTPOSITION
},
74 { &GUID_POV
, offsetof(struct joystick_state
, pov
), DIDFT_OPTIONAL
|DIDFT_POV
|DIDFT_ANYINSTANCE
, 0 },
75 { NULL
, offsetof(struct joystick_state
, buttons
[0]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
76 { NULL
, offsetof(struct joystick_state
, buttons
[1]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
77 { NULL
, offsetof(struct joystick_state
, buttons
[2]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
78 { NULL
, offsetof(struct joystick_state
, buttons
[3]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
79 { NULL
, offsetof(struct joystick_state
, buttons
[4]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
80 { NULL
, offsetof(struct joystick_state
, buttons
[5]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
81 { NULL
, offsetof(struct joystick_state
, buttons
[6]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
82 { NULL
, offsetof(struct joystick_state
, buttons
[7]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
83 { NULL
, offsetof(struct joystick_state
, buttons
[8]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
84 { NULL
, offsetof(struct joystick_state
, buttons
[9]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
85 { NULL
, offsetof(struct joystick_state
, buttons
[10]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
86 { NULL
, offsetof(struct joystick_state
, buttons
[11]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
87 { NULL
, offsetof(struct joystick_state
, buttons
[12]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
88 { NULL
, offsetof(struct joystick_state
, buttons
[13]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
89 { NULL
, offsetof(struct joystick_state
, buttons
[14]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
90 { NULL
, offsetof(struct joystick_state
, buttons
[15]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
91 { NULL
, offsetof(struct joystick_state
, buttons
[16]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
92 { NULL
, offsetof(struct joystick_state
, buttons
[17]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
93 { NULL
, offsetof(struct joystick_state
, buttons
[18]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
94 { NULL
, offsetof(struct joystick_state
, buttons
[19]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
95 { NULL
, offsetof(struct joystick_state
, buttons
[20]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
96 { NULL
, offsetof(struct joystick_state
, buttons
[21]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
97 { NULL
, offsetof(struct joystick_state
, buttons
[22]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
98 { NULL
, offsetof(struct joystick_state
, buttons
[23]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
99 { NULL
, offsetof(struct joystick_state
, buttons
[24]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
100 { NULL
, offsetof(struct joystick_state
, buttons
[25]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
101 { NULL
, offsetof(struct joystick_state
, buttons
[26]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
102 { NULL
, offsetof(struct joystick_state
, buttons
[27]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
103 { NULL
, offsetof(struct joystick_state
, buttons
[28]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
104 { NULL
, offsetof(struct joystick_state
, buttons
[29]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
105 { NULL
, offsetof(struct joystick_state
, buttons
[30]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
106 { NULL
, offsetof(struct joystick_state
, buttons
[31]), DIDFT_OPTIONAL
|DIDFT_BUTTON
|DIDFT_ANYINSTANCE
, 0 },
109 static const DIDATAFORMAT data_format
=
111 .dwSize
= sizeof(DIDATAFORMAT
),
112 .dwObjSize
= sizeof(DIOBJECTDATAFORMAT
),
113 .dwFlags
= DIDF_ABSAXIS
,
114 .dwDataSize
= sizeof(struct joystick_state
),
115 .dwNumObjs
= ARRAY_SIZE(object_formats
),
116 .rgodf
= (DIOBJECTDATAFORMAT
*)object_formats
,
119 #define JOY_PERIOD_MIN (10) /* min Capture time period */
120 #define JOY_PERIOD_MAX (1000) /* max Capture time period */
124 DIDEVICEINSTANCEW instance
;
125 IDirectInputDevice8W
*device
;
126 struct joystick_state state
;
136 static DIDEVICEINSTANCEW instances
[16];
137 static struct joystick joysticks
[16];
138 static IDirectInput8W
*dinput
;
140 static BOOL CALLBACK
enum_instances( const DIDEVICEINSTANCEW
*instance
, void *context
)
142 ULONG index
= *(ULONG
*)context
;
143 BYTE type
= instance
->dwDevType
;
145 if (type
== DI8DEVTYPE_MOUSE
) return DIENUM_CONTINUE
;
146 if (type
== DI8DEVTYPE_KEYBOARD
) return DIENUM_CONTINUE
;
148 instances
[index
++] = *instance
;
149 if (index
>= ARRAY_SIZE(instances
)) return DIENUM_STOP
;
150 *(ULONG
*)context
= index
;
151 return DIENUM_CONTINUE
;
154 static BOOL WINAPI
joystick_load_once( INIT_ONCE
*once
, void *param
, void **context
)
156 HRESULT hr
= DirectInput8Create( hWinMM32Instance
, DIRECTINPUT_VERSION
, &IID_IDirectInput8W
,
157 (void **)&dinput
, NULL
);
158 if (FAILED(hr
)) ERR( "Could not create dinput instance, hr %#lx\n", hr
);
162 void joystick_unload(void)
168 for (i
= 0; i
< ARRAY_SIZE(joysticks
); i
++)
170 if (!joysticks
[i
].device
) continue;
171 IDirectInputDevice8_Release( joysticks
[i
].device
);
172 CloseHandle( joysticks
[i
].event
);
175 IDirectInput8_Release( dinput
);
178 static void find_joysticks(void)
180 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
182 IDirectInputDevice8W
*device
;
187 InitOnceExecuteOnce( &init_once
, joystick_load_once
, NULL
, NULL
);
192 IDirectInput8_EnumDevices( dinput
, DI8DEVCLASS_ALL
, enum_instances
, &index
, DIEDFL_ATTACHEDONLY
);
193 TRACE( "found %lu device instances\n", index
);
197 if (!memcmp( &joysticks
[index
].instance
, &instances
[index
], sizeof(DIDEVICEINSTANCEW
) ))
200 if (joysticks
[index
].device
)
202 IDirectInputDevice8_Release( joysticks
[index
].device
);
203 CloseHandle( joysticks
[index
].event
);
206 if (!(event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
)))
207 WARN( "could not event for device, error %lu\n", GetLastError() );
208 else if (FAILED(hr
= IDirectInput8_CreateDevice( dinput
, &instances
[index
].guidInstance
, &device
, NULL
)))
209 WARN( "could not create device %s instance, hr %#lx\n",
210 debugstr_guid( &instances
[index
].guidInstance
), hr
);
211 else if (FAILED(hr
= IDirectInputDevice8_SetEventNotification( device
, event
)))
212 WARN( "SetEventNotification device %p hr %#lx\n", device
, hr
);
213 else if (FAILED(hr
= IDirectInputDevice8_SetCooperativeLevel( device
, NULL
, DISCL_NONEXCLUSIVE
|DISCL_BACKGROUND
)))
214 WARN( "SetCooperativeLevel device %p hr %#lx\n", device
, hr
);
215 else if (FAILED(hr
= IDirectInputDevice8_SetDataFormat( device
, &data_format
)))
216 WARN( "SetDataFormat device %p hr %#lx\n", device
, hr
);
217 else if (FAILED(hr
= IDirectInputDevice8_Acquire( device
)))
218 WARN( "Acquire device %p hr %#lx\n", device
, hr
);
221 TRACE( "opened device %p event %p\n", device
, event
);
223 memset( &joysticks
[index
], 0, sizeof(struct joystick
) );
224 joysticks
[index
].instance
= instances
[index
];
225 joysticks
[index
].device
= device
;
226 joysticks
[index
].event
= event
;
230 CloseHandle( event
);
231 if (device
) IDirectInputDevice8_Release( device
);
232 memmove( joysticks
+ index
, joysticks
+ index
+ 1,
233 (ARRAY_SIZE(joysticks
) - index
- 1) * sizeof(struct joystick
) );
234 memset( &joysticks
[ARRAY_SIZE(joysticks
) - 1], 0, sizeof(struct joystick
) );
238 static BOOL
compare_uint(unsigned int x
, unsigned int y
, unsigned int max_diff
)
240 unsigned int diff
= x
> y
? x
- y
: y
- x
;
241 return diff
<= max_diff
;
244 static void CALLBACK
joystick_timer( HWND hwnd
, UINT msg
, UINT_PTR timer
, DWORD time
)
252 EnterCriticalSection( &joystick_cs
);
254 for (i
= 0; i
< ARRAY_SIZE(joysticks
); i
++)
256 if (joysticks
[i
].capture
!= hwnd
) continue;
257 if ((res
= joyGetPos( i
, &info
)))
259 WARN( "joyGetPos failed: %08x\n", res
);
263 pos
= MAKELONG( info
.wXpos
, info
.wYpos
);
265 if (!joysticks
[i
].changed
||
266 !compare_uint( joysticks
[i
].info
.wXpos
, info
.wXpos
, joysticks
[i
].threshold
) ||
267 !compare_uint( joysticks
[i
].info
.wYpos
, info
.wYpos
, joysticks
[i
].threshold
))
269 SendMessageA( hwnd
, MM_JOY1MOVE
+ i
, info
.wButtons
, pos
);
270 joysticks
[i
].info
.wXpos
= info
.wXpos
;
271 joysticks
[i
].info
.wYpos
= info
.wYpos
;
273 if (!joysticks
[i
].changed
||
274 !compare_uint( joysticks
[i
].info
.wZpos
, info
.wZpos
, joysticks
[i
].threshold
))
276 SendMessageA( hwnd
, MM_JOY1ZMOVE
+ i
, info
.wButtons
, pos
);
277 joysticks
[i
].info
.wZpos
= info
.wZpos
;
279 if ((change
= joysticks
[i
].info
.wButtons
^ info
.wButtons
) != 0)
281 if (info
.wButtons
& change
)
282 SendMessageA( hwnd
, MM_JOY1BUTTONDOWN
+ i
, (change
<< 8) | (info
.wButtons
& change
), pos
);
283 if (joysticks
[i
].info
.wButtons
& change
)
284 SendMessageA( hwnd
, MM_JOY1BUTTONUP
+ i
, (change
<< 8) | (joysticks
[i
].info
.wButtons
& change
), pos
);
285 joysticks
[i
].info
.wButtons
= info
.wButtons
;
289 LeaveCriticalSection( &joystick_cs
);
292 /**************************************************************************
293 * joyConfigChanged [WINMM.@]
295 MMRESULT WINAPI
joyConfigChanged(DWORD flags
)
297 FIXME( "flags %#lx stub!\n", flags
);
298 if (flags
) return JOYERR_PARMS
;
299 return JOYERR_NOERROR
;
302 /**************************************************************************
303 * joyGetNumDevs [WINMM.@]
305 UINT WINAPI DECLSPEC_HOTPATCH
joyGetNumDevs(void)
307 return ARRAY_SIZE(joysticks
);
310 /**************************************************************************
311 * joyGetDevCapsW [WINMM.@]
313 MMRESULT WINAPI DECLSPEC_HOTPATCH
joyGetDevCapsW( UINT_PTR id
, JOYCAPSW
*caps
, UINT size
)
315 static ULONG last_check
;
316 DIDEVICEOBJECTINSTANCEW instance
= {.dwSize
= sizeof(DIDEVICEOBJECTINSTANCEW
)};
317 DIDEVCAPS dicaps
= {.dwSize
= sizeof(DIDEVCAPS
)};
322 .dwSize
= sizeof(DIPROPDWORD
),
323 .dwHeaderSize
= sizeof(DIPROPHEADER
),
324 .dwHow
= DIPH_DEVICE
,
327 MMRESULT res
= JOYERR_NOERROR
;
328 IDirectInputDevice8W
*device
;
329 ULONG ticks
= GetTickCount();
332 TRACE( "id %d, caps %p, size %u.\n", (int)id
, caps
, size
);
334 if (!caps
) return MMSYSERR_INVALPARAM
;
335 if (size
!= sizeof(JOYCAPSW
) && size
!= sizeof(JOYCAPS2W
)) return JOYERR_PARMS
;
337 memset( caps
, 0, size
);
338 wcscpy( caps
->szRegKey
, L
"DINPUT.DLL" );
339 if (id
== ~(UINT_PTR
)0) return JOYERR_NOERROR
;
341 if (id
>= ARRAY_SIZE(joysticks
)) return JOYERR_PARMS
;
343 EnterCriticalSection( &joystick_cs
);
345 if (!(device
= joysticks
[id
].device
) && (ticks
- last_check
) >= 2000)
351 if (!(device
= joysticks
[id
].device
)) res
= JOYERR_PARMS
;
352 else if (FAILED(hr
= IDirectInputDevice8_GetCapabilities( device
, &dicaps
)))
354 WARN( "GetCapabilities device %p returned %#lx\n", device
, hr
);
359 hr
= IDirectInputDevice8_GetProperty( device
, DIPROP_VIDPID
, &diprop
.diph
);
360 if (FAILED(hr
)) WARN( "GetProperty device %p returned %#lx\n", device
, hr
);
363 caps
->wMid
= LOWORD(diprop
.dwData
);
364 caps
->wPid
= HIWORD(diprop
.dwData
);
367 wcscpy( caps
->szPname
, L
"Wine joystick driver" );
369 caps
->wXmax
= 0xffff;
371 caps
->wYmax
= 0xffff;
373 caps
->wZmax
= 0xffff;
374 caps
->wNumButtons
= dicaps
.dwButtons
;
375 caps
->wPeriodMin
= JOY_PERIOD_MIN
;
376 caps
->wPeriodMax
= JOY_PERIOD_MAX
;
378 caps
->wRmax
= 0xffff;
380 caps
->wUmax
= 0xffff;
382 caps
->wVmax
= 0xffff;
385 caps
->wNumAxes
= min( dicaps
.dwAxes
, caps
->wMaxAxes
);
386 caps
->wMaxButtons
= 32;
388 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, z
), DIPH_BYOFFSET
);
389 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASZ
;
390 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, r
), DIPH_BYOFFSET
);
391 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASR
;
392 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, u
), DIPH_BYOFFSET
);
393 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASU
;
394 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, v
), DIPH_BYOFFSET
);
395 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASV
;
396 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, pov
), DIPH_BYOFFSET
);
397 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASPOV
|JOYCAPS_POV4DIR
;
400 LeaveCriticalSection( &joystick_cs
);
405 /**************************************************************************
406 * joyGetDevCapsA [WINMM.@]
408 MMRESULT WINAPI DECLSPEC_HOTPATCH
joyGetDevCapsA( UINT_PTR id
, JOYCAPSA
*caps
, UINT size
)
410 UINT size_w
= sizeof(JOYCAPS2W
);
414 TRACE( "id %d, caps %p, size %u.\n", (int)id
, caps
, size
);
416 if (!caps
) return MMSYSERR_INVALPARAM
;
417 if (size
!= sizeof(JOYCAPSA
) && size
!= sizeof(JOYCAPS2A
)) return JOYERR_PARMS
;
419 if (size
== sizeof(JOYCAPSA
)) size_w
= sizeof(JOYCAPSW
);
420 res
= joyGetDevCapsW( id
, (JOYCAPSW
*)&caps_w
, size_w
);
423 caps
->wMid
= caps_w
.wMid
;
424 caps
->wPid
= caps_w
.wPid
;
425 WideCharToMultiByte( CP_ACP
, 0, caps_w
.szPname
, -1, caps
->szPname
,
426 sizeof(caps
->szPname
), NULL
, NULL
);
427 caps
->wXmin
= caps_w
.wXmin
;
428 caps
->wXmax
= caps_w
.wXmax
;
429 caps
->wYmin
= caps_w
.wYmin
;
430 caps
->wYmax
= caps_w
.wYmax
;
431 caps
->wZmin
= caps_w
.wZmin
;
432 caps
->wZmax
= caps_w
.wZmax
;
433 caps
->wNumButtons
= caps_w
.wNumButtons
;
434 caps
->wPeriodMin
= caps_w
.wPeriodMin
;
435 caps
->wPeriodMax
= caps_w
.wPeriodMax
;
436 caps
->wRmin
= caps_w
.wRmin
;
437 caps
->wRmax
= caps_w
.wRmax
;
438 caps
->wUmin
= caps_w
.wUmin
;
439 caps
->wUmax
= caps_w
.wUmax
;
440 caps
->wVmin
= caps_w
.wVmin
;
441 caps
->wVmax
= caps_w
.wVmax
;
442 caps
->wCaps
= caps_w
.wCaps
;
443 caps
->wMaxAxes
= caps_w
.wMaxAxes
;
444 caps
->wNumAxes
= caps_w
.wNumAxes
;
445 caps
->wMaxButtons
= caps_w
.wMaxButtons
;
446 WideCharToMultiByte( CP_ACP
, 0, caps_w
.szRegKey
, -1, caps
->szRegKey
,
447 sizeof(caps
->szRegKey
), NULL
, NULL
);
448 WideCharToMultiByte( CP_ACP
, 0, caps_w
.szOEMVxD
, -1, caps
->szOEMVxD
,
449 sizeof(caps
->szOEMVxD
), NULL
, NULL
);
451 if (size
== sizeof(JOYCAPS2A
))
453 JOYCAPS2A
*caps2_a
= (JOYCAPS2A
*)caps
;
454 caps2_a
->ManufacturerGuid
= caps_w
.ManufacturerGuid
;
455 caps2_a
->ProductGuid
= caps_w
.ProductGuid
;
456 caps2_a
->NameGuid
= caps_w
.NameGuid
;
459 return JOYERR_NOERROR
;
462 /**************************************************************************
463 * joyGetPosEx [WINMM.@]
465 MMRESULT WINAPI DECLSPEC_HOTPATCH
joyGetPosEx( UINT id
, JOYINFOEX
*info
)
467 static ULONG last_check
;
468 DWORD i
, ticks
= GetTickCount();
469 MMRESULT res
= JOYERR_NOERROR
;
470 IDirectInputDevice8W
*device
;
471 struct joystick_state state
;
474 TRACE( "id %u, info %p.\n", id
, info
);
476 if (!info
) return MMSYSERR_INVALPARAM
;
477 if (id
>= ARRAY_SIZE(joysticks
) || info
->dwSize
< sizeof(JOYINFOEX
)) return JOYERR_PARMS
;
479 EnterCriticalSection( &joystick_cs
);
481 if (!(device
= joysticks
[id
].device
) && (ticks
- last_check
) >= 2000)
487 if (!(device
= joysticks
[id
].device
))
489 else if (FAILED(hr
= IDirectInputDevice8_GetDeviceState( device
, sizeof(struct joystick_state
), &state
)))
491 WARN( "GetDeviceState device %p returned %#lx\n", device
, hr
);
496 if (info
->dwFlags
& JOY_RETURNX
) info
->dwXpos
= state
.x
;
497 if (info
->dwFlags
& JOY_RETURNY
) info
->dwYpos
= state
.y
;
498 if (info
->dwFlags
& JOY_RETURNZ
) info
->dwZpos
= state
.z
;
499 if (info
->dwFlags
& JOY_RETURNR
) info
->dwRpos
= state
.r
;
500 if (info
->dwFlags
& JOY_RETURNU
) info
->dwUpos
= state
.u
;
501 if (info
->dwFlags
& JOY_RETURNV
) info
->dwVpos
= state
.v
;
502 if (info
->dwFlags
& JOY_RETURNPOV
)
504 if (state
.pov
== ~0) info
->dwPOV
= 0xffff;
505 else info
->dwPOV
= state
.pov
;
507 if (info
->dwFlags
& JOY_RETURNBUTTONS
)
509 info
->dwButtonNumber
= info
->dwButtons
= 0;
510 for (i
= 0; i
< ARRAY_SIZE(state
.buttons
); ++i
)
512 if (!state
.buttons
[i
]) continue;
513 info
->dwButtonNumber
++;
514 info
->dwButtons
|= 1 << i
;
519 LeaveCriticalSection( &joystick_cs
);
524 /**************************************************************************
525 * joyGetPos [WINMM.@]
527 MMRESULT WINAPI
joyGetPos( UINT id
, JOYINFO
*info
)
531 .dwSize
= sizeof(JOYINFOEX
),
532 .dwFlags
= JOY_RETURNX
| JOY_RETURNY
| JOY_RETURNZ
| JOY_RETURNBUTTONS
,
536 TRACE( "id %u, info %p.\n", id
, info
);
538 if (!info
) return MMSYSERR_INVALPARAM
;
539 if ((res
= joyGetPosEx( id
, &infoex
))) return res
;
541 info
->wXpos
= infoex
.dwXpos
;
542 info
->wYpos
= infoex
.dwYpos
;
543 info
->wZpos
= infoex
.dwZpos
;
544 info
->wButtons
= infoex
.dwButtons
;
546 return JOYERR_NOERROR
;
549 /**************************************************************************
550 * joyGetThreshold [WINMM.@]
552 MMRESULT WINAPI
joyGetThreshold( UINT id
, UINT
*threshold
)
554 TRACE( "id %u, threshold %p.\n", id
, threshold
);
556 if (id
>= ARRAY_SIZE(joysticks
)) return JOYERR_PARMS
;
558 EnterCriticalSection( &joystick_cs
);
559 *threshold
= joysticks
[id
].threshold
;
560 LeaveCriticalSection( &joystick_cs
);
562 return JOYERR_NOERROR
;
565 /**************************************************************************
566 * joyReleaseCapture [WINMM.@]
568 MMRESULT WINAPI
joyReleaseCapture( UINT id
)
570 TRACE( "id %u.\n", id
);
572 if (id
>= ARRAY_SIZE(joysticks
)) return JOYERR_PARMS
;
574 EnterCriticalSection( &joystick_cs
);
576 if (!joysticks
[id
].capture
)
577 TRACE("Joystick is not captured, ignoring request.\n");
580 KillTimer( joysticks
[id
].capture
, joysticks
[id
].timer
);
581 joysticks
[id
].capture
= 0;
582 joysticks
[id
].timer
= 0;
585 LeaveCriticalSection( &joystick_cs
);
587 return JOYERR_NOERROR
;
590 /**************************************************************************
591 * joySetCapture [WINMM.@]
593 MMRESULT WINAPI
joySetCapture( HWND hwnd
, UINT id
, UINT period
, BOOL changed
)
595 MMRESULT res
= JOYERR_NOERROR
;
597 TRACE( "hwnd %p, id %u, period %u, changed %u.\n", hwnd
, id
, period
, changed
);
599 if (id
>= ARRAY_SIZE(joysticks
) || hwnd
== 0) return JOYERR_PARMS
;
600 if (period
< JOY_PERIOD_MIN
) period
= JOY_PERIOD_MIN
;
601 else if (period
> JOY_PERIOD_MAX
) period
= JOY_PERIOD_MAX
;
603 EnterCriticalSection( &joystick_cs
);
605 if (joysticks
[id
].capture
|| !IsWindow( hwnd
))
606 res
= JOYERR_NOCANDO
; /* FIXME: what should be returned ? */
607 else if (joyGetPos( id
, &joysticks
[id
].info
) != JOYERR_NOERROR
)
608 res
= JOYERR_UNPLUGGED
;
609 else if ((joysticks
[id
].timer
= SetTimer( hwnd
, 0, period
, joystick_timer
)) == 0)
610 res
= JOYERR_NOCANDO
;
613 joysticks
[id
].capture
= hwnd
;
614 joysticks
[id
].changed
= changed
;
617 LeaveCriticalSection( &joystick_cs
);
621 /**************************************************************************
622 * joySetThreshold [WINMM.@]
624 MMRESULT WINAPI
joySetThreshold( UINT id
, UINT threshold
)
626 TRACE( "id %u, threshold %u.\n", id
, threshold
);
628 if (id
>= ARRAY_SIZE(joysticks
) || threshold
> 65535) return MMSYSERR_INVALPARAM
;
630 EnterCriticalSection( &joystick_cs
);
631 joysticks
[id
].threshold
= threshold
;
632 LeaveCriticalSection( &joystick_cs
);
634 return JOYERR_NOERROR
;