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
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(winmm
);
46 static CRITICAL_SECTION joystick_cs
;
47 static CRITICAL_SECTION_DEBUG critsect_debug
=
50 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
51 0, 0, { (DWORD_PTR
)(__FILE__
": joystick_cs") }
53 static CRITICAL_SECTION joystick_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
66 #define BUTTON_COUNT 32
70 LONG axes
[AXIS_COUNT
];
72 BYTE buttons
[BUTTON_COUNT
];
75 #define JOY_PERIOD_MIN (10) /* min Capture time period */
76 #define JOY_PERIOD_MAX (1000) /* max Capture time period */
80 DIDEVICEINSTANCEW instance
;
81 IDirectInputDevice8W
*device
;
82 struct joystick_state state
;
92 static DIDEVICEINSTANCEW instances
[16];
93 static struct joystick joysticks
[16];
94 static IDirectInput8W
*dinput
;
96 static BOOL CALLBACK
enum_instances( const DIDEVICEINSTANCEW
*instance
, void *context
)
98 ULONG index
= *(ULONG
*)context
;
99 BYTE type
= instance
->dwDevType
;
101 if (type
== DI8DEVTYPE_MOUSE
) return DIENUM_CONTINUE
;
102 if (type
== DI8DEVTYPE_KEYBOARD
) return DIENUM_CONTINUE
;
104 instances
[index
++] = *instance
;
105 if (index
>= ARRAY_SIZE(instances
)) return DIENUM_STOP
;
106 *(ULONG
*)context
= index
;
107 return DIENUM_CONTINUE
;
110 static BOOL WINAPI
joystick_load_once( INIT_ONCE
*once
, void *param
, void **context
)
112 HRESULT hr
= DirectInput8Create( hWinMM32Instance
, DIRECTINPUT_VERSION
, &IID_IDirectInput8W
,
113 (void **)&dinput
, NULL
);
114 if (FAILED(hr
)) ERR( "Could not create dinput instance, hr %#lx\n", hr
);
118 void joystick_unload(void)
124 for (i
= 0; i
< ARRAY_SIZE(joysticks
); i
++)
126 if (!joysticks
[i
].device
) continue;
127 IDirectInputDevice8_Release( joysticks
[i
].device
);
128 CloseHandle( joysticks
[i
].event
);
131 IDirectInput8_Release( dinput
);
134 static int is_already_mapped( const DIOBJECTDATAFORMAT
*object_formats
, DWORD count
, DWORD instance_number
)
138 for (i
= 0; i
< count
; ++i
)
140 if (object_formats
[i
].dwType
== instance_number
)
147 struct usage_enum_params
151 DWORD instance_number
;
154 static BOOL CALLBACK
usage_enum_cb( const DIDEVICEOBJECTINSTANCEW
*instance
, void *ctx
)
156 struct usage_enum_params
*params
= ctx
;
158 if (!(instance
->dwFlags
& DIDOI_ASPECTPOSITION
))
159 return DIENUM_CONTINUE
;
161 if (instance
->wUsagePage
!= HID_USAGE_PAGE_GENERIC
)
162 return DIENUM_CONTINUE
;
164 if ((params
->usage
== instance
->wUsage
)
165 || (params
->usage
== HID_USAGE_GENERIC_Z
&& instance
->wUsage
== HID_USAGE_GENERIC_WHEEL
))
167 params
->instance_number
= instance
->dwType
;
172 return DIENUM_CONTINUE
;
175 static HRESULT
set_data_format( IDirectInputDevice8W
*device
)
177 DIOBJECTDATAFORMAT object_formats
[AXIS_COUNT
+ 1 + BUTTON_COUNT
] = {{0}}; /* +1 for hat switch */
178 DIOBJECTDATAFORMAT
*object_format
;
179 DIDATAFORMAT data_format
= {0};
186 usage_mappings
[AXIS_COUNT
] =
188 [AXIS_X
] = {{HID_USAGE_GENERIC_X
, HID_USAGE_GENERIC_RY
}},
189 [AXIS_Y
] = {{HID_USAGE_GENERIC_Y
, HID_USAGE_GENERIC_RX
}},
190 [AXIS_Z
] = {{HID_USAGE_GENERIC_Z
, HID_USAGE_GENERIC_SLIDER
, HID_USAGE_GENERIC_DIAL
}},
191 [AXIS_R
] = {{HID_USAGE_GENERIC_RZ
, HID_USAGE_GENERIC_SLIDER
, HID_USAGE_GENERIC_DIAL
, HID_USAGE_GENERIC_RY
, HID_USAGE_GENERIC_RX
}},
192 [AXIS_U
] = {{HID_USAGE_GENERIC_SLIDER
, HID_USAGE_GENERIC_DIAL
, HID_USAGE_GENERIC_RY
, HID_USAGE_GENERIC_RX
}},
193 [AXIS_V
] = {{HID_USAGE_GENERIC_RX
}},
196 data_format
.dwSize
= sizeof(DIDATAFORMAT
);
197 data_format
.dwObjSize
= sizeof(DIOBJECTDATAFORMAT
);
198 data_format
.dwFlags
= DIDF_ABSAXIS
;
199 data_format
.dwDataSize
= sizeof(struct joystick_state
);
200 data_format
.rgodf
= object_formats
;
202 for (i
= 0; i
< ARRAY_SIZE(usage_mappings
); ++i
)
204 for (j
= 0; j
< ARRAY_SIZE(usage_mappings
[i
].usages
) && usage_mappings
[i
].usages
[j
]; ++j
)
206 struct usage_enum_params params
= {.usage
= usage_mappings
[i
].usages
[j
]};
208 /* We can almost use GetObjectInfo() here, except that winmm
209 * treats Z and wheel identically. */
210 if (FAILED(IDirectInputDevice8_EnumObjects( device
, usage_enum_cb
, ¶ms
, DIDFT_AXIS
)))
214 if (is_already_mapped( object_formats
, data_format
.dwNumObjs
, params
.instance_number
))
217 object_format
= &object_formats
[data_format
.dwNumObjs
++];
218 object_format
->dwOfs
= offsetof(struct joystick_state
, axes
[i
]);
219 object_format
->dwType
= params
.instance_number
;
224 object_format
= &object_formats
[data_format
.dwNumObjs
++];
225 object_format
->pguid
= &GUID_POV
;
226 object_format
->dwOfs
= offsetof(struct joystick_state
, pov
);
227 object_format
->dwType
= DIDFT_OPTIONAL
| DIDFT_POV
| DIDFT_ANYINSTANCE
;
229 for (i
= 0; i
< BUTTON_COUNT
; ++i
)
231 object_format
= &object_formats
[data_format
.dwNumObjs
++];
232 object_format
->dwOfs
= offsetof(struct joystick_state
, buttons
[i
]);
233 object_format
->dwType
= DIDFT_OPTIONAL
| DIDFT_BUTTON
| DIDFT_ANYINSTANCE
;
236 return IDirectInputDevice8_SetDataFormat( device
, &data_format
);
239 static void find_joysticks(void)
241 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
243 IDirectInputDevice8W
*device
;
248 InitOnceExecuteOnce( &init_once
, joystick_load_once
, NULL
, NULL
);
253 IDirectInput8_EnumDevices( dinput
, DI8DEVCLASS_ALL
, enum_instances
, &index
, DIEDFL_ATTACHEDONLY
);
254 TRACE( "found %lu device instances\n", index
);
258 if (!memcmp( &joysticks
[index
].instance
, &instances
[index
], sizeof(DIDEVICEINSTANCEW
) ))
261 if (joysticks
[index
].device
)
263 IDirectInputDevice8_Release( joysticks
[index
].device
);
264 CloseHandle( joysticks
[index
].event
);
267 if (!(event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
)))
268 WARN( "could not event for device, error %lu\n", GetLastError() );
269 else if (FAILED(hr
= IDirectInput8_CreateDevice( dinput
, &instances
[index
].guidInstance
, &device
, NULL
)))
270 WARN( "could not create device %s instance, hr %#lx\n",
271 debugstr_guid( &instances
[index
].guidInstance
), hr
);
272 else if (FAILED(hr
= IDirectInputDevice8_SetEventNotification( device
, event
)))
273 WARN( "SetEventNotification device %p hr %#lx\n", device
, hr
);
274 else if (FAILED(hr
= IDirectInputDevice8_SetCooperativeLevel( device
, NULL
, DISCL_NONEXCLUSIVE
|DISCL_BACKGROUND
)))
275 WARN( "SetCooperativeLevel device %p hr %#lx\n", device
, hr
);
276 else if (FAILED(hr
= set_data_format( device
)))
277 WARN( "SetDataFormat device %p hr %#lx\n", device
, hr
);
278 else if (FAILED(hr
= IDirectInputDevice8_Acquire( device
)))
279 WARN( "Acquire device %p hr %#lx\n", device
, hr
);
282 TRACE( "opened device %p event %p\n", device
, event
);
284 memset( &joysticks
[index
], 0, sizeof(struct joystick
) );
285 joysticks
[index
].instance
= instances
[index
];
286 joysticks
[index
].device
= device
;
287 joysticks
[index
].event
= event
;
291 CloseHandle( event
);
292 if (device
) IDirectInputDevice8_Release( device
);
293 memmove( joysticks
+ index
, joysticks
+ index
+ 1,
294 (ARRAY_SIZE(joysticks
) - index
- 1) * sizeof(struct joystick
) );
295 memset( &joysticks
[ARRAY_SIZE(joysticks
) - 1], 0, sizeof(struct joystick
) );
299 static BOOL
compare_uint(unsigned int x
, unsigned int y
, unsigned int max_diff
)
301 unsigned int diff
= x
> y
? x
- y
: y
- x
;
302 return diff
<= max_diff
;
305 static void CALLBACK
joystick_timer( HWND hwnd
, UINT msg
, UINT_PTR timer
, DWORD time
)
313 EnterCriticalSection( &joystick_cs
);
315 for (i
= 0; i
< ARRAY_SIZE(joysticks
); i
++)
317 if (joysticks
[i
].capture
!= hwnd
) continue;
318 if ((res
= joyGetPos( i
, &info
)))
320 WARN( "joyGetPos failed: %08x\n", res
);
324 pos
= MAKELONG( info
.wXpos
, info
.wYpos
);
326 if (!joysticks
[i
].changed
||
327 !compare_uint( joysticks
[i
].info
.wXpos
, info
.wXpos
, joysticks
[i
].threshold
) ||
328 !compare_uint( joysticks
[i
].info
.wYpos
, info
.wYpos
, joysticks
[i
].threshold
))
330 SendMessageA( hwnd
, MM_JOY1MOVE
+ i
, info
.wButtons
, pos
);
331 joysticks
[i
].info
.wXpos
= info
.wXpos
;
332 joysticks
[i
].info
.wYpos
= info
.wYpos
;
334 if (!joysticks
[i
].changed
||
335 !compare_uint( joysticks
[i
].info
.wZpos
, info
.wZpos
, joysticks
[i
].threshold
))
337 SendMessageA( hwnd
, MM_JOY1ZMOVE
+ i
, info
.wButtons
, pos
);
338 joysticks
[i
].info
.wZpos
= info
.wZpos
;
340 if ((change
= joysticks
[i
].info
.wButtons
^ info
.wButtons
) != 0)
342 if (info
.wButtons
& change
)
343 SendMessageA( hwnd
, MM_JOY1BUTTONDOWN
+ i
, (change
<< 8) | (info
.wButtons
& change
), pos
);
344 if (joysticks
[i
].info
.wButtons
& change
)
345 SendMessageA( hwnd
, MM_JOY1BUTTONUP
+ i
, (change
<< 8) | (joysticks
[i
].info
.wButtons
& change
), pos
);
346 joysticks
[i
].info
.wButtons
= info
.wButtons
;
350 LeaveCriticalSection( &joystick_cs
);
353 /**************************************************************************
354 * joyConfigChanged [WINMM.@]
356 MMRESULT WINAPI
joyConfigChanged(DWORD flags
)
358 FIXME( "flags %#lx stub!\n", flags
);
359 if (flags
) return JOYERR_PARMS
;
360 return JOYERR_NOERROR
;
363 /**************************************************************************
364 * joyGetNumDevs [WINMM.@]
366 UINT WINAPI DECLSPEC_HOTPATCH
joyGetNumDevs(void)
368 return ARRAY_SIZE(joysticks
);
371 /**************************************************************************
372 * joyGetDevCapsW [WINMM.@]
374 MMRESULT WINAPI DECLSPEC_HOTPATCH
joyGetDevCapsW( UINT_PTR id
, JOYCAPSW
*caps
, UINT size
)
376 static ULONG last_check
;
377 DIDEVICEOBJECTINSTANCEW instance
= {.dwSize
= sizeof(DIDEVICEOBJECTINSTANCEW
)};
378 DIDEVCAPS dicaps
= {.dwSize
= sizeof(DIDEVCAPS
)};
383 .dwSize
= sizeof(DIPROPDWORD
),
384 .dwHeaderSize
= sizeof(DIPROPHEADER
),
385 .dwHow
= DIPH_DEVICE
,
388 MMRESULT res
= JOYERR_NOERROR
;
389 IDirectInputDevice8W
*device
;
390 ULONG ticks
= GetTickCount();
393 TRACE( "id %d, caps %p, size %u.\n", (int)id
, caps
, size
);
395 if (!caps
) return MMSYSERR_INVALPARAM
;
396 if (size
!= sizeof(JOYCAPSW
) && size
!= sizeof(JOYCAPS2W
)) return JOYERR_PARMS
;
398 memset( caps
, 0, size
);
399 wcscpy( caps
->szRegKey
, L
"DINPUT.DLL" );
400 if (id
== ~(UINT_PTR
)0) return JOYERR_NOERROR
;
402 if (id
>= ARRAY_SIZE(joysticks
)) return JOYERR_PARMS
;
404 EnterCriticalSection( &joystick_cs
);
406 if (!(device
= joysticks
[id
].device
) && (ticks
- last_check
) >= 2000)
412 if (!(device
= joysticks
[id
].device
)) res
= JOYERR_PARMS
;
413 else if (FAILED(hr
= IDirectInputDevice8_GetCapabilities( device
, &dicaps
)))
415 WARN( "GetCapabilities device %p returned %#lx\n", device
, hr
);
420 hr
= IDirectInputDevice8_GetProperty( device
, DIPROP_VIDPID
, &diprop
.diph
);
421 if (FAILED(hr
)) WARN( "GetProperty device %p returned %#lx\n", device
, hr
);
424 caps
->wMid
= LOWORD(diprop
.dwData
);
425 caps
->wPid
= HIWORD(diprop
.dwData
);
428 wcscpy( caps
->szPname
, L
"Wine joystick driver" );
430 caps
->wXmax
= 0xffff;
432 caps
->wYmax
= 0xffff;
434 caps
->wZmax
= 0xffff;
435 caps
->wNumButtons
= dicaps
.dwButtons
;
436 caps
->wPeriodMin
= JOY_PERIOD_MIN
;
437 caps
->wPeriodMax
= JOY_PERIOD_MAX
;
439 caps
->wRmax
= 0xffff;
441 caps
->wUmax
= 0xffff;
443 caps
->wVmax
= 0xffff;
445 caps
->wMaxAxes
= AXIS_COUNT
;
446 caps
->wNumAxes
= min( dicaps
.dwAxes
, caps
->wMaxAxes
);
447 caps
->wMaxButtons
= BUTTON_COUNT
;
449 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, axes
[AXIS_Z
]), DIPH_BYOFFSET
);
450 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASZ
;
451 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, axes
[AXIS_R
]), DIPH_BYOFFSET
);
452 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASR
;
453 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, axes
[AXIS_U
]), DIPH_BYOFFSET
);
454 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASU
;
455 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, axes
[AXIS_V
]), DIPH_BYOFFSET
);
456 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASV
;
457 hr
= IDirectInputDevice8_GetObjectInfo( device
, &instance
, offsetof(struct joystick_state
, pov
), DIPH_BYOFFSET
);
458 if (SUCCEEDED(hr
)) caps
->wCaps
|= JOYCAPS_HASPOV
|JOYCAPS_POV4DIR
;
461 LeaveCriticalSection( &joystick_cs
);
466 /**************************************************************************
467 * joyGetDevCapsA [WINMM.@]
469 MMRESULT WINAPI DECLSPEC_HOTPATCH
joyGetDevCapsA( UINT_PTR id
, JOYCAPSA
*caps
, UINT size
)
471 UINT size_w
= sizeof(JOYCAPS2W
);
475 TRACE( "id %d, caps %p, size %u.\n", (int)id
, caps
, size
);
477 if (!caps
) return MMSYSERR_INVALPARAM
;
478 if (size
!= sizeof(JOYCAPSA
) && size
!= sizeof(JOYCAPS2A
)) return JOYERR_PARMS
;
480 if (size
== sizeof(JOYCAPSA
)) size_w
= sizeof(JOYCAPSW
);
481 res
= joyGetDevCapsW( id
, (JOYCAPSW
*)&caps_w
, size_w
);
484 caps
->wMid
= caps_w
.wMid
;
485 caps
->wPid
= caps_w
.wPid
;
486 WideCharToMultiByte( CP_ACP
, 0, caps_w
.szPname
, -1, caps
->szPname
,
487 sizeof(caps
->szPname
), NULL
, NULL
);
488 caps
->wXmin
= caps_w
.wXmin
;
489 caps
->wXmax
= caps_w
.wXmax
;
490 caps
->wYmin
= caps_w
.wYmin
;
491 caps
->wYmax
= caps_w
.wYmax
;
492 caps
->wZmin
= caps_w
.wZmin
;
493 caps
->wZmax
= caps_w
.wZmax
;
494 caps
->wNumButtons
= caps_w
.wNumButtons
;
495 caps
->wPeriodMin
= caps_w
.wPeriodMin
;
496 caps
->wPeriodMax
= caps_w
.wPeriodMax
;
497 caps
->wRmin
= caps_w
.wRmin
;
498 caps
->wRmax
= caps_w
.wRmax
;
499 caps
->wUmin
= caps_w
.wUmin
;
500 caps
->wUmax
= caps_w
.wUmax
;
501 caps
->wVmin
= caps_w
.wVmin
;
502 caps
->wVmax
= caps_w
.wVmax
;
503 caps
->wCaps
= caps_w
.wCaps
;
504 caps
->wMaxAxes
= caps_w
.wMaxAxes
;
505 caps
->wNumAxes
= caps_w
.wNumAxes
;
506 caps
->wMaxButtons
= caps_w
.wMaxButtons
;
507 WideCharToMultiByte( CP_ACP
, 0, caps_w
.szRegKey
, -1, caps
->szRegKey
,
508 sizeof(caps
->szRegKey
), NULL
, NULL
);
509 WideCharToMultiByte( CP_ACP
, 0, caps_w
.szOEMVxD
, -1, caps
->szOEMVxD
,
510 sizeof(caps
->szOEMVxD
), NULL
, NULL
);
512 if (size
== sizeof(JOYCAPS2A
))
514 JOYCAPS2A
*caps2_a
= (JOYCAPS2A
*)caps
;
515 caps2_a
->ManufacturerGuid
= caps_w
.ManufacturerGuid
;
516 caps2_a
->ProductGuid
= caps_w
.ProductGuid
;
517 caps2_a
->NameGuid
= caps_w
.NameGuid
;
520 return JOYERR_NOERROR
;
523 /**************************************************************************
524 * joyGetPosEx [WINMM.@]
526 MMRESULT WINAPI DECLSPEC_HOTPATCH
joyGetPosEx( UINT id
, JOYINFOEX
*info
)
528 static ULONG last_check
;
529 DWORD i
, ticks
= GetTickCount();
530 MMRESULT res
= JOYERR_NOERROR
;
531 IDirectInputDevice8W
*device
;
532 struct joystick_state state
;
535 TRACE( "id %u, info %p.\n", id
, info
);
537 if (!info
) return MMSYSERR_INVALPARAM
;
538 if (id
>= ARRAY_SIZE(joysticks
) || info
->dwSize
< sizeof(JOYINFOEX
)) return JOYERR_PARMS
;
540 EnterCriticalSection( &joystick_cs
);
542 if (!(device
= joysticks
[id
].device
) && (ticks
- last_check
) >= 2000)
548 if (!(device
= joysticks
[id
].device
))
550 else if (FAILED(hr
= IDirectInputDevice8_GetDeviceState( device
, sizeof(struct joystick_state
), &state
)))
552 WARN( "GetDeviceState device %p returned %#lx\n", device
, hr
);
557 if (info
->dwFlags
& JOY_RETURNX
) info
->dwXpos
= state
.axes
[AXIS_X
];
558 if (info
->dwFlags
& JOY_RETURNY
) info
->dwYpos
= state
.axes
[AXIS_Y
];
559 if (info
->dwFlags
& JOY_RETURNZ
) info
->dwZpos
= state
.axes
[AXIS_Z
];
560 if (info
->dwFlags
& JOY_RETURNR
) info
->dwRpos
= state
.axes
[AXIS_R
];
561 if (info
->dwFlags
& JOY_RETURNU
) info
->dwUpos
= state
.axes
[AXIS_U
];
562 if (info
->dwFlags
& JOY_RETURNV
) info
->dwVpos
= state
.axes
[AXIS_V
];
563 if (info
->dwFlags
& JOY_RETURNPOV
)
565 if (state
.pov
== ~0) info
->dwPOV
= 0xffff;
566 else info
->dwPOV
= state
.pov
;
568 if (info
->dwFlags
& JOY_RETURNBUTTONS
)
570 info
->dwButtonNumber
= info
->dwButtons
= 0;
571 for (i
= 0; i
< ARRAY_SIZE(state
.buttons
); ++i
)
573 if (!state
.buttons
[i
]) continue;
574 info
->dwButtonNumber
++;
575 info
->dwButtons
|= 1 << i
;
580 LeaveCriticalSection( &joystick_cs
);
585 /**************************************************************************
586 * joyGetPos [WINMM.@]
588 MMRESULT WINAPI
joyGetPos( UINT id
, JOYINFO
*info
)
592 .dwSize
= sizeof(JOYINFOEX
),
593 .dwFlags
= JOY_RETURNX
| JOY_RETURNY
| JOY_RETURNZ
| JOY_RETURNBUTTONS
,
597 TRACE( "id %u, info %p.\n", id
, info
);
599 if (!info
) return MMSYSERR_INVALPARAM
;
600 if ((res
= joyGetPosEx( id
, &infoex
))) return res
;
602 info
->wXpos
= infoex
.dwXpos
;
603 info
->wYpos
= infoex
.dwYpos
;
604 info
->wZpos
= infoex
.dwZpos
;
605 info
->wButtons
= infoex
.dwButtons
;
607 return JOYERR_NOERROR
;
610 /**************************************************************************
611 * joyGetThreshold [WINMM.@]
613 MMRESULT WINAPI
joyGetThreshold( UINT id
, UINT
*threshold
)
615 TRACE( "id %u, threshold %p.\n", id
, threshold
);
617 if (id
>= ARRAY_SIZE(joysticks
)) return JOYERR_PARMS
;
619 EnterCriticalSection( &joystick_cs
);
620 *threshold
= joysticks
[id
].threshold
;
621 LeaveCriticalSection( &joystick_cs
);
623 return JOYERR_NOERROR
;
626 /**************************************************************************
627 * joyReleaseCapture [WINMM.@]
629 MMRESULT WINAPI
joyReleaseCapture( UINT id
)
631 TRACE( "id %u.\n", id
);
633 if (id
>= ARRAY_SIZE(joysticks
)) return JOYERR_PARMS
;
635 EnterCriticalSection( &joystick_cs
);
637 if (!joysticks
[id
].capture
)
638 TRACE("Joystick is not captured, ignoring request.\n");
641 KillTimer( joysticks
[id
].capture
, joysticks
[id
].timer
);
642 joysticks
[id
].capture
= 0;
643 joysticks
[id
].timer
= 0;
646 LeaveCriticalSection( &joystick_cs
);
648 return JOYERR_NOERROR
;
651 /**************************************************************************
652 * joySetCapture [WINMM.@]
654 MMRESULT WINAPI
joySetCapture( HWND hwnd
, UINT id
, UINT period
, BOOL changed
)
656 MMRESULT res
= JOYERR_NOERROR
;
658 TRACE( "hwnd %p, id %u, period %u, changed %u.\n", hwnd
, id
, period
, changed
);
660 if (id
>= ARRAY_SIZE(joysticks
) || hwnd
== 0) return JOYERR_PARMS
;
661 if (period
< JOY_PERIOD_MIN
) period
= JOY_PERIOD_MIN
;
662 else if (period
> JOY_PERIOD_MAX
) period
= JOY_PERIOD_MAX
;
664 EnterCriticalSection( &joystick_cs
);
666 if (joysticks
[id
].capture
|| !IsWindow( hwnd
))
667 res
= JOYERR_NOCANDO
; /* FIXME: what should be returned ? */
668 else if (joyGetPos( id
, &joysticks
[id
].info
) != JOYERR_NOERROR
)
669 res
= JOYERR_UNPLUGGED
;
670 else if ((joysticks
[id
].timer
= SetTimer( hwnd
, 0, period
, joystick_timer
)) == 0)
671 res
= JOYERR_NOCANDO
;
674 joysticks
[id
].capture
= hwnd
;
675 joysticks
[id
].changed
= changed
;
678 LeaveCriticalSection( &joystick_cs
);
682 /**************************************************************************
683 * joySetThreshold [WINMM.@]
685 MMRESULT WINAPI
joySetThreshold( UINT id
, UINT threshold
)
687 TRACE( "id %u, threshold %u.\n", id
, threshold
);
689 if (id
>= ARRAY_SIZE(joysticks
) || threshold
> 65535) return MMSYSERR_INVALPARAM
;
691 EnterCriticalSection( &joystick_cs
);
692 joysticks
[id
].threshold
= threshold
;
693 LeaveCriticalSection( &joystick_cs
);
695 return JOYERR_NOERROR
;