4 * Copyright 1997 Andreas Mohr
6 * nearly all joystick functions can be regarded as obsolete,
7 * as Linux (2.1.x) now supports extended joysticks
8 * with a completely new joystick driver interface
9 * new driver's docu says:
10 * "For backward compatibility the old interface is still included,
11 * but will be dropped in the future."
12 * Thus we should implement the new interface and at most keep the old
13 * routines for backward compatibility.
19 * 01/2000 added support for new joystick driver
29 #include <sys/ioctl.h>
30 #ifdef HAVE_LINUX_JOYSTICK_H
31 #include <linux/joystick.h>
32 #define JOYDEV "/dev/js%d"
34 #ifdef HAVE_SYS_ERRNO_H
35 #include <sys/errno.h>
40 #include "debugtools.h"
42 DEFAULT_DEBUG_CHANNEL(mmsys
)
44 #define MAXJOYSTICK (JOYSTICKID2 + 1)
45 #define JOY_PERIOD_MIN (10) /* min Capture time period */
46 #define JOY_PERIOD_MAX (1000) /* max Capture time period */
48 static int count_use
[MAXJOYSTICK
] = {0, 0};
49 static int joy_nr_open
= 0;
50 static BOOL16 joyCaptured
= FALSE
;
51 static HWND16 CaptureWnd
[MAXJOYSTICK
] = {0, 0};
52 static int joy_dev
[MAXJOYSTICK
] = {-1, -1};
53 static JOYINFO16 joyCapData
[MAXJOYSTICK
];
54 static unsigned int joy_threshold
[MAXJOYSTICK
] = {0, 0};
64 /**************************************************************************
65 * joyOpenDriver [internal]
67 BOOL16
joyOpenDriver(WORD wID
)
72 if (wID
>=MAXJOYSTICK
) return FALSE
;
73 if (joy_dev
[wID
] >= 0) return TRUE
; /* was already open */
74 sprintf(buf
,JOYDEV
,wID
);
76 #ifdef HAVE_LINUX_22_JOYSTICK_API
79 if ((joy_dev
[wID
] = open(buf
, flags
)) >= 0) {
86 /**************************************************************************
87 * joyCloseDriver [internal]
89 void joyCloseDriver(WORD wID
)
91 if (joy_dev
[wID
] >= 0) {
98 /**************************************************************************
99 * joyUpdateCaptureData [internal]
101 #ifdef HAVE_LINUX_22_JOYSTICK_API
102 void joyUpdateCaptureData(WORD wID
)
105 unsigned int ButtonState
;
108 if (joyOpenDriver(wID
) == FALSE
) return;
109 while (read(joy_dev
[wID
], &ev
, sizeof(struct js_event
)) > 0) {
110 if (ev
.type
& JS_EVENT_AXIS
) {
112 joyCapData
[wID
].wXpos
= ev
.value
+ 32767;
114 joyCapData
[wID
].wYpos
= ev
.value
+ 32767;
115 if (ev
.number
<= 1) /* Message for X, Y-Axis */
116 SendMessageA(CaptureWnd
[wID
], MM_JOY1MOVE
+ wID
,
117 joyCapData
[wID
].wButtons
,
118 MAKELONG(joyCapData
[wID
].wXpos
,
119 joyCapData
[wID
].wYpos
));
120 if (ev
.number
== 2) { /* Message for Z-axis */
121 joyCapData
[wID
].wZpos
= ev
.value
+ 32767;
122 SendMessageA(CaptureWnd
[wID
], MM_JOY1ZMOVE
+ wID
,
123 joyCapData
[wID
].wButtons
,
124 joyCapData
[wID
].wZpos
);
126 } else if (ev
.type
& JS_EVENT_BUTTON
) {
128 joyCapData
[wID
].wButtons
|= (1 << ev
.number
);
129 messageType
= MM_JOY1BUTTONDOWN
;
131 joyCapData
[wID
].wButtons
&= ~(1 << ev
.number
);
132 messageType
= MM_JOY1BUTTONUP
;
134 /* create button state with changed buttons and
136 ButtonState
= ((1 << (ev
.number
+ 8)) & 0xFF00) |
137 (joyCapData
[wID
].wButtons
& 0xFF);
138 SendMessageA(CaptureWnd
[wID
], messageType
+ wID
,
140 MAKELONG(joyCapData
[wID
].wXpos
,
141 joyCapData
[wID
].wYpos
));
144 /* EAGAIN is returned when the queue is empty */
145 if (errno
!= EAGAIN
) {
146 /* FIXME: error should not be ignored */
151 /**************************************************************************
152 * joySendMessages [internal]
154 void joySendMessages(void)
157 #ifndef HAVE_LINUX_22_JOYSTICK_API
162 for (joy
=0; joy
< MAXJOYSTICK
; joy
++)
163 if (joy_dev
[joy
] >= 0) {
164 if (count_use
[joy
] > 250) {
172 if (joyCaptured
== FALSE
) return;
176 #ifdef HAVE_LINUX_22_JOYSTICK_API
177 for (joy
=0; joy
< MAXJOYSTICK
; joy
++)
178 joyUpdateCaptureData(joy
);
181 for (joy
=0; joy
< MAXJOYSTICK
; joy
++) {
184 if (joyOpenDriver(joy
) == FALSE
) continue;
185 dev_stat
= read(joy_dev
[joy
], &js
, sizeof(js
));
186 if (dev_stat
== sizeof(js
)) {
189 if ((joyCapData
[joy
].wXpos
!= js
.x
) || (joyCapData
[joy
].wYpos
!= js
.y
)) {
190 SendMessageA(CaptureWnd
[joy
], MM_JOY1MOVE
+ joy
, js
.buttons
, MAKELONG(js
.x
, js
.y
));
191 joyCapData
[joy
].wXpos
= js
.x
;
192 joyCapData
[joy
].wYpos
= js
.y
;
194 if (joyCapData
[joy
].wButtons
!= js
.buttons
) {
195 unsigned int ButtonChanged
= (WORD
)(joyCapData
[joy
].wButtons
^ js
.buttons
)<<8;
196 if (joyCapData
[joy
].wButtons
< js
.buttons
)
197 SendMessageA(CaptureWnd
[joy
], MM_JOY1BUTTONDOWN
+ joy
, ButtonChanged
, MAKELONG(js
.x
, js
.y
));
199 if (joyCapData
[joy
].wButtons
> js
.buttons
)
200 SendMessageA(CaptureWnd
[joy
], MM_JOY1BUTTONUP
201 + joy
, ButtonChanged
, MAKELONG(js
.x
, js
.y
));
202 joyCapData
[joy
].wButtons
= js
.buttons
;
210 /**************************************************************************
211 * JoyGetNumDevs [MMSYSTEM.101]
213 UINT WINAPI
joyGetNumDevs(void)
215 return joyGetNumDevs16();
218 /**************************************************************************
219 * JoyGetNumDevs [MMSYSTEM.101]
221 UINT16 WINAPI
joyGetNumDevs16(void)
226 for (joy=0; joy<MAXJOYSTICK; joy++)
227 if (joyOpenDriver(joy) == TRUE) {
231 TRACE("returning %d\n", joy_cnt);
232 if (!joy_cnt) ERR("No joystick found - "
233 "perhaps get joystick-0.8.0.tar.gz and load"
234 "it as module or use Linux >= 2.1.45 to be "
235 "able to use joysticks.\n");
238 /* simply return the max. nr. of supported joysticks. The rest
239 will be done with joyGetPos or joyGetDevCaps. Look at
240 MS Joystick Driver */
245 /**************************************************************************
246 * JoyGetDevCaps [WINMM.27]
248 MMRESULT WINAPI
joyGetDevCapsA(UINT wID
, LPJOYCAPSA lpCaps
,UINT wSize
)
251 MMRESULT16 ret
= joyGetDevCaps16(wID
,&jc16
,sizeof(jc16
));
253 if (ret
!= JOYERR_NOERROR
) return ret
;
254 lpCaps
->wMid
= jc16
.wMid
;
255 lpCaps
->wPid
= jc16
.wPid
;
256 strcpy(lpCaps
->szPname
,jc16
.szPname
);
257 lpCaps
->wXmin
= jc16
.wXmin
;
258 lpCaps
->wXmax
= jc16
.wXmax
;
259 lpCaps
->wYmin
= jc16
.wYmin
;
260 lpCaps
->wYmax
= jc16
.wYmax
;
261 lpCaps
->wZmin
= jc16
.wZmin
;
262 lpCaps
->wZmax
= jc16
.wZmax
;
263 lpCaps
->wNumButtons
= jc16
.wNumButtons
;
264 lpCaps
->wPeriodMin
= jc16
.wPeriodMin
;
265 lpCaps
->wPeriodMax
= jc16
.wPeriodMax
;
267 lpCaps
->wRmin
= jc16
.wRmin
;
268 lpCaps
->wRmax
= jc16
.wRmax
;
269 lpCaps
->wUmin
= jc16
.wUmin
;
270 lpCaps
->wUmax
= jc16
.wUmax
;
271 lpCaps
->wVmin
= jc16
.wVmin
;
272 lpCaps
->wVmax
= jc16
.wVmax
;
273 lpCaps
->wCaps
= jc16
.wCaps
;
274 lpCaps
->wMaxAxes
= jc16
.wMaxAxes
;
275 lpCaps
->wNumAxes
= jc16
.wNumAxes
;
276 lpCaps
->wMaxButtons
= jc16
.wMaxButtons
;
277 strcpy(lpCaps
->szRegKey
,jc16
.szRegKey
);
278 strcpy(lpCaps
->szOEMVxD
,jc16
.szOEMVxD
);
282 /**************************************************************************
283 * JoyGetDevCaps [WINMM.28]
285 MMRESULT WINAPI
joyGetDevCapsW(UINT wID
, LPJOYCAPSW lpCaps
,UINT wSize
)
288 MMRESULT16 ret
= joyGetDevCaps16(wID
,&jc16
,sizeof(jc16
));
290 if (ret
!= JOYERR_NOERROR
) return ret
;
291 lpCaps
->wMid
= jc16
.wMid
;
292 lpCaps
->wPid
= jc16
.wPid
;
293 lstrcpyAtoW(lpCaps
->szPname
,jc16
.szPname
);
294 lpCaps
->wXmin
= jc16
.wXmin
;
295 lpCaps
->wXmax
= jc16
.wXmax
;
296 lpCaps
->wYmin
= jc16
.wYmin
;
297 lpCaps
->wYmax
= jc16
.wYmax
;
298 lpCaps
->wZmin
= jc16
.wZmin
;
299 lpCaps
->wZmax
= jc16
.wZmax
;
300 lpCaps
->wNumButtons
= jc16
.wNumButtons
;
301 lpCaps
->wPeriodMin
= jc16
.wPeriodMin
;
302 lpCaps
->wPeriodMax
= jc16
.wPeriodMax
;
304 lpCaps
->wRmin
= jc16
.wRmin
;
305 lpCaps
->wRmax
= jc16
.wRmax
;
306 lpCaps
->wUmin
= jc16
.wUmin
;
307 lpCaps
->wUmax
= jc16
.wUmax
;
308 lpCaps
->wVmin
= jc16
.wVmin
;
309 lpCaps
->wVmax
= jc16
.wVmax
;
310 lpCaps
->wCaps
= jc16
.wCaps
;
311 lpCaps
->wMaxAxes
= jc16
.wMaxAxes
;
312 lpCaps
->wNumAxes
= jc16
.wNumAxes
;
313 lpCaps
->wMaxButtons
= jc16
.wMaxButtons
;
314 lstrcpyAtoW(lpCaps
->szRegKey
,jc16
.szRegKey
);
315 lstrcpyAtoW(lpCaps
->szOEMVxD
,jc16
.szOEMVxD
);
318 /**************************************************************************
319 * JoyGetDevCaps [MMSYSTEM.102]
321 MMRESULT16 WINAPI
joyGetDevCaps16(UINT16 wID
, LPJOYCAPS16 lpCaps
, UINT16 wSize
)
323 TRACE("(%04X, %p, %d);\n",
325 if (wID
>= MAXJOYSTICK
) return MMSYSERR_NODRIVER
;
326 #ifdef HAVE_LINUX_22_JOYSTICK_API
327 if (joyOpenDriver(wID
) == TRUE
) {
330 char identString
[MAXPNAMELEN
];
333 ioctl(joy_dev
[wID
], JSIOCGAXES
, &nrOfAxes
);
334 ioctl(joy_dev
[wID
], JSIOCGBUTTONS
, &nrOfButtons
);
335 ioctl(joy_dev
[wID
], JSIOCGVERSION
, &driverVersion
);
336 ioctl(joy_dev
[wID
], JSIOCGNAME(sizeof(identString
)),
338 TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
339 driverVersion
, identString
, nrOfAxes
, nrOfButtons
);
340 lpCaps
->wMid
= MM_MICROSOFT
;
341 lpCaps
->wPid
= MM_PC_JOYSTICK
;
342 strncpy(lpCaps
->szPname
, identString
, MAXPNAMELEN
);
343 lpCaps
->szPname
[MAXPNAMELEN
-1]='\0';
345 lpCaps
->wXmax
= 0xFFFF;
347 lpCaps
->wYmax
= 0xFFFF;
349 lpCaps
->wZmax
= nrOfAxes
>= 3 ? 0xFFFF : 0;
350 lpCaps
->wNumButtons
= nrOfButtons
;
351 lpCaps
->wPeriodMin
= JOY_PERIOD_MIN
; /* FIXME */
352 lpCaps
->wPeriodMax
= JOY_PERIOD_MAX
; /* FIXME (same as MS Joystick Driver */
353 if (wSize
== sizeof(JOYCAPS16
)) {
354 /* complete 95 structure */
356 lpCaps
->wRmax
= nrOfAxes
>= 4 ? 0xFFFF : 0;
358 lpCaps
->wUmax
= nrOfAxes
>= 5 ? 0xFFFF : 0;
360 lpCaps
->wVmax
= nrOfAxes
>= 6 ? 0xFFFF : 0;
361 lpCaps
->wMaxAxes
= 6; /* same as MS Joystick Driver */
362 lpCaps
->wNumAxes
= nrOfAxes
; /* nr of axes in use */
363 lpCaps
->wMaxButtons
= 32; /* same as MS Joystick Driver */
364 strcpy(lpCaps
->szRegKey
,"");
365 strcpy(lpCaps
->szOEMVxD
,"");
368 case 6: lpCaps
->wCaps
|= JOYCAPS_HASV
;
369 case 5: lpCaps
->wCaps
|= JOYCAPS_HASU
;
370 case 4: lpCaps
->wCaps
|= JOYCAPS_HASR
;
371 case 3: lpCaps
->wCaps
|= JOYCAPS_HASZ
;
372 /* FIXME: don't know how to detect for
373 JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
377 return JOYERR_NOERROR
;
381 if (joyOpenDriver(wID
) == TRUE
) {
382 lpCaps
->wMid
= MM_MICROSOFT
;
383 lpCaps
->wPid
= MM_PC_JOYSTICK
;
384 strcpy(lpCaps
->szPname
, "WineJoy"); /* joystick product name */
386 lpCaps
->wXmax
= 0xFFFF;
388 lpCaps
->wYmax
= 0xFFFF;
391 lpCaps
->wNumButtons
= 2;
392 lpCaps
->wPeriodMin
= JOY_PERIOD_MIN
; /* FIXME */
393 lpCaps
->wPeriodMax
= JOY_PERIOD_MAX
; /* FIXME end */
394 if (wSize
== sizeof(JOYCAPS16
)) {
395 /* complete 95 structure */
403 lpCaps
->wMaxAxes
= 2;
404 lpCaps
->wNumAxes
= 2;
405 lpCaps
->wMaxButtons
= 4;
406 strcpy(lpCaps
->szRegKey
,"");
407 strcpy(lpCaps
->szOEMVxD
,"");
410 return JOYERR_NOERROR
;
416 /**************************************************************************
417 * JoyGetPosEx [WINMM.31]
419 MMRESULT WINAPI
joyGetPosEx(UINT wID
, LPJOYINFOEX lpInfo
)
421 return joyGetPosEx16(wID
, lpInfo
);
424 /**************************************************************************
425 * JoyGetPosEx [WINMM.31]
427 MMRESULT16 WINAPI
joyGetPosEx16(UINT16 wID
, LPJOYINFOEX lpInfo
)
430 TRACE("(%04X, %p)\n", wID
, lpInfo
);
432 if (wID
< MAXJOYSTICK
) {
433 #ifdef HAVE_LINUX_22_JOYSTICK_API
437 if (joyOpenDriver(wID
) == FALSE
) return JOYERR_PARMS
;
438 lpInfo
->dwSize
= sizeof(JOYINFOEX
);
439 lpInfo
->dwXpos
= lpInfo
->dwYpos
=lpInfo
->dwZpos
= 0;
440 lpInfo
->dwButtons
= lpInfo
->dwFlags
= 0;
441 /* After opening the device it's state can be
442 read with JS_EVENT_INIT flag */
443 while ((read(joy_dev
[wID
], &ev
, sizeof(struct js_event
))) > 0) {
444 if (ev
.type
== (JS_EVENT_AXIS
| JS_EVENT_INIT
)) {
446 case 0: lpInfo
->dwXpos
= ev
.value
+ 32767;
447 lpInfo
->dwFlags
|= JOY_RETURNX
; break;
448 case 1: lpInfo
->dwYpos
= ev
.value
+ 32767;
449 lpInfo
->dwFlags
|= JOY_RETURNY
; break;
450 case 2: lpInfo
->dwZpos
= ev
.value
+ 32767;
451 lpInfo
->dwFlags
|= JOY_RETURNZ
; break;
452 case 3: lpInfo
->dwRpos
= ev
.value
+ 32767;
453 lpInfo
->dwFlags
|= JOY_RETURNR
; break;
454 case 4: lpInfo
->dwUpos
= ev
.value
+ 32767;
455 lpInfo
->dwFlags
|= JOY_RETURNU
; break;
456 case 5: lpInfo
->dwVpos
= ev
.value
+ 32767;
457 lpInfo
->dwFlags
|= JOY_RETURNV
; break;
459 } else if (ev
.type
==
460 (JS_EVENT_BUTTON
| JS_EVENT_INIT
)) {
462 lpInfo
->dwButtons
|= (1 << ev
.number
);
464 lpInfo
->dwButtons
&= ~(1 << ev
.number
);
465 lpInfo
->dwFlags
|= JOY_RETURNBUTTONS
;
468 /* EAGAIN is returned when the queue is empty */
469 if (errno
!= EAGAIN
) {
470 /* FIXME: error should not be ignored */
473 TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, \
474 buttons: 0x%04x, flags: 0x%04x\n",
475 lpInfo
->dwXpos
, lpInfo
->dwYpos
, lpInfo
->dwZpos
,
476 lpInfo
->dwRpos
, lpInfo
->dwUpos
, lpInfo
->dwVpos
,
477 (unsigned int)lpInfo
->dwButtons
,
478 (unsigned int)lpInfo
->dwFlags
);
479 return JOYERR_NOERROR
;
484 if (joyOpenDriver(wID
) == FALSE
) return JOYERR_UNPLUGGED
;
485 dev_stat
= read(joy_dev
[wID
], &js
, sizeof(js
));
486 if (dev_stat
!= sizeof(js
)) {
488 return JOYERR_UNPLUGGED
; /* FIXME: perhaps wrong, but what should I return else ? */
493 lpInfo
->dwXpos
= js
.x
; /* FIXME: perhaps multiply it somehow ? */
494 lpInfo
->dwYpos
= js
.y
;
496 lpInfo
->dwButtons
= js
.buttons
;
497 lpInfo
->dwFlags
= JOY_RETURNX
| JOY_RETURNY
| JOY_RETURNBUTTONS
;
498 TRACE("x: %ld, y: %ld, buttons: 0x%04x, flags: 0x%04x\n",
499 lpInfo
->dwXpos
, lpInfo
->dwYpos
,
500 (unsigned int)lpInfo
->dwButtons
,
501 (unsigned int)lpInfo
->dwFlags
);
502 return JOYERR_NOERROR
;
508 /**************************************************************************
509 * JoyGetPos [WINMM.30]
511 MMRESULT WINAPI
joyGetPos(UINT wID
, LPJOYINFO lpInfo
)
516 TRACE("(%d, %p);\n", wID
, lpInfo
);
518 ret
= joyGetPosEx16(wID
,&ji
);
519 lpInfo
->wXpos
= ji
.dwXpos
;
520 lpInfo
->wYpos
= ji
.dwYpos
;
521 lpInfo
->wZpos
= ji
.dwZpos
;
522 lpInfo
->wButtons
= ji
.dwButtons
;
526 /**************************************************************************
527 * JoyGetPos16 [MMSYSTEM.103]
529 MMRESULT16 WINAPI
joyGetPos16(UINT16 wID
, LPJOYINFO16 lpInfo
)
534 TRACE("(%d, %p);\n", wID
, lpInfo
);
536 ret
= joyGetPosEx16(wID
,&ji
);
537 lpInfo
->wXpos
= ji
.dwXpos
;
538 lpInfo
->wYpos
= ji
.dwYpos
;
539 lpInfo
->wZpos
= ji
.dwZpos
;
540 lpInfo
->wButtons
= ji
.dwButtons
;
544 /**************************************************************************
545 * JoyGetThreshold [WINMM.32]
547 MMRESULT WINAPI
joyGetThreshold(UINT wID
, LPUINT lpThreshold
)
550 MMRESULT16 ret
= joyGetThreshold16(wID
,&thresh
);
552 *lpThreshold
= thresh
;
556 /**************************************************************************
557 * JoyGetThreshold [MMSYSTEM.104]
559 MMRESULT16 WINAPI
joyGetThreshold16(UINT16 wID
, LPUINT16 lpThreshold
)
561 TRACE("(%04X, %p);\n", wID
, lpThreshold
);
562 if (wID
>= MAXJOYSTICK
) return MMSYSERR_INVALPARAM
;
563 *lpThreshold
= joy_threshold
[wID
];
564 return JOYERR_NOERROR
;
567 /**************************************************************************
568 * JoyReleaseCapture [WINMM.33]
570 MMRESULT WINAPI
joyReleaseCapture(UINT wID
)
572 return joyReleaseCapture16(wID
);
575 /**************************************************************************
576 * JoyReleaseCapture [MMSYSTEM.105]
578 MMRESULT16 WINAPI
joyReleaseCapture16(UINT16 wID
)
580 TRACE("(%04X);\n", wID
);
581 if (wID
>= MAXJOYSTICK
) return MMSYSERR_INVALPARAM
;
586 return JOYERR_NOERROR
;
589 /**************************************************************************
590 * JoySetCapture [MMSYSTEM.106]
592 MMRESULT WINAPI
joySetCapture(HWND hWnd
,UINT wID
,UINT wPeriod
,BOOL bChanged
)
594 return joySetCapture16(hWnd
,wID
,wPeriod
,bChanged
);
597 /**************************************************************************
598 * JoySetCapture [MMSYSTEM.106]
600 MMRESULT16 WINAPI
joySetCapture16(HWND16 hWnd
,UINT16 wID
,UINT16 wPeriod
,BOOL16 bChanged
)
603 TRACE("(%04X, %04X, %d, %d);\n",
604 hWnd
, wID
, wPeriod
, bChanged
);
605 if (wID
>= MAXJOYSTICK
) return JOYERR_PARMS
;
606 if (hWnd
== 0) return JOYERR_PARMS
;
607 if (wPeriod
<JOY_PERIOD_MIN
|| wPeriod
>JOY_PERIOD_MAX
) return JOYERR_PARMS
;
608 if (!CaptureWnd
[wID
]) {
609 if (joyOpenDriver(wID
) == FALSE
) return JOYERR_PARMS
;
611 CaptureWnd
[wID
] = hWnd
;
612 joyCapData
[wID
].wXpos
= 0;
613 joyCapData
[wID
].wYpos
= 0;
614 joyCapData
[wID
].wZpos
= 0;
615 joyCapData
[wID
].wButtons
= 0;
616 return JOYERR_NOERROR
;
618 return JOYERR_NOCANDO
; /* FIXME: what should be returned ? */
621 /**************************************************************************
622 * JoySetThreshold [WINMM.35]
624 MMRESULT WINAPI
joySetThreshold(UINT wID
, UINT wThreshold
)
626 return joySetThreshold16(wID
,wThreshold
);
628 /**************************************************************************
629 * JoySetThreshold [MMSYSTEM.107]
631 MMRESULT16 WINAPI
joySetThreshold16(UINT16 wID
, UINT16 wThreshold
)
633 TRACE("(%04X, %d);\n", wID
, wThreshold
);
635 if (wID
>= MAXJOYSTICK
) return MMSYSERR_INVALPARAM
;
636 joy_threshold
[wID
] = wThreshold
;
637 return JOYERR_NOERROR
;
640 /**************************************************************************
641 * JoySetCalibration [MMSYSTEM.109]
643 MMRESULT16 WINAPI
joySetCalibration16(UINT16 wID
)
645 FIXME("(%04X): stub.\n", wID
);
646 return JOYERR_NOCANDO
;