- Make the ListView control Unicode ready.
[wine] / dlls / winmm / joystick.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * joystick functions
4  *
5  * Copyright 1997 Andreas Mohr
6  *           2000 Wolfgang Schwotzer
7  *                Eric Pouech
8  */
9
10 #include "config.h"
11
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include <sys/ioctl.h>
18
19 #include "mmsystem.h"
20 #include "winbase.h"
21 #include "winnls.h"
22 #include "wingdi.h"
23 #include "winuser.h"
24
25 #include "wine/mmsystem16.h"
26 #include "winemm.h"
27
28 #include "debugtools.h"
29
30 DEFAULT_DEBUG_CHANNEL(mmsys);
31
32 #define MAXJOYSTICK     (JOYSTICKID2 + 1)
33 #define JOY_PERIOD_MIN  (10)    /* min Capture time period */
34 #define JOY_PERIOD_MAX  (1000)  /* max Capture time period */
35
36 typedef struct tagWINE_JOYSTICK {
37     JOYINFO     ji;
38     HWND        hCapture;
39     UINT        wTimer;
40     DWORD       threshold;
41     BOOL        bChanged;
42     HDRVR       hDriver;
43 } WINE_JOYSTICK;
44
45 static  WINE_JOYSTICK   JOY_Sticks[MAXJOYSTICK];
46
47 /**************************************************************************
48  *                              JOY_LoadDriver          [internal]
49  */
50 static  BOOL JOY_LoadDriver(DWORD dwJoyID)
51 {
52     if (dwJoyID >= MAXJOYSTICK)
53         return FALSE;
54     if (JOY_Sticks[dwJoyID].hDriver)
55         return TRUE;
56
57     return JOY_Sticks[dwJoyID].hDriver = OpenDriverA("joystick.drv", 0, dwJoyID);
58 }
59
60 /**************************************************************************
61  *                              JOY_Timer               [internal]
62  */
63 static  void    CALLBACK        JOY_Timer(HWND hWnd, UINT wMsg, UINT wTimer, DWORD dwTime)
64 {
65     int                 i;
66     WINE_JOYSTICK*      joy;
67     JOYINFO             ji;
68     LONG                pos;
69     unsigned            buttonChange;
70     
71     for (i = 0; i < MAXJOYSTICK; i++) {
72         joy = &JOY_Sticks[i];
73         
74         if (joy->hCapture != hWnd) continue;    
75         
76         joyGetPos(i, &ji);
77         pos = MAKELONG(ji.wXpos, ji.wYpos);
78         
79         if (!joy->bChanged ||
80             abs(joy->ji.wXpos - ji.wXpos) > joy->threshold || 
81             abs(joy->ji.wYpos - ji.wYpos) > joy->threshold) {
82             SendMessageA(joy->hCapture, MM_JOY1MOVE + i, ji.wButtons, pos);
83             joy->ji.wXpos = ji.wXpos;
84             joy->ji.wYpos = ji.wYpos;
85         }
86         if (!joy->bChanged ||
87             abs(joy->ji.wZpos - ji.wZpos) > joy->threshold) {
88             SendMessageA(joy->hCapture, MM_JOY1ZMOVE + i, ji.wButtons, pos);
89             joy->ji.wZpos = ji.wZpos;
90         }
91         if ((buttonChange = joy->ji.wButtons ^ ji.wButtons) != 0) {
92             if (ji.wButtons & buttonChange)
93                 SendMessageA(joy->hCapture, MM_JOY1BUTTONDOWN + i, 
94                              (buttonChange << 8) | (ji.wButtons & buttonChange), pos);
95             if (joy->ji.wButtons & buttonChange)
96                 SendMessageA(joy->hCapture, MM_JOY1BUTTONUP + i, 
97                              (buttonChange << 8) | (joy->ji.wButtons & buttonChange), pos);
98             joy->ji.wButtons = ji.wButtons;
99         }
100     }
101 }
102
103 /**************************************************************************
104  *                              joyGetNumDevs           [WINMM.@]
105  */
106 UINT WINAPI joyGetNumDevs(void)
107 {
108     UINT        ret = 0;
109     int         i;
110
111     for (i = 0; i < MAXJOYSTICK; i++) {
112         if (JOY_LoadDriver(i)) {
113             ret += SendDriverMessage(JOY_Sticks[i].hDriver, JDD_GETNUMDEVS, 0L, 0L);
114         }
115     }
116     return ret;
117 }
118
119 /**************************************************************************
120  *                              joyGetNumDevs           [MMSYSTEM.101]
121  */
122 UINT16 WINAPI joyGetNumDevs16(void)
123 {
124     return joyGetNumDevs();
125 }
126
127 /**************************************************************************
128  *                              joyGetDevCapsA          [WINMM.@]
129  */
130 MMRESULT WINAPI joyGetDevCapsA(UINT wID, LPJOYCAPSA lpCaps, UINT wSize)
131 {
132     if (wID >= MAXJOYSTICK)     return JOYERR_PARMS;
133     if (!JOY_LoadDriver(wID))   return MMSYSERR_NODRIVER;
134
135     lpCaps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */
136     lpCaps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */
137
138     return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETDEVCAPS, (DWORD)lpCaps, wSize);
139 }   
140
141 /**************************************************************************
142  *                              joyGetDevCapsW          [WINMM.@]
143  */
144 MMRESULT WINAPI joyGetDevCapsW(UINT wID, LPJOYCAPSW lpCaps, UINT wSize)
145 {
146     JOYCAPSA    jca;
147     MMRESULT    ret = joyGetDevCapsA(wID, &jca, sizeof(jca));
148     
149     if (ret != JOYERR_NOERROR) return ret;
150     lpCaps->wMid = jca.wMid;
151     lpCaps->wPid = jca.wPid;
152     MultiByteToWideChar( CP_ACP, 0, jca.szPname, -1, lpCaps->szPname,
153                          sizeof(lpCaps->szPname)/sizeof(WCHAR) );
154     lpCaps->wXmin = jca.wXmin;
155     lpCaps->wXmax = jca.wXmax;
156     lpCaps->wYmin = jca.wYmin;
157     lpCaps->wYmax = jca.wYmax;
158     lpCaps->wZmin = jca.wZmin;
159     lpCaps->wZmax = jca.wZmax;
160     lpCaps->wNumButtons = jca.wNumButtons;
161     lpCaps->wPeriodMin = jca.wPeriodMin;
162     lpCaps->wPeriodMax = jca.wPeriodMax;
163     
164     if (wSize >= sizeof(JOYCAPSW)) { /* Win95 extensions ? */
165         lpCaps->wRmin = jca.wRmin;
166         lpCaps->wRmax = jca.wRmax;
167         lpCaps->wUmin = jca.wUmin;
168         lpCaps->wUmax = jca.wUmax;
169         lpCaps->wVmin = jca.wVmin;
170         lpCaps->wVmax = jca.wVmax;
171         lpCaps->wCaps = jca.wCaps;
172         lpCaps->wMaxAxes = jca.wMaxAxes;
173         lpCaps->wNumAxes = jca.wNumAxes;
174         lpCaps->wMaxButtons = jca.wMaxButtons;
175         MultiByteToWideChar( CP_ACP, 0, jca.szRegKey, -1, lpCaps->szRegKey,
176                          sizeof(lpCaps->szRegKey)/sizeof(WCHAR) );
177         MultiByteToWideChar( CP_ACP, 0, jca.szOEMVxD, -1, lpCaps->szOEMVxD,
178                          sizeof(lpCaps->szOEMVxD)/sizeof(WCHAR) );
179     }
180     
181     return ret;
182 }
183
184 /**************************************************************************
185  *                              joyGetDevCaps           [MMSYSTEM.102]
186  */
187 MMRESULT16 WINAPI joyGetDevCaps16(UINT16 wID, LPJOYCAPS16 lpCaps, UINT16 wSize)
188 {
189     JOYCAPSA    jca;
190     MMRESULT    ret = joyGetDevCapsA(wID, &jca, sizeof(jca));
191     
192     if (ret != JOYERR_NOERROR) return ret;
193     lpCaps->wMid = jca.wMid;
194     lpCaps->wPid = jca.wPid;
195     strcpy(lpCaps->szPname, jca.szPname);
196     lpCaps->wXmin = jca.wXmin;
197     lpCaps->wXmax = jca.wXmax;
198     lpCaps->wYmin = jca.wYmin;
199     lpCaps->wYmax = jca.wYmax;
200     lpCaps->wZmin = jca.wZmin;
201     lpCaps->wZmax = jca.wZmax;
202     lpCaps->wNumButtons = jca.wNumButtons;
203     lpCaps->wPeriodMin = jca.wPeriodMin;
204     lpCaps->wPeriodMax = jca.wPeriodMax;
205     
206     if (wSize >= sizeof(JOYCAPS16)) { /* Win95 extensions ? */
207         lpCaps->wRmin = jca.wRmin;
208         lpCaps->wRmax = jca.wRmax;
209         lpCaps->wUmin = jca.wUmin;
210         lpCaps->wUmax = jca.wUmax;
211         lpCaps->wVmin = jca.wVmin;
212         lpCaps->wVmax = jca.wVmax;
213         lpCaps->wCaps = jca.wCaps;
214         lpCaps->wMaxAxes = jca.wMaxAxes;
215         lpCaps->wNumAxes = jca.wNumAxes;
216         lpCaps->wMaxButtons = jca.wMaxButtons;
217         strcpy(lpCaps->szRegKey, jca.szRegKey);
218         strcpy(lpCaps->szOEMVxD, jca.szOEMVxD);
219     }
220     
221     return ret;
222 }
223
224 /**************************************************************************
225  *                              joyGetPosEx             [WINMM.@]
226  */
227 MMRESULT WINAPI joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo)
228 {
229     TRACE("(%d, %p);\n", wID, lpInfo);
230     
231     if (wID >= MAXJOYSTICK)     return JOYERR_PARMS;
232     if (!JOY_LoadDriver(wID))   return MMSYSERR_NODRIVER;
233     
234     lpInfo->dwXpos = 0;
235     lpInfo->dwYpos = 0;
236     lpInfo->dwZpos = 0;
237     lpInfo->dwRpos = 0;
238     lpInfo->dwUpos = 0;
239     lpInfo->dwVpos = 0;
240     lpInfo->dwButtons = 0;
241     lpInfo->dwButtonNumber = 0;
242     lpInfo->dwPOV = 0;
243     lpInfo->dwReserved1 = 0;
244     lpInfo->dwReserved2 = 0;
245
246     return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOSEX, (DWORD)lpInfo, 0L);
247 }
248
249 /**************************************************************************
250  *                              joyGetPosEx           [MMSYSTEM.110]
251  */
252 MMRESULT16 WINAPI joyGetPosEx16(UINT16 wID, LPJOYINFOEX lpInfo)
253 {
254     return joyGetPosEx(wID, lpInfo);
255 }
256
257 /**************************************************************************
258  *                              joyGetPos               [WINMM.@]
259  */
260 MMRESULT WINAPI joyGetPos(UINT wID, LPJOYINFO lpInfo)
261 {
262     TRACE("(%d, %p);\n", wID, lpInfo);
263     
264     if (wID >= MAXJOYSTICK)     return JOYERR_PARMS;
265     if (!JOY_LoadDriver(wID))   return MMSYSERR_NODRIVER;
266     
267     lpInfo->wXpos = 0;
268     lpInfo->wYpos = 0;
269     lpInfo->wZpos = 0;
270     lpInfo->wButtons = 0;
271
272     return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOS, (DWORD)lpInfo, 0L);
273 }
274
275 /**************************************************************************
276  *                              joyGetPos               [MMSYSTEM.103]
277  */
278 MMRESULT16 WINAPI joyGetPos16(UINT16 wID, LPJOYINFO16 lpInfo)
279 {
280     JOYINFO     ji;
281     MMRESULT    ret;
282     
283     TRACE("(%d, %p);\n", wID, lpInfo);
284     
285     if ((ret = joyGetPos(wID, &ji)) == JOYERR_NOERROR) {
286         lpInfo->wXpos = ji.wXpos;
287         lpInfo->wYpos = ji.wYpos;
288         lpInfo->wZpos = ji.wZpos;
289         lpInfo->wButtons = ji.wButtons;
290     }
291     return ret;
292 }
293
294 /**************************************************************************
295  *                              joyGetThreshold         [WINMM.@]
296  */
297 MMRESULT WINAPI joyGetThreshold(UINT wID, LPUINT lpThreshold)
298 {
299     TRACE("(%04X, %p);\n", wID, lpThreshold);
300     
301     if (wID >= MAXJOYSTICK)     return JOYERR_PARMS;
302     
303     *lpThreshold = JOY_Sticks[wID].threshold;
304     return JOYERR_NOERROR;
305 }
306
307 /**************************************************************************
308  *                              joyGetThreshold         [MMSYSTEM.104]
309  */
310 MMRESULT16 WINAPI joyGetThreshold16(UINT16 wID, LPUINT16 lpThreshold)
311 {
312     TRACE("(%04X, %p);\n", wID, lpThreshold);
313     
314     if (wID >= MAXJOYSTICK)     return JOYERR_PARMS;
315     
316     *lpThreshold = JOY_Sticks[wID].threshold;
317     return JOYERR_NOERROR;
318 }
319
320 /**************************************************************************
321  *                              joyReleaseCapture       [WINMM.@]
322  */
323 MMRESULT WINAPI joyReleaseCapture(UINT wID)
324 {
325     TRACE("(%04X);\n", wID);
326
327     if (wID >= MAXJOYSTICK)             return JOYERR_PARMS;
328     if (!JOY_LoadDriver(wID))           return MMSYSERR_NODRIVER;
329     if (!JOY_Sticks[wID].hCapture)      return JOYERR_NOCANDO;
330
331     KillTimer(JOY_Sticks[wID].hCapture, JOY_Sticks[wID].wTimer);
332     JOY_Sticks[wID].hCapture = 0;
333     JOY_Sticks[wID].wTimer = 0;
334
335     return JOYERR_NOERROR;
336 }
337
338 /**************************************************************************
339  *                              joyReleaseCapture       [MMSYSTEM.105]
340  */
341 MMRESULT16 WINAPI joyReleaseCapture16(UINT16 wID)
342 {
343     return joyReleaseCapture(wID);
344 }
345
346 /**************************************************************************
347  *                              joySetCapture           [WINMM.@]
348  */
349 MMRESULT WINAPI joySetCapture(HWND hWnd, UINT wID, UINT wPeriod, BOOL bChanged)
350 {
351     TRACE("(%04X, %04X, %d, %d);\n",  hWnd, wID, wPeriod, bChanged);
352
353     if (wID >= MAXJOYSTICK || hWnd == 0) return JOYERR_PARMS;
354     if (wPeriod<JOY_PERIOD_MIN || wPeriod>JOY_PERIOD_MAX) return JOYERR_PARMS;
355     if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER;
356
357     if (JOY_Sticks[wID].hCapture || !IsWindow(hWnd))
358         return JOYERR_NOCANDO; /* FIXME: what should be returned ? */
359
360     if (joyGetPos(wID, &JOY_Sticks[wID].ji) != JOYERR_NOERROR)
361         return JOYERR_UNPLUGGED;
362
363     if ((JOY_Sticks[wID].wTimer = SetTimer(hWnd, 0, wPeriod, JOY_Timer)) == 0)
364         return JOYERR_NOCANDO;
365
366     JOY_Sticks[wID].hCapture = hWnd;
367     JOY_Sticks[wID].bChanged = bChanged;
368     
369     return JOYERR_NOERROR;
370 }
371
372 /**************************************************************************
373  *                              joySetCapture           [MMSYSTEM.106]
374  */
375 MMRESULT16 WINAPI joySetCapture16(HWND16 hWnd, UINT16 wID, UINT16 wPeriod, BOOL16 bChanged)
376 {
377     return joySetCapture16(hWnd, wID, wPeriod, bChanged);    
378 }
379
380 /**************************************************************************
381  *                              joySetThreshold         [WINMM.@]
382  */
383 MMRESULT WINAPI joySetThreshold(UINT wID, UINT wThreshold)
384 {
385     TRACE("(%04X, %d);\n", wID, wThreshold);
386     
387     if (wID >= MAXJOYSTICK) return MMSYSERR_INVALPARAM;
388
389     JOY_Sticks[wID].threshold = wThreshold;
390
391     return JOYERR_NOERROR;
392 }
393
394 /**************************************************************************
395  *                              joySetThreshold         [MMSYSTEM.107]
396  */
397 MMRESULT16 WINAPI joySetThreshold16(UINT16 wID, UINT16 wThreshold)
398 {
399     return joySetThreshold16(wID,wThreshold);
400 }
401
402 /**************************************************************************
403  *                              joySetCalibration       [MMSYSTEM.109]
404  */
405 MMRESULT16 WINAPI joySetCalibration16(UINT16 wID)
406 {
407     FIXME("(%04X): stub.\n", wID);
408     return JOYERR_NOCANDO;
409 }