2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
24 #ifdef SDL_JOYSTICK_WINMM
26 /* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */
28 #define WIN32_LEAN_AND_MEAN
33 #include "SDL_events.h"
34 #include "SDL_joystick.h"
35 #include "../SDL_sysjoystick.h"
36 #include "../SDL_joystick_c.h"
38 #define MAX_JOYSTICKS 16
39 #define MAX_AXES 6 /* each joystick can have up to 6 axes */
40 #define MAX_BUTTONS 32 /* and 32 buttons */
41 #define AXIS_MIN -32768 /* minimum value for axis coordinate */
42 #define AXIS_MAX 32767 /* maximum value for axis coordinate */
43 /* limit axis to 256 possible positions to filter out noise */
44 #define JOY_AXIS_THRESHOLD (((AXIS_MAX)-(AXIS_MIN))/256)
45 #define JOY_BUTTON_FLAG(n) (1<<n)
48 /* array to hold joystick ID values */
49 static UINT SYS_JoystickID[MAX_JOYSTICKS];
50 static JOYCAPS SYS_Joystick[MAX_JOYSTICKS];
51 static char *SYS_JoystickName[MAX_JOYSTICKS];
53 /* The private structure used to keep track of a joystick */
54 struct joystick_hwdata
59 /* values used to translate device-specific coordinates into
60 SDL-standard ranges */
67 /* Convert a win32 Multimedia API return code to a text message */
68 static void SetMMerror(char *function, int code);
71 static char *GetJoystickName(int index, const char *szRegKey)
73 /* added 7/24/2004 by Eckhard Stolberg */
75 see if there is a joystick for the current
76 index (1-16) listed in the registry
87 SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s\\%s",
88 REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR);
89 hTopKey = HKEY_LOCAL_MACHINE;
90 regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
91 if (regresult != ERROR_SUCCESS) {
92 hTopKey = HKEY_CURRENT_USER;
93 regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
95 if (regresult != ERROR_SUCCESS) {
99 /* find the registry key name for the joystick's properties */
100 regsize = sizeof(regname);
101 SDL_snprintf(regvalue, SDL_arraysize(regvalue), "Joystick%d%s", index+1, REGSTR_VAL_JOYOEMNAME);
102 regresult = RegQueryValueExA(hKey, regvalue, 0, 0, (LPBYTE)regname, ®size);
105 if (regresult != ERROR_SUCCESS) {
109 /* open that registry key */
110 SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s", REGSTR_PATH_JOYOEM, regname);
111 regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
112 if (regresult != ERROR_SUCCESS) {
116 /* find the size for the OEM name text */
117 regsize = sizeof(regvalue);
118 regresult = RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, ®size);
119 if (regresult == ERROR_SUCCESS) {
120 /* allocate enough memory for the OEM name text ... */
121 name = (char *) SDL_malloc(regsize);
123 /* ... and read it from the registry */
124 regresult = RegQueryValueExA(hKey,
125 REGSTR_VAL_JOYOEMNAME, 0, 0,
126 (LPBYTE) name, ®size);
134 /* Function to scan the system for joysticks.
135 * This function should set SDL_numjoysticks to the number of available
136 * joysticks. Joystick 0 should be the system default joystick.
137 * It should return 0, or -1 on an unrecoverable fatal error.
139 int SDL_SYS_JoystickInit(void)
148 /* Reset the joystick ID & name mapping tables */
149 for ( i = 0; i < MAX_JOYSTICKS; ++i ) {
150 SYS_JoystickID[i] = 0;
151 SYS_JoystickName[i] = NULL;
154 /* Loop over all potential joystick devices */
156 maxdevs = joyGetNumDevs();
157 for ( i = JOYSTICKID1; i < maxdevs && numdevs < MAX_JOYSTICKS; ++i ) {
159 joyinfo.dwSize = sizeof(joyinfo);
160 joyinfo.dwFlags = JOY_RETURNALL;
161 result = joyGetPosEx(i, &joyinfo);
162 if ( result == JOYERR_NOERROR ) {
163 result = joyGetDevCaps(i, &joycaps, sizeof(joycaps));
164 if ( result == JOYERR_NOERROR ) {
165 SYS_JoystickID[numdevs] = i;
166 SYS_Joystick[numdevs] = joycaps;
167 SYS_JoystickName[numdevs] = GetJoystickName(i, joycaps.szRegKey);
175 /* Function to get the device-dependent name of a joystick */
176 const char *SDL_SYS_JoystickName(int index)
178 if ( SYS_JoystickName[index] != NULL ) {
179 return(SYS_JoystickName[index]);
181 return(SYS_Joystick[index].szPname);
185 /* Function to open a joystick for use.
186 The joystick to open is specified by the index field of the joystick.
187 This should fill the nbuttons and naxes fields of the joystick structure.
188 It returns 0, or -1 if there is an error.
190 int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
193 int caps_flags[MAX_AXES-2] =
194 { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
195 int axis_min[MAX_AXES], axis_max[MAX_AXES];
199 index = joystick->index;
200 axis_min[0] = SYS_Joystick[index].wXmin;
201 axis_max[0] = SYS_Joystick[index].wXmax;
202 axis_min[1] = SYS_Joystick[index].wYmin;
203 axis_max[1] = SYS_Joystick[index].wYmax;
204 axis_min[2] = SYS_Joystick[index].wZmin;
205 axis_max[2] = SYS_Joystick[index].wZmax;
206 axis_min[3] = SYS_Joystick[index].wRmin;
207 axis_max[3] = SYS_Joystick[index].wRmax;
208 axis_min[4] = SYS_Joystick[index].wUmin;
209 axis_max[4] = SYS_Joystick[index].wUmax;
210 axis_min[5] = SYS_Joystick[index].wVmin;
211 axis_max[5] = SYS_Joystick[index].wVmax;
213 /* allocate memory for system specific hardware data */
214 joystick->hwdata = (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
215 if (joystick->hwdata == NULL)
220 SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
222 /* set hardware data */
223 joystick->hwdata->id = SYS_JoystickID[index];
224 for ( i = 0; i < MAX_AXES; ++i ) {
225 if ( (i<2) || (SYS_Joystick[index].wCaps & caps_flags[i-2]) ) {
226 joystick->hwdata->transaxis[i].offset =
227 AXIS_MIN - axis_min[i];
228 joystick->hwdata->transaxis[i].scale =
229 (float)(AXIS_MAX - AXIS_MIN) / (axis_max[i] - axis_min[i]);
231 joystick->hwdata->transaxis[i].offset = 0;
232 joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
236 /* fill nbuttons, naxes, and nhats fields */
237 joystick->nbuttons = SYS_Joystick[index].wNumButtons;
238 joystick->naxes = SYS_Joystick[index].wNumAxes;
239 if ( SYS_Joystick[index].wCaps & JOYCAPS_HASPOV ) {
247 static Uint8 TranslatePOV(DWORD value)
251 pos = SDL_HAT_CENTERED;
252 if ( value != JOY_POVCENTERED ) {
253 if ( (value > JOY_POVLEFT) || (value < JOY_POVRIGHT) ) {
256 if ( (value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD) ) {
257 pos |= SDL_HAT_RIGHT;
259 if ( (value > JOY_POVRIGHT) && (value < JOY_POVLEFT) ) {
262 if ( value > JOY_POVBACKWARD ) {
269 /* Function to update the state of a joystick - called as a device poll.
270 * This function shouldn't update the joystick structure directly,
271 * but instead should call SDL_PrivateJoystick*() to deliver events
272 * and update joystick device state.
274 void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
278 DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
279 JOY_RETURNR, JOY_RETURNU, JOY_RETURNV };
281 struct _transaxis *transaxis;
285 joyinfo.dwSize = sizeof(joyinfo);
286 joyinfo.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS;
287 if ( ! joystick->hats ) {
288 joyinfo.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS);
290 result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
291 if ( result != JOYERR_NOERROR ) {
292 SetMMerror("joyGetPosEx", result);
296 /* joystick motion events */
297 pos[0] = joyinfo.dwXpos;
298 pos[1] = joyinfo.dwYpos;
299 pos[2] = joyinfo.dwZpos;
300 pos[3] = joyinfo.dwRpos;
301 pos[4] = joyinfo.dwUpos;
302 pos[5] = joyinfo.dwVpos;
304 transaxis = joystick->hwdata->transaxis;
305 for (i = 0; i < joystick->naxes; i++) {
306 if (joyinfo.dwFlags & flags[i]) {
307 value = (int)(((float)pos[i] + transaxis[i].offset) * transaxis[i].scale);
308 change = (value - joystick->axes[i]);
309 if ( (change < -JOY_AXIS_THRESHOLD) || (change > JOY_AXIS_THRESHOLD) ) {
310 SDL_PrivateJoystickAxis(joystick, (Uint8)i, (Sint16)value);
315 /* joystick button events */
316 if ( joyinfo.dwFlags & JOY_RETURNBUTTONS ) {
317 for ( i = 0; i < joystick->nbuttons; ++i ) {
318 if ( joyinfo.dwButtons & JOY_BUTTON_FLAG(i) ) {
319 if ( ! joystick->buttons[i] ) {
320 SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_PRESSED);
323 if ( joystick->buttons[i] ) {
324 SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_RELEASED);
330 /* joystick hat events */
331 if ( joyinfo.dwFlags & JOY_RETURNPOV ) {
334 pos = TranslatePOV(joyinfo.dwPOV);
335 if ( pos != joystick->hats[0] ) {
336 SDL_PrivateJoystickHat(joystick, 0, pos);
341 /* Function to close a joystick after use */
342 void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
344 if (joystick->hwdata != NULL) {
345 /* free system specific hardware data */
346 SDL_free(joystick->hwdata);
347 joystick->hwdata = NULL;
351 /* Function to perform any system-specific joystick related cleanup */
352 void SDL_SYS_JoystickQuit(void)
355 for (i = 0; i < MAX_JOYSTICKS; i++) {
356 if ( SYS_JoystickName[i] != NULL ) {
357 SDL_free(SYS_JoystickName[i]);
358 SYS_JoystickName[i] = NULL;
364 /* implementation functions */
365 void SetMMerror(char *function, int code)
368 static char errbuf[1024];
373 case MMSYSERR_NODRIVER:
374 error = "Joystick driver not present";
377 case MMSYSERR_INVALPARAM:
379 error = "Invalid parameter(s)";
382 case MMSYSERR_BADDEVICEID:
383 error = "Bad device ID";
386 case JOYERR_UNPLUGGED:
387 error = "Joystick not attached";
391 error = "Can't capture joystick input";
395 SDL_snprintf(errbuf, SDL_arraysize(errbuf),
396 "%s: Unknown Multimedia system error: 0x%x",
402 SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function, error);
404 SDL_SetError("%s", errbuf);
407 #endif /* SDL_JOYSTICK_WINMM */