joystick.c 9.9 KB
Newer Older
1
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
Alexandre Julliard's avatar
Alexandre Julliard committed
2
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
3
 * joystick functions
Alexandre Julliard's avatar
Alexandre Julliard committed
4
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 * Copyright 1997 Andreas Mohr
6 7
 *	     2000 Wolfgang Schwotzer
 *                Eric Pouech
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 23
 */

24 25
#include "config.h"

26 27 28
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
29
#include <stdarg.h>
30
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
31 32 33
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
34
#ifdef HAVE_SYS_IOCTL_H
Alexandre Julliard's avatar
Alexandre Julliard committed
35
#include <sys/ioctl.h>
36
#endif
37

38
#include "windef.h"
39
#include "winbase.h"
40
#include "mmsystem.h"
41
#include "wingdi.h"
42
#include "winuser.h"
43
#include "winnls.h"
44

45
#include "mmddk.h"
46

47
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
48

49
WINE_DEFAULT_DEBUG_CHANNEL(winmm);
50

51
#define MAXJOYSTICK (JOYSTICKID2 + 30)
52 53
#define JOY_PERIOD_MIN	(10)	/* min Capture time period */
#define JOY_PERIOD_MAX	(1000)	/* max Capture time period */
Alexandre Julliard's avatar
Alexandre Julliard committed
54

55 56 57 58 59 60
typedef struct tagWINE_JOYSTICK {
    JOYINFO	ji;
    HWND	hCapture;
    UINT	wTimer;
    DWORD	threshold;
    BOOL	bChanged;
61
    HDRVR	hDriver;
62
} WINE_JOYSTICK;
Alexandre Julliard's avatar
Alexandre Julliard committed
63

64
static	WINE_JOYSTICK	JOY_Sticks[MAXJOYSTICK];
Alexandre Julliard's avatar
Alexandre Julliard committed
65 66

/**************************************************************************
67
 * 				JOY_LoadDriver		[internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
68
 */
69
static	BOOL JOY_LoadDriver(DWORD dwJoyID)
Alexandre Julliard's avatar
Alexandre Julliard committed
70
{
71 72 73
    if (dwJoyID >= MAXJOYSTICK)
	return FALSE;
    if (JOY_Sticks[dwJoyID].hDriver)
74
	return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
75

76
    JOY_Sticks[dwJoyID].hDriver = OpenDriverA("winejoystick.drv", 0, dwJoyID);
77
    return (JOY_Sticks[dwJoyID].hDriver != 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
78 79
}

80
/**************************************************************************
81
 * 				JOY_Timer		[internal]
82
 */
83
static	void	CALLBACK	JOY_Timer(HWND hWnd, UINT wMsg, UINT_PTR wTimer, DWORD dwTime)
84
{
85 86
    int			i;
    WINE_JOYSTICK*	joy;
87
    MMRESULT		res;
88 89 90
    JOYINFO		ji;
    LONG		pos;
    unsigned 		buttonChange;
91

92 93
    for (i = 0; i < MAXJOYSTICK; i++) {
	joy = &JOY_Sticks[i];
94 95 96

	if (joy->hCapture != hWnd) continue;

97 98 99 100 101 102
	res = joyGetPos(i, &ji);
	if (res != JOYERR_NOERROR) {
	    WARN("joyGetPos failed: %08x\n", res);
	    continue;
	}

103
	pos = MAKELONG(ji.wXpos, ji.wYpos);
104

105
	if (!joy->bChanged ||
106
	    abs(joy->ji.wXpos - ji.wXpos) > joy->threshold ||
107 108 109 110
	    abs(joy->ji.wYpos - ji.wYpos) > joy->threshold) {
	    SendMessageA(joy->hCapture, MM_JOY1MOVE + i, ji.wButtons, pos);
	    joy->ji.wXpos = ji.wXpos;
	    joy->ji.wYpos = ji.wYpos;
111
	}
112 113 114 115
	if (!joy->bChanged ||
	    abs(joy->ji.wZpos - ji.wZpos) > joy->threshold) {
	    SendMessageA(joy->hCapture, MM_JOY1ZMOVE + i, ji.wButtons, pos);
	    joy->ji.wZpos = ji.wZpos;
116
	}
117 118
	if ((buttonChange = joy->ji.wButtons ^ ji.wButtons) != 0) {
	    if (ji.wButtons & buttonChange)
119
		SendMessageA(joy->hCapture, MM_JOY1BUTTONDOWN + i,
120 121
			     (buttonChange << 8) | (ji.wButtons & buttonChange), pos);
	    if (joy->ji.wButtons & buttonChange)
122
		SendMessageA(joy->hCapture, MM_JOY1BUTTONUP + i,
123 124 125 126
			     (buttonChange << 8) | (joy->ji.wButtons & buttonChange), pos);
	    joy->ji.wButtons = ji.wButtons;
	}
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
127 128
}

129 130 131 132 133 134
/**************************************************************************
 *                              joyConfigChanged        [WINMM.@]
 */
MMRESULT WINAPI joyConfigChanged(DWORD flags)
{
    FIXME("(%x) - stub\n", flags);
135 136 137 138

    if (flags)
	return JOYERR_PARMS;

139 140 141
    return JOYERR_NOERROR;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
142
/**************************************************************************
143
 * 				joyGetNumDevs		[WINMM.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
144
 */
145
UINT WINAPI DECLSPEC_HOTPATCH joyGetNumDevs(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
146
{
147 148
    UINT	ret = 0;
    int		i;
149

150 151
    for (i = 0; i < MAXJOYSTICK; i++) {
	if (JOY_LoadDriver(i)) {
152
            ret += SendDriverMessage(JOY_Sticks[i].hDriver, JDD_GETNUMDEVS, 0, 0);
153 154 155
	}
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
156 157 158
}

/**************************************************************************
159
 * 				joyGetDevCapsW		[WINMM.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
160
 */
161
MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsW(UINT_PTR wID, LPJOYCAPSW lpCaps, UINT wSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
162
{
163
    if (wID >= MAXJOYSTICK)	return JOYERR_PARMS;
164
    if (!JOY_LoadDriver(wID))	return MMSYSERR_NODRIVER;
165 166 167 168

    lpCaps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */
    lpCaps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */

169
    return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETDEVCAPS, (LPARAM)lpCaps, wSize);
170
}
Alexandre Julliard's avatar
Alexandre Julliard committed
171 172

/**************************************************************************
173
 * 				joyGetDevCapsA		[WINMM.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
174
 */
175
MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsA(UINT_PTR wID, LPJOYCAPSA lpCaps, UINT wSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
176
{
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
    JOYCAPSW	jcw;
    MMRESULT	ret;

    if (lpCaps == NULL) return MMSYSERR_INVALPARAM;

    ret = joyGetDevCapsW(wID, &jcw, sizeof(jcw));

    if (ret == JOYERR_NOERROR)
    {
        lpCaps->wMid = jcw.wMid;
        lpCaps->wPid = jcw.wPid;
        WideCharToMultiByte( CP_ACP, 0, jcw.szPname, -1, lpCaps->szPname,
                             sizeof(lpCaps->szPname), NULL, NULL );
        lpCaps->wXmin = jcw.wXmin;
        lpCaps->wXmax = jcw.wXmax;
        lpCaps->wYmin = jcw.wYmin;
        lpCaps->wYmax = jcw.wYmax;
        lpCaps->wZmin = jcw.wZmin;
        lpCaps->wZmax = jcw.wZmax;
        lpCaps->wNumButtons = jcw.wNumButtons;
        lpCaps->wPeriodMin = jcw.wPeriodMin;
        lpCaps->wPeriodMax = jcw.wPeriodMax;

        if (wSize >= sizeof(JOYCAPSA)) { /* Win95 extensions ? */
            lpCaps->wRmin = jcw.wRmin;
            lpCaps->wRmax = jcw.wRmax;
            lpCaps->wUmin = jcw.wUmin;
            lpCaps->wUmax = jcw.wUmax;
            lpCaps->wVmin = jcw.wVmin;
            lpCaps->wVmax = jcw.wVmax;
            lpCaps->wCaps = jcw.wCaps;
            lpCaps->wMaxAxes = jcw.wMaxAxes;
            lpCaps->wNumAxes = jcw.wNumAxes;
            lpCaps->wMaxButtons = jcw.wMaxButtons;
            WideCharToMultiByte( CP_ACP, 0, jcw.szRegKey, -1, lpCaps->szRegKey,
                                 sizeof(lpCaps->szRegKey), NULL, NULL );
            WideCharToMultiByte( CP_ACP, 0, jcw.szOEMVxD, -1, lpCaps->szOEMVxD,
                                 sizeof(lpCaps->szOEMVxD), NULL, NULL );
        }
216
    }
217

218
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
219
}
220

Alexandre Julliard's avatar
Alexandre Julliard committed
221
/**************************************************************************
222
 *                              joyGetPosEx             [WINMM.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
223
 */
224
MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo)
Alexandre Julliard's avatar
Alexandre Julliard committed
225
{
226
    TRACE("(%d, %p);\n", wID, lpInfo);
227

228
    if (!lpInfo) return MMSYSERR_INVALPARAM;
229
    if (wID >= MAXJOYSTICK || lpInfo->dwSize < sizeof(JOYINFOEX)) return JOYERR_PARMS;
230
    if (!JOY_LoadDriver(wID))	return MMSYSERR_NODRIVER;
231

232 233 234 235 236 237 238 239 240 241 242 243
    lpInfo->dwXpos = 0;
    lpInfo->dwYpos = 0;
    lpInfo->dwZpos = 0;
    lpInfo->dwRpos = 0;
    lpInfo->dwUpos = 0;
    lpInfo->dwVpos = 0;
    lpInfo->dwButtons = 0;
    lpInfo->dwButtonNumber = 0;
    lpInfo->dwPOV = 0;
    lpInfo->dwReserved1 = 0;
    lpInfo->dwReserved2 = 0;

244
    return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOSEX, (LPARAM)lpInfo, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
245 246
}

Alexandre Julliard's avatar
Alexandre Julliard committed
247
/**************************************************************************
248
 * 				joyGetPos	       	[WINMM.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
249
 */
250
MMRESULT WINAPI joyGetPos(UINT wID, LPJOYINFO lpInfo)
Alexandre Julliard's avatar
Alexandre Julliard committed
251
{
252
    TRACE("(%d, %p);\n", wID, lpInfo);
253

254
    if (!lpInfo) return MMSYSERR_INVALPARAM;
255
    if (wID >= MAXJOYSTICK)	return JOYERR_PARMS;
256
    if (!JOY_LoadDriver(wID))	return MMSYSERR_NODRIVER;
257

258 259 260 261 262
    lpInfo->wXpos = 0;
    lpInfo->wYpos = 0;
    lpInfo->wZpos = 0;
    lpInfo->wButtons = 0;

263
    return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOS, (LPARAM)lpInfo, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
264 265 266
}

/**************************************************************************
267
 * 				joyGetThreshold		[WINMM.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
268
 */
269
MMRESULT WINAPI joyGetThreshold(UINT wID, LPUINT lpThreshold)
Alexandre Julliard's avatar
Alexandre Julliard committed
270
{
271
    TRACE("(%04X, %p);\n", wID, lpThreshold);
272

273
    if (wID >= MAXJOYSTICK)	return JOYERR_PARMS;
274

275 276
    *lpThreshold = JOY_Sticks[wID].threshold;
    return JOYERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
277 278 279
}

/**************************************************************************
280
 * 				joyReleaseCapture	[WINMM.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
281
 */
282
MMRESULT WINAPI joyReleaseCapture(UINT wID)
Alexandre Julliard's avatar
Alexandre Julliard committed
283
{
284 285 286
    TRACE("(%04X);\n", wID);

    if (wID >= MAXJOYSTICK)		return JOYERR_PARMS;
287
    if (!JOY_LoadDriver(wID))		return MMSYSERR_NODRIVER;
288 289 290 291 292 293 294 295
    if (JOY_Sticks[wID].hCapture)
    {
        KillTimer(JOY_Sticks[wID].hCapture, JOY_Sticks[wID].wTimer);
        JOY_Sticks[wID].hCapture = 0;
        JOY_Sticks[wID].wTimer = 0;
    }
    else
        TRACE("Joystick is not captured, ignoring request.\n");
296 297

    return JOYERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
298 299
}

Alexandre Julliard's avatar
Alexandre Julliard committed
300
/**************************************************************************
301
 * 				joySetCapture		[WINMM.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
302
 */
303
MMRESULT WINAPI joySetCapture(HWND hWnd, UINT wID, UINT wPeriod, BOOL bChanged)
Alexandre Julliard's avatar
Alexandre Julliard committed
304
{
305
    TRACE("(%p, %04X, %d, %d);\n",  hWnd, wID, wPeriod, bChanged);
306 307

    if (wID >= MAXJOYSTICK || hWnd == 0) return JOYERR_PARMS;
308 309
    if (wPeriod<JOY_PERIOD_MIN) wPeriod = JOY_PERIOD_MIN;
    else if(wPeriod>JOY_PERIOD_MAX) wPeriod = JOY_PERIOD_MAX;
310
    if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER;
311 312 313 314 315 316 317 318 319 320 321 322

    if (JOY_Sticks[wID].hCapture || !IsWindow(hWnd))
	return JOYERR_NOCANDO; /* FIXME: what should be returned ? */

    if (joyGetPos(wID, &JOY_Sticks[wID].ji) != JOYERR_NOERROR)
	return JOYERR_UNPLUGGED;

    if ((JOY_Sticks[wID].wTimer = SetTimer(hWnd, 0, wPeriod, JOY_Timer)) == 0)
	return JOYERR_NOCANDO;

    JOY_Sticks[wID].hCapture = hWnd;
    JOY_Sticks[wID].bChanged = bChanged;
323

324
    return JOYERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
325 326 327
}

/**************************************************************************
328
 * 				joySetThreshold		[WINMM.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
329
 */
330
MMRESULT WINAPI joySetThreshold(UINT wID, UINT wThreshold)
Alexandre Julliard's avatar
Alexandre Julliard committed
331
{
332
    TRACE("(%04X, %d);\n", wID, wThreshold);
333

334
    if (wID >= MAXJOYSTICK || wThreshold > 65535) return MMSYSERR_INVALPARAM;
335 336 337 338

    JOY_Sticks[wID].threshold = wThreshold;

    return JOYERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
339
}