Better implementation of GetCalendarInfo{A,W}, not perfect.
[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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * NOTES:
22  *
23  * nearly all joystick functions can be regarded as obsolete,
24  * as Linux (2.1.x) now supports extended joysticks
25  * with a completely new joystick driver interface
26  * new driver's docu says:
27  * "For backward compatibility the old interface is still included,
28  * but will be dropped in the future."
29  * Thus we should implement the new interface and at most keep the old
30  * routines for backward compatibility.
31  */
32
33 /*
34  * Wolfgang Schwotzer
35  *
36  *    01/2000    added support for new joystick driver
37  *
38  */
39
40 #include "config.h"
41
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <fcntl.h>
47 #include <sys/ioctl.h>
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 } WINE_JSTCK;
73
74 static  WINE_JSTCK      JSTCK_Data[MAXJOYSTICK];
75
76 /**************************************************************************
77  *                              JSTCK_drvGet                    [internal]      
78  */
79 static  WINE_JSTCK*     JSTCK_drvGet(DWORD dwDevID)
80 {
81     int p;
82
83     if ((dwDevID - (DWORD)JSTCK_Data) % sizeof(JSTCK_Data[0]) != 0)
84         return NULL;
85     p = (dwDevID - (DWORD)JSTCK_Data) / sizeof(JSTCK_Data[0]);
86     if (p < 0 || p >= MAXJOYSTICK || !((WINE_JSTCK*)dwDevID)->in_use)
87         return NULL;
88
89     return (WINE_JSTCK*)dwDevID;
90 }
91
92 /**************************************************************************
93  *                              JSTCK_drvOpen                   [internal]      
94  */
95 static  DWORD   JSTCK_drvOpen(LPSTR str, DWORD dwIntf)
96 {
97     if (dwIntf >= MAXJOYSTICK || JSTCK_Data[dwIntf].in_use)
98         return 0;
99
100     JSTCK_Data[dwIntf].joyIntf = dwIntf;
101     JSTCK_Data[dwIntf].in_use = 1;
102     return (DWORD)&JSTCK_Data[dwIntf];
103 }
104
105 /**************************************************************************
106  *                              JSTCK_drvClose                  [internal]      
107  */
108 static  DWORD   JSTCK_drvClose(DWORD dwDevID)
109 {
110     WINE_JSTCK* jstck = JSTCK_drvGet(dwDevID);
111
112     if (jstck == NULL)
113         return 0;
114     jstck->in_use = 0;
115     return 1;
116 }
117
118 struct js_status
119 {
120     int buttons;
121     int x;
122     int y;
123 };
124
125 /**************************************************************************
126  *                              JSTCK_OpenDevice           [internal]
127  */
128 static  int     JSTCK_OpenDevice(WINE_JSTCK* jstick)
129 {
130     char        buf[20];
131     int         flags;
132
133     sprintf(buf, JOYDEV, jstick->joyIntf);
134 #ifdef HAVE_LINUX_22_JOYSTICK_API
135     flags = O_RDONLY | O_NONBLOCK;
136 #else
137     flags = O_RDONLY;
138 #endif
139     return open(buf, flags);
140 }
141
142 /**************************************************************************
143  *                              JoyGetDevCaps           [MMSYSTEM.102]
144  */
145 static  LONG    JSTCK_GetDevCaps(DWORD dwDevID, LPJOYCAPSA lpCaps, DWORD dwSize)
146 {
147     WINE_JSTCK* jstck;
148 #ifdef HAVE_LINUX_22_JOYSTICK_API
149     int         dev;
150     char        nrOfAxes;
151     char        nrOfButtons;
152     char        identString[MAXPNAMELEN];
153     int         driverVersion;
154 #endif
155
156     if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
157         return MMSYSERR_NODRIVER;
158
159 #ifdef HAVE_LINUX_22_JOYSTICK_API
160     
161     if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
162     ioctl(dev, JSIOCGAXES, &nrOfAxes);
163     ioctl(dev, JSIOCGBUTTONS, &nrOfButtons);
164     ioctl(dev, JSIOCGVERSION, &driverVersion);
165     ioctl(dev, JSIOCGNAME(sizeof(identString)), &identString);
166     TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
167           driverVersion, identString, nrOfAxes, nrOfButtons);
168     lpCaps->wMid = MM_MICROSOFT;
169     lpCaps->wPid = MM_PC_JOYSTICK;
170     strncpy(lpCaps->szPname, identString, MAXPNAMELEN);
171     lpCaps->szPname[MAXPNAMELEN-1] = '\0';
172     lpCaps->wXmin = 0;
173     lpCaps->wXmax = 0xFFFF;
174     lpCaps->wYmin = 0;
175     lpCaps->wYmax = 0xFFFF;
176     lpCaps->wZmin = 0;
177     lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0;
178     lpCaps->wNumButtons = nrOfButtons;
179     if (dwSize == sizeof(JOYCAPSA)) {
180         /* since we suppose ntOfAxes <= 6 in the following code, do it explicitly */
181         if (nrOfAxes > 6) nrOfAxes = 6;
182         /* complete 95 structure */
183         lpCaps->wRmin = 0;
184         lpCaps->wRmax = nrOfAxes >= 4 ? 0xFFFF : 0;
185         lpCaps->wUmin = 0;
186         lpCaps->wUmax = nrOfAxes >= 5 ? 0xFFFF : 0;
187         lpCaps->wVmin = 0;
188         lpCaps->wVmax = nrOfAxes >= 6 ? 0xFFFF : 0;
189         lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */
190         lpCaps->wNumAxes = nrOfAxes; /* nr of axes in use */
191         lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */
192         strcpy(lpCaps->szRegKey, "");
193         strcpy(lpCaps->szOEMVxD, "");
194         lpCaps->wCaps = 0;
195         switch(nrOfAxes) {
196         case 6: lpCaps->wCaps |= JOYCAPS_HASV;
197         case 5: lpCaps->wCaps |= JOYCAPS_HASU;
198         case 4: lpCaps->wCaps |= JOYCAPS_HASR;
199         case 3: lpCaps->wCaps |= JOYCAPS_HASZ;
200             /* FIXME: don't know how to detect for
201                JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
202         }
203     }
204     close(dev);
205
206 #else
207     lpCaps->wMid = MM_MICROSOFT;
208     lpCaps->wPid = MM_PC_JOYSTICK;
209     strcpy(lpCaps->szPname, "WineJoy"); /* joystick product name */
210     lpCaps->wXmin = 0;
211     lpCaps->wXmax = 0xFFFF;
212     lpCaps->wYmin = 0;
213     lpCaps->wYmax = 0xFFFF;
214     lpCaps->wZmin = 0;
215     lpCaps->wZmax = 0;
216     lpCaps->wNumButtons = 2;
217     if (dwSize == sizeof(JOYCAPSA)) {
218         /* complete 95 structure */
219         lpCaps->wRmin = 0;
220         lpCaps->wRmax = 0;
221         lpCaps->wUmin = 0;
222         lpCaps->wUmax = 0;
223         lpCaps->wVmin = 0;
224         lpCaps->wVmax = 0;
225         lpCaps->wCaps = 0;
226         lpCaps->wMaxAxes = 2;
227         lpCaps->wNumAxes = 2;
228         lpCaps->wMaxButtons = 4;
229         strcpy(lpCaps->szRegKey,"");
230         strcpy(lpCaps->szOEMVxD,"");
231     }
232 #endif
233
234     return JOYERR_NOERROR;
235 }
236
237 /**************************************************************************
238  *                              JSTCK_GetPos                    [internal]
239  */
240 static LONG     JSTCK_GetPosEx(DWORD dwDevID, LPJOYINFOEX lpInfo)
241 {
242     WINE_JSTCK*         jstck;
243     int                 dev;
244 #ifdef HAVE_LINUX_22_JOYSTICK_API
245     struct js_event     ev;
246 #else
247     struct js_status    js;
248     int                 dev_stat;
249 #endif
250     
251     if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
252         return MMSYSERR_NODRIVER;
253
254     if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
255
256 #ifdef HAVE_LINUX_22_JOYSTICK_API
257     /* After opening the device, its state can be
258        read with JS_EVENT_INIT flag */
259     while ((read(dev, &ev, sizeof(struct js_event))) > 0) {
260         if (ev.type == (JS_EVENT_AXIS | JS_EVENT_INIT)) {
261             switch (ev.number) {
262             case 0:
263                 if (lpInfo->dwFlags & JOY_RETURNX)
264                     lpInfo->dwXpos   = ev.value + 32767;
265                 break;
266             case 1: 
267                 if (lpInfo->dwFlags & JOY_RETURNY)
268                     lpInfo->dwYpos   = ev.value + 32767;
269                 break;
270             case 2:
271                 if (lpInfo->dwFlags & JOY_RETURNZ)
272                     lpInfo->dwZpos   = ev.value + 32767;
273                 break;
274             case 3: 
275                 if (lpInfo->dwFlags & JOY_RETURNR)
276                     lpInfo->dwRpos   = ev.value + 32767;
277             case 4: 
278                 if (lpInfo->dwFlags & JOY_RETURNU)
279                     lpInfo->dwUpos   = ev.value + 32767;
280             case 5: 
281                 if (lpInfo->dwFlags & JOY_RETURNV)
282                     lpInfo->dwVpos   = ev.value + 32767;
283                 break;
284             default: 
285                 FIXME("Unknown joystick event '%d'\n", ev.number);
286             }
287         } else if (ev.type == (JS_EVENT_BUTTON | JS_EVENT_INIT)) {
288             if (lpInfo->dwFlags & JOY_RETURNBUTTONS) {
289                 if (ev.value) {
290                     lpInfo->dwButtons |= (1 << ev.number);
291                     /* FIXME: what to do for this field when 
292                      * multiple buttons are depressed ?
293                      */
294                     lpInfo->dwButtonNumber = ev.number + 1;
295                 }
296             }
297         }
298     }
299     /* EAGAIN is returned when the queue is empty */
300     if (errno != EAGAIN) {
301         /* FIXME: error should not be ignored */
302         ERR("Error while reading joystick state (%s)\n", strerror(errno));
303     }
304 #else
305     dev_stat = read(dev, &js, sizeof(js));
306     if (dev_stat != sizeof(js)) {
307         close(dev);
308         return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */
309     }
310     js.x = js.x<<8;
311     js.y = js.y<<8;
312     if (lpInfo->dwFlags & JOY_RETURNX)
313         lpInfo->dwXpos = js.x;   /* FIXME: perhaps multiply it somehow ? */
314     if (lpInfo->dwFlags & JOY_RETURNY)
315         lpInfo->dwYpos = js.y;
316     if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
317         lpInfo->dwButtons = js.buttons;
318 #endif
319
320     close(dev);
321
322     TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x\n", 
323           lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos,
324           lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos,
325           (unsigned int)lpInfo->dwButtons,
326           (unsigned int)lpInfo->dwFlags);
327
328     return JOYERR_NOERROR;
329 }
330
331 /**************************************************************************
332  *                              JSTCK_GetPos                    [internal]
333  */
334 static LONG     JSTCK_GetPos(DWORD dwDevID, LPJOYINFO lpInfo)
335 {
336     JOYINFOEX   ji;
337     LONG        ret;
338
339     memset(&ji, 0, sizeof(ji));
340
341     ji.dwSize = sizeof(ji);
342     ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
343     ret = JSTCK_GetPosEx(dwDevID, &ji);
344     if (ret == JOYERR_NOERROR)  {
345         lpInfo->wXpos    = ji.dwXpos;
346         lpInfo->wYpos    = ji.dwYpos;
347         lpInfo->wZpos    = ji.dwZpos;
348         lpInfo->wButtons = ji.dwButtons;
349     }
350
351     return ret;
352 }
353
354 /**************************************************************************
355  *                              DriverProc (JOYSTICK.@)
356  */
357 LONG CALLBACK   JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
358                                  DWORD dwParam1, DWORD dwParam2)
359 {
360     /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
361     /* EPP        dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
362     
363     switch(wMsg) {
364     case DRV_LOAD:              return 1;
365     case DRV_FREE:              return 1;
366     case DRV_OPEN:              return JSTCK_drvOpen((LPSTR)dwParam1, dwParam2);
367     case DRV_CLOSE:             return JSTCK_drvClose(dwDevID);
368     case DRV_ENABLE:            return 1;
369     case DRV_DISABLE:           return 1;
370     case DRV_QUERYCONFIGURE:    return 1;
371     case DRV_CONFIGURE:         MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK);       return 1;
372     case DRV_INSTALL:           return DRVCNF_RESTART;
373     case DRV_REMOVE:            return DRVCNF_RESTART;
374
375     case JDD_GETNUMDEVS:        return 1;
376     case JDD_GETDEVCAPS:        return JSTCK_GetDevCaps(dwDevID, (LPJOYCAPSA)dwParam1, dwParam2);
377     case JDD_GETPOS:            return JSTCK_GetPos(dwDevID, (LPJOYINFO)dwParam1);
378     case JDD_SETCALIBRATION:    
379     case JDD_CONFIGCHANGED:     return JOYERR_NOCANDO;
380     case JDD_GETPOSEX:          return JSTCK_GetPosEx(dwDevID, (LPJOYINFOEX)dwParam1);
381     default:
382         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
383     }
384 }
385
386 #else
387
388 /**************************************************************************
389  *                              DriverProc (JOYSTICK.@)
390  */
391 LONG CALLBACK   JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
392                                  DWORD dwParam1, DWORD dwParam2)
393 {
394     /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
395     /* EPP        dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
396     
397     switch(wMsg) {
398     case DRV_LOAD:              
399     case DRV_FREE:              
400     case DRV_OPEN:              
401     case DRV_CLOSE:             
402     case DRV_ENABLE:            
403     case DRV_DISABLE:           
404     case DRV_QUERYCONFIGURE:    return 0;
405     case DRV_CONFIGURE:         MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK);       return 1;
406     case DRV_INSTALL:           return DRVCNF_RESTART;
407     case DRV_REMOVE:            return DRVCNF_RESTART;
408     default:
409         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
410     }
411 }
412
413 #endif