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