dxgi: Add IDXGISwapChain2 stubs for D3D11.
[wine.git] / dlls / winmm / joystick.c
blob0028b5c168eaadf115a8554fcb5da022a82cfdd4
1 /*
2 * joystick functions
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
25 #include <stdarg.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "mmsystem.h"
36 #include "hidusage.h"
37 #include "initguid.h"
38 #include "dinput.h"
40 #include "winemm.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
46 static CRITICAL_SECTION joystick_cs;
47 static CRITICAL_SECTION_DEBUG critsect_debug =
49 0, 0, &joystick_cs,
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 };
55 enum axis
57 AXIS_X,
58 AXIS_Y,
59 AXIS_Z,
60 AXIS_R,
61 AXIS_U,
62 AXIS_V,
63 AXIS_COUNT,
66 #define BUTTON_COUNT 32
68 struct joystick_state
70 LONG axes[AXIS_COUNT];
71 LONG pov;
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 */
78 struct joystick
80 DIDEVICEINSTANCEW instance;
81 IDirectInputDevice8W *device;
82 struct joystick_state state;
83 HANDLE event;
85 JOYINFO info;
86 HWND capture;
87 UINT timer;
88 DWORD threshold;
89 BOOL changed;
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 );
115 return TRUE;
118 void joystick_unload(void)
120 int i;
122 if (!dinput) return;
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 )
136 DWORD i;
138 for (i = 0; i < count; ++i)
140 if (object_formats[i].dwType == instance_number)
141 return 1;
144 return 0;
147 struct usage_enum_params
149 WORD usage;
150 int found;
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;
168 params->found = 1;
169 return DIENUM_STOP;
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};
180 unsigned int i, j;
182 static const struct
184 WORD usages[5];
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, &params, DIDFT_AXIS )))
211 continue;
212 if (!params.found)
213 continue;
214 if (is_already_mapped( object_formats, data_format.dwNumObjs, params.instance_number ))
215 continue;
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;
220 break;
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;
244 HANDLE event;
245 DWORD index;
246 HRESULT hr;
248 InitOnceExecuteOnce( &init_once, joystick_load_once, NULL, NULL );
250 if (!dinput) return;
252 index = 0;
253 IDirectInput8_EnumDevices( dinput, DI8DEVCLASS_ALL, enum_instances, &index, DIEDFL_ATTACHEDONLY );
254 TRACE( "found %lu device instances\n", index );
256 while (index--)
258 if (!memcmp( &joysticks[index].instance, &instances[index], sizeof(DIDEVICEINSTANCEW) ))
259 continue;
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 );
280 else
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;
288 continue;
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 )
307 MMRESULT res;
308 JOYINFO info;
309 WORD change;
310 LONG pos;
311 int i;
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 );
321 continue;
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)};
379 DIPROPDWORD diprop =
381 .diph =
383 .dwSize = sizeof(DIPROPDWORD),
384 .dwHeaderSize = sizeof(DIPROPHEADER),
385 .dwHow = DIPH_DEVICE,
388 MMRESULT res = JOYERR_NOERROR;
389 IDirectInputDevice8W *device;
390 ULONG ticks = GetTickCount();
391 HRESULT hr;
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)
408 last_check = ticks;
409 find_joysticks();
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 );
416 res = JOYERR_PARMS;
418 else
420 hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &diprop.diph );
421 if (FAILED(hr)) WARN( "GetProperty device %p returned %#lx\n", device, hr );
422 else
424 caps->wMid = LOWORD(diprop.dwData);
425 caps->wPid = HIWORD(diprop.dwData);
428 wcscpy( caps->szPname, L"Wine joystick driver" );
429 caps->wXmin = 0;
430 caps->wXmax = 0xffff;
431 caps->wYmin = 0;
432 caps->wYmax = 0xffff;
433 caps->wZmin = 0;
434 caps->wZmax = 0xffff;
435 caps->wNumButtons = dicaps.dwButtons;
436 caps->wPeriodMin = JOY_PERIOD_MIN;
437 caps->wPeriodMax = JOY_PERIOD_MAX;
438 caps->wRmin = 0;
439 caps->wRmax = 0xffff;
440 caps->wUmin = 0;
441 caps->wUmax = 0xffff;
442 caps->wVmin = 0;
443 caps->wVmax = 0xffff;
444 caps->wCaps = 0;
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 );
463 return res;
466 /**************************************************************************
467 * joyGetDevCapsA [WINMM.@]
469 MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsA( UINT_PTR id, JOYCAPSA *caps, UINT size )
471 UINT size_w = sizeof(JOYCAPS2W);
472 JOYCAPS2W caps_w;
473 MMRESULT res;
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 );
482 if (res) return res;
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;
533 HRESULT hr;
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)
544 last_check = ticks;
545 find_joysticks();
548 if (!(device = joysticks[id].device))
549 res = JOYERR_PARMS;
550 else if (FAILED(hr = IDirectInputDevice8_GetDeviceState( device, sizeof(struct joystick_state), &state )))
552 WARN( "GetDeviceState device %p returned %#lx\n", device, hr );
553 res = JOYERR_PARMS;
555 else
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 );
582 return res;
585 /**************************************************************************
586 * joyGetPos [WINMM.@]
588 MMRESULT WINAPI joyGetPos( UINT id, JOYINFO *info )
590 JOYINFOEX infoex =
592 .dwSize = sizeof(JOYINFOEX),
593 .dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS,
595 MMRESULT res;
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");
639 else
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;
672 else
674 joysticks[id].capture = hwnd;
675 joysticks[id].changed = changed;
678 LeaveCriticalSection( &joystick_cs );
679 return res;
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;