Fix the case of product and company names.
[wine] / dlls / winmm / joystick / joystick.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * joystick functions
4  *
5  * Copyright 1997 Andreas Mohr
6  * Copyright 2000 Wolfgang Schwotzer
7  * Copyright 2002 David Hagood
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * NOTES:
24  *
25  * nearly all joystick functions can be regarded as obsolete,
26  * as Linux (2.1.x) now supports extended joysticks
27  * with a completely new joystick driver interface
28  * new driver's docu says:
29  * "For backward compatibility the old interface is still included,
30  * but will be dropped in the future."
31  * Thus we should implement the new interface and at most keep the old
32  * routines for backward compatibility.
33  */
34
35 #include "config.h"
36
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <fcntl.h>
45 #ifdef HAVE_SYS_IOCTL_H
46 #include <sys/ioctl.h>
47 #endif
48 #ifdef HAVE_LINUX_JOYSTICK_H
49 #include <linux/joystick.h>
50 #define JOYDEV "/dev/js%d"
51 #endif
52 #ifdef HAVE_SYS_ERRNO_H
53 #include <sys/errno.h>
54 #endif
55
56 #include "windef.h"
57 #include "winbase.h"
58 #include "wingdi.h"
59 #include "winuser.h"
60 #include "mmddk.h"
61 #include "wine/debug.h"
62
63 WINE_DEFAULT_DEBUG_CHANNEL(joystick);
64
65 #ifdef HAVE_LINUX_JOYSTICK_H
66
67 #define MAXJOYSTICK     (JOYSTICKID2 + 1)
68
69 typedef struct tagWINE_JSTCK {
70     int         joyIntf;
71     int         in_use;
72     /* Some extra info we need to make this acutaly work under the
73        Linux 2.2 event api.
74        First of all, we cannot keep closing and reopening the device file -
75        that blows away the state of the stick device, and we lose events. So, we
76        need to open the low-level device once, and close it when we are done.
77
78        Secondly, the event API only gives us what's changed. However, Windows apps
79        want the whole state every time, so we have to cache the data.
80     */
81
82     int         dev; /* Linux level device file descriptor */
83     int         x;
84     int         y;
85     int         z;
86     int         r;
87     int         u;
88     int         v;
89     int         buttons;
90 } WINE_JSTCK;
91
92 static  WINE_JSTCK      JSTCK_Data[MAXJOYSTICK];
93
94 /**************************************************************************
95  *                              JSTCK_drvGet                    [internal]
96  */
97 static  WINE_JSTCK*     JSTCK_drvGet(DWORD dwDevID)
98 {
99     int p;
100
101     if ((dwDevID - (DWORD)JSTCK_Data) % sizeof(JSTCK_Data[0]) != 0)
102         return NULL;
103     p = (dwDevID - (DWORD)JSTCK_Data) / sizeof(JSTCK_Data[0]);
104     if (p < 0 || p >= MAXJOYSTICK || !((WINE_JSTCK*)dwDevID)->in_use)
105         return NULL;
106
107     return (WINE_JSTCK*)dwDevID;
108 }
109
110 /**************************************************************************
111  *                              JSTCK_drvOpen                   [internal]
112  */
113 static  DWORD   JSTCK_drvOpen(LPSTR str, DWORD dwIntf)
114 {
115     if (dwIntf >= MAXJOYSTICK || JSTCK_Data[dwIntf].in_use)
116         return 0;
117
118     JSTCK_Data[dwIntf].joyIntf = dwIntf;
119     JSTCK_Data[dwIntf].in_use = 1;
120     return (DWORD)&JSTCK_Data[dwIntf];
121 }
122
123 /**************************************************************************
124  *                              JSTCK_drvClose                  [internal]
125  */
126 static  DWORD   JSTCK_drvClose(DWORD dwDevID)
127 {
128     WINE_JSTCK* jstck = JSTCK_drvGet(dwDevID);
129
130     if (jstck == NULL)
131         return 0;
132     jstck->in_use = 0;
133     if (jstck->dev > 0)
134     {
135        close(jstck->dev);
136        jstck->dev = 0;
137     }
138     return 1;
139 }
140
141 struct js_status
142 {
143     int buttons;
144     int x;
145     int y;
146 };
147
148 /**************************************************************************
149  *                              JSTCK_OpenDevice           [internal]
150  */
151 static  int     JSTCK_OpenDevice(WINE_JSTCK* jstick)
152 {
153     char        buf[20];
154     int         flags;
155
156     if (jstick->dev > 0)
157       return jstick->dev;
158
159     sprintf(buf, JOYDEV, jstick->joyIntf);
160 #ifdef HAVE_LINUX_22_JOYSTICK_API
161     flags = O_RDONLY | O_NONBLOCK;
162 #else
163     flags = O_RDONLY;
164 #endif
165     return (jstick->dev = open(buf, flags));
166 }
167
168 /**************************************************************************
169  *                              JoyGetDevCaps           [MMSYSTEM.102]
170  */
171 static  LONG    JSTCK_GetDevCaps(DWORD dwDevID, LPJOYCAPSA lpCaps, DWORD dwSize)
172 {
173     WINE_JSTCK* jstck;
174 #ifdef HAVE_LINUX_22_JOYSTICK_API
175     int         dev;
176     char        nrOfAxes;
177     char        nrOfButtons;
178     char        identString[MAXPNAMELEN];
179     int         driverVersion;
180 #endif
181
182     if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
183         return MMSYSERR_NODRIVER;
184
185 #ifdef HAVE_LINUX_22_JOYSTICK_API
186     if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
187     ioctl(dev, JSIOCGAXES, &nrOfAxes);
188     ioctl(dev, JSIOCGBUTTONS, &nrOfButtons);
189     ioctl(dev, JSIOCGVERSION, &driverVersion);
190     ioctl(dev, JSIOCGNAME(sizeof(identString)), &identString);
191     TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
192           driverVersion, identString, nrOfAxes, nrOfButtons);
193     lpCaps->wMid = MM_MICROSOFT;
194     lpCaps->wPid = MM_PC_JOYSTICK;
195     strncpy(lpCaps->szPname, identString, MAXPNAMELEN);
196     lpCaps->szPname[MAXPNAMELEN-1] = '\0';
197     lpCaps->wXmin = 0;
198     lpCaps->wXmax = 0xFFFF;
199     lpCaps->wYmin = 0;
200     lpCaps->wYmax = 0xFFFF;
201     lpCaps->wZmin = 0;
202     lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0;
203 #ifdef BODGE_THE_HAT
204     /* HalfLife won't allow you to map an axis event to things like
205        "next weapon" and "use". Linux reports the hat on my stick as
206        axis U and V. So, IFF BODGE_THE_HAT is defined, lie through our
207        teeth and say we have 32 buttons, and we will map the axises to
208        the high buttons. Really, perhaps this should be a registry entry,
209        or even a parameter to the Linux joystick driver (which would completely
210        remove the need for this.)
211     */
212     lpCaps->wNumButtons = 32;
213 #else
214     lpCaps->wNumButtons = nrOfButtons;
215 #endif
216     if (dwSize == sizeof(JOYCAPSA)) {
217         /* since we suppose ntOfAxes <= 6 in the following code, do it explicitly */
218         if (nrOfAxes > 6) nrOfAxes = 6;
219         /* complete 95 structure */
220         lpCaps->wRmin = 0;
221         lpCaps->wRmax = nrOfAxes >= 4 ? 0xFFFF : 0;
222         lpCaps->wUmin = 0;
223         lpCaps->wUmax = nrOfAxes >= 5 ? 0xFFFF : 0;
224         lpCaps->wVmin = 0;
225         lpCaps->wVmax = nrOfAxes >= 6 ? 0xFFFF : 0;
226         lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */
227         lpCaps->wNumAxes = nrOfAxes; /* nr of axes in use */
228         lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */
229         strcpy(lpCaps->szRegKey, "");
230         strcpy(lpCaps->szOEMVxD, "");
231         lpCaps->wCaps = 0;
232         switch(nrOfAxes) {
233         case 6: lpCaps->wCaps |= JOYCAPS_HASV;
234         case 5: lpCaps->wCaps |= JOYCAPS_HASU;
235         case 4: lpCaps->wCaps |= JOYCAPS_HASR;
236         case 3: lpCaps->wCaps |= JOYCAPS_HASZ;
237             /* FIXME: don't know how to detect for
238                JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
239         }
240     }
241 #else
242     lpCaps->wMid = MM_MICROSOFT;
243     lpCaps->wPid = MM_PC_JOYSTICK;
244     strcpy(lpCaps->szPname, "WineJoy"); /* joystick product name */
245     lpCaps->wXmin = 0;
246     lpCaps->wXmax = 0xFFFF;
247     lpCaps->wYmin = 0;
248     lpCaps->wYmax = 0xFFFF;
249     lpCaps->wZmin = 0;
250     lpCaps->wZmax = 0;
251     lpCaps->wNumButtons = 2;
252     if (dwSize == sizeof(JOYCAPSA)) {
253         /* complete 95 structure */
254         lpCaps->wRmin = 0;
255         lpCaps->wRmax = 0;
256         lpCaps->wUmin = 0;
257         lpCaps->wUmax = 0;
258         lpCaps->wVmin = 0;
259         lpCaps->wVmax = 0;
260         lpCaps->wCaps = 0;
261         lpCaps->wMaxAxes = 2;
262         lpCaps->wNumAxes = 2;
263         lpCaps->wMaxButtons = 4;
264         strcpy(lpCaps->szRegKey,"");
265         strcpy(lpCaps->szOEMVxD,"");
266     }
267 #endif
268
269     return JOYERR_NOERROR;
270 }
271
272 /**************************************************************************
273  *                              JSTCK_GetPos                    [internal]
274  */
275 static LONG     JSTCK_GetPosEx(DWORD dwDevID, LPJOYINFOEX lpInfo)
276 {
277     WINE_JSTCK*         jstck;
278     int                 dev;
279 #ifdef HAVE_LINUX_22_JOYSTICK_API
280     struct js_event     ev;
281 #else
282     struct js_status    js;
283     int                 dev_stat;
284 #endif
285
286     if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
287         return MMSYSERR_NODRIVER;
288
289     if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
290
291 #ifdef HAVE_LINUX_22_JOYSTICK_API
292     while ((read(dev, &ev, sizeof(struct js_event))) > 0) {
293         if (ev.type == (JS_EVENT_AXIS)) {
294             switch (ev.number) {
295             case 0:
296                 jstck->x = ev.value;
297                 break;
298             case 1:
299                 jstck->y = ev.value;
300                 break;
301             case 2:
302                 jstck->z = ev.value;
303                 break;
304             case 3:
305                 jstck->r = ev.value;
306                 break;
307             case 4:
308                 jstck->u = ev.value;
309                 break;
310             case 5:
311                 jstck->v = ev.value;
312                 break;
313             default:
314                 FIXME("Unknown joystick event '%d'\n", ev.number);
315             }
316         } else if (ev.type == (JS_EVENT_BUTTON)) {
317             if (ev.value) {
318                     jstck->buttons |= (1 << ev.number);
319                     /* FIXME: what to do for this field when
320                      * multiple buttons are depressed ?
321                      */
322                     if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
323                        lpInfo->dwButtonNumber = ev.number + 1;
324                 }
325              else
326                jstck->buttons  &= ~(1 << ev.number);
327         }
328     }
329     /* EAGAIN is returned when the queue is empty */
330     if (errno != EAGAIN) {
331         /* FIXME: error should not be ignored */
332         ERR("Error while reading joystick state (%s)\n", strerror(errno));
333     }
334     /* Now, copy the cached values into Window's structure... */
335     if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
336        lpInfo->dwButtons = jstck->buttons;
337     if (lpInfo->dwFlags & JOY_RETURNX)
338        lpInfo->dwXpos   = jstck->x + 32767;
339     if (lpInfo->dwFlags & JOY_RETURNY)
340        lpInfo->dwYpos   = jstck->y + 32767;
341     if (lpInfo->dwFlags & JOY_RETURNZ)
342        lpInfo->dwZpos   = jstck->z + 32767;
343     if (lpInfo->dwFlags & JOY_RETURNR)
344        lpInfo->dwRpos   = jstck->r + 32767;
345     #ifdef BODGE_THE_HAT
346     else if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
347     {
348          if (jstck->r > 0)
349             lpInfo->dwButtons |= 1<<7;
350          else if (jstck->r < 0)
351             lpInfo->dwButtons |= 1<<8;
352     }
353     #endif
354     if (lpInfo->dwFlags & JOY_RETURNU)
355         lpInfo->dwUpos   = jstck->u + 32767;
356     #ifdef BODGE_THE_HAT
357     else if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
358     {
359        if (jstck->u > 0)
360           lpInfo->dwButtons |= 1<<9;
361         else if (jstck->u < 0)
362           lpInfo->dwButtons |= 1<<10;
363     }
364     #endif
365     if (lpInfo->dwFlags & JOY_RETURNV)
366        lpInfo->dwVpos   = jstck->v + 32767;
367
368 #else
369     dev_stat = read(dev, &js, sizeof(js));
370     if (dev_stat != sizeof(js)) {
371         return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */
372     }
373     js.x = js.x<<8;
374     js.y = js.y<<8;
375     if (lpInfo->dwFlags & JOY_RETURNX)
376         lpInfo->dwXpos = js.x;   /* FIXME: perhaps multiply it somehow ? */
377     if (lpInfo->dwFlags & JOY_RETURNY)
378         lpInfo->dwYpos = js.y;
379     if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
380         lpInfo->dwButtons = js.buttons;
381 #endif
382
383     TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x (fd %d)\n",
384           lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos,
385           lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos,
386           (unsigned int)lpInfo->dwButtons,
387           (unsigned int)lpInfo->dwFlags,
388           dev
389          );
390
391     return JOYERR_NOERROR;
392 }
393
394 /**************************************************************************
395  *                              JSTCK_GetPos                    [internal]
396  */
397 static LONG     JSTCK_GetPos(DWORD dwDevID, LPJOYINFO lpInfo)
398 {
399     JOYINFOEX   ji;
400     LONG        ret;
401
402     memset(&ji, 0, sizeof(ji));
403
404     ji.dwSize = sizeof(ji);
405     ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
406     ret = JSTCK_GetPosEx(dwDevID, &ji);
407     if (ret == JOYERR_NOERROR)  {
408         lpInfo->wXpos    = ji.dwXpos;
409         lpInfo->wYpos    = ji.dwYpos;
410         lpInfo->wZpos    = ji.dwZpos;
411         lpInfo->wButtons = ji.dwButtons;
412     }
413
414     return ret;
415 }
416
417 /**************************************************************************
418  *                              DriverProc (JOYSTICK.@)
419  */
420 LONG CALLBACK   JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
421                                  DWORD dwParam1, DWORD dwParam2)
422 {
423     /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
424     /* EPP        dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
425
426     switch(wMsg) {
427     case DRV_LOAD:              return 1;
428     case DRV_FREE:              return 1;
429     case DRV_OPEN:              return JSTCK_drvOpen((LPSTR)dwParam1, dwParam2);
430     case DRV_CLOSE:             return JSTCK_drvClose(dwDevID);
431     case DRV_ENABLE:            return 1;
432     case DRV_DISABLE:           return 1;
433     case DRV_QUERYCONFIGURE:    return 1;
434     case DRV_CONFIGURE:         MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK);       return 1;
435     case DRV_INSTALL:           return DRVCNF_RESTART;
436     case DRV_REMOVE:            return DRVCNF_RESTART;
437
438     case JDD_GETNUMDEVS:        return 1;
439     case JDD_GETDEVCAPS:        return JSTCK_GetDevCaps(dwDevID, (LPJOYCAPSA)dwParam1, dwParam2);
440     case JDD_GETPOS:            return JSTCK_GetPos(dwDevID, (LPJOYINFO)dwParam1);
441     case JDD_SETCALIBRATION:
442     case JDD_CONFIGCHANGED:     return JOYERR_NOCANDO;
443     case JDD_GETPOSEX:          return JSTCK_GetPosEx(dwDevID, (LPJOYINFOEX)dwParam1);
444     default:
445         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
446     }
447 }
448
449 #else
450
451 /**************************************************************************
452  *                              DriverProc (JOYSTICK.@)
453  */
454 LONG CALLBACK   JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
455                                  DWORD dwParam1, DWORD dwParam2)
456 {
457     /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
458     /* EPP        dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
459
460     switch(wMsg) {
461     case DRV_LOAD:
462     case DRV_FREE:
463     case DRV_OPEN:
464     case DRV_CLOSE:
465     case DRV_ENABLE:
466     case DRV_DISABLE:
467     case DRV_QUERYCONFIGURE:    return 0;
468     case DRV_CONFIGURE:         MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK);       return 1;
469     case DRV_INSTALL:           return DRVCNF_RESTART;
470     case DRV_REMOVE:            return DRVCNF_RESTART;
471     default:
472         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
473     }
474 }
475
476 #endif