windows.applicationmodel/tests: Use PathRemoveFileSpecW() instead of PathCchRemoveFil...
[wine.git] / dlls / winmm / joystick.c
blob0285074bd4016684e4b572a02e6d6039ebe04172
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 "initguid.h"
37 #include "dinput.h"
39 #include "winemm.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
45 static CRITICAL_SECTION joystick_cs;
46 static CRITICAL_SECTION_DEBUG critsect_debug =
48 0, 0, &joystick_cs,
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 };
54 struct joystick_state
56 LONG x;
57 LONG y;
58 LONG z;
59 LONG u;
60 LONG v;
61 LONG r;
62 LONG pov;
63 BYTE buttons[32];
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 */
122 struct joystick
124 DIDEVICEINSTANCEW instance;
125 IDirectInputDevice8W *device;
126 struct joystick_state state;
127 HANDLE event;
129 JOYINFO info;
130 HWND capture;
131 UINT timer;
132 DWORD threshold;
133 BOOL changed;
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 );
159 return TRUE;
162 void joystick_unload(void)
164 int i;
166 if (!dinput) return;
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;
183 HANDLE event;
184 DWORD index;
185 HRESULT hr;
187 InitOnceExecuteOnce( &init_once, joystick_load_once, NULL, NULL );
189 if (!dinput) return;
191 index = 0;
192 IDirectInput8_EnumDevices( dinput, DI8DEVCLASS_ALL, enum_instances, &index, DIEDFL_ATTACHEDONLY );
193 TRACE( "found %lu device instances\n", index );
195 while (index--)
197 if (!memcmp( &joysticks[index].instance, &instances[index], sizeof(DIDEVICEINSTANCEW) ))
198 continue;
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 );
219 else
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;
227 continue;
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 )
246 MMRESULT res;
247 JOYINFO info;
248 WORD change;
249 LONG pos;
250 int i;
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 );
260 continue;
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)};
318 DIPROPDWORD diprop =
320 .diph =
322 .dwSize = sizeof(DIPROPDWORD),
323 .dwHeaderSize = sizeof(DIPROPHEADER),
324 .dwHow = DIPH_DEVICE,
327 MMRESULT res = JOYERR_NOERROR;
328 IDirectInputDevice8W *device;
329 ULONG ticks = GetTickCount();
330 HRESULT hr;
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)
347 last_check = ticks;
348 find_joysticks();
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 );
355 res = JOYERR_PARMS;
357 else
359 hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &diprop.diph );
360 if (FAILED(hr)) WARN( "GetProperty device %p returned %#lx\n", device, hr );
361 else
363 caps->wMid = LOWORD(diprop.dwData);
364 caps->wPid = HIWORD(diprop.dwData);
367 wcscpy( caps->szPname, L"Wine joystick driver" );
368 caps->wXmin = 0;
369 caps->wXmax = 0xffff;
370 caps->wYmin = 0;
371 caps->wYmax = 0xffff;
372 caps->wZmin = 0;
373 caps->wZmax = 0xffff;
374 caps->wNumButtons = dicaps.dwButtons;
375 caps->wPeriodMin = JOY_PERIOD_MIN;
376 caps->wPeriodMax = JOY_PERIOD_MAX;
377 caps->wRmin = 0;
378 caps->wRmax = 0xffff;
379 caps->wUmin = 0;
380 caps->wUmax = 0xffff;
381 caps->wVmin = 0;
382 caps->wVmax = 0xffff;
383 caps->wCaps = 0;
384 caps->wMaxAxes = 6;
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 );
402 return res;
405 /**************************************************************************
406 * joyGetDevCapsA [WINMM.@]
408 MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsA( UINT_PTR id, JOYCAPSA *caps, UINT size )
410 UINT size_w = sizeof(JOYCAPS2W);
411 JOYCAPS2W caps_w;
412 MMRESULT res;
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 );
421 if (res) return res;
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;
472 HRESULT hr;
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)
483 last_check = ticks;
484 find_joysticks();
487 if (!(device = joysticks[id].device))
488 res = JOYERR_PARMS;
489 else if (FAILED(hr = IDirectInputDevice8_GetDeviceState( device, sizeof(struct joystick_state), &state )))
491 WARN( "GetDeviceState device %p returned %#lx\n", device, hr );
492 res = JOYERR_PARMS;
494 else
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 );
521 return res;
524 /**************************************************************************
525 * joyGetPos [WINMM.@]
527 MMRESULT WINAPI joyGetPos( UINT id, JOYINFO *info )
529 JOYINFOEX infoex =
531 .dwSize = sizeof(JOYINFOEX),
532 .dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS,
534 MMRESULT res;
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");
578 else
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;
611 else
613 joysticks[id].capture = hwnd;
614 joysticks[id].changed = changed;
617 LeaveCriticalSection( &joystick_cs );
618 return res;
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;