SDL-1.2.14
[sdl_omap.git] / src / joystick / win32 / SDL_mmjoystick.c
CommitLineData
e14743d1 1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
4
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.
9
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.
14
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
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#ifdef SDL_JOYSTICK_WINMM
25
26/* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */
27
28#define WIN32_LEAN_AND_MEAN
29#include <windows.h>
30#include <mmsystem.h>
31#include <regstr.h>
32
33#include "SDL_events.h"
34#include "SDL_joystick.h"
35#include "../SDL_sysjoystick.h"
36#include "../SDL_joystick_c.h"
37
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)
46
47
48/* array to hold joystick ID values */
49static UINT SYS_JoystickID[MAX_JOYSTICKS];
50static JOYCAPS SYS_Joystick[MAX_JOYSTICKS];
51static char *SYS_JoystickName[MAX_JOYSTICKS];
52
53/* The private structure used to keep track of a joystick */
54struct joystick_hwdata
55{
56 /* joystick ID */
57 UINT id;
58
59 /* values used to translate device-specific coordinates into
60 SDL-standard ranges */
61 struct _transaxis {
62 int offset;
63 float scale;
64 } transaxis[6];
65};
66
67/* Convert a win32 Multimedia API return code to a text message */
68static void SetMMerror(char *function, int code);
69
70
71static char *GetJoystickName(int index, const char *szRegKey)
72{
73 /* added 7/24/2004 by Eckhard Stolberg */
74 /*
75 see if there is a joystick for the current
76 index (1-16) listed in the registry
77 */
78 char *name = NULL;
79 HKEY hTopKey;
80 HKEY hKey;
81 DWORD regsize;
82 LONG regresult;
83 char regkey[256];
84 char regvalue[256];
85 char regname[256];
86
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);
94 }
95 if (regresult != ERROR_SUCCESS) {
96 return NULL;
97 }
98
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, &regsize);
103 RegCloseKey(hKey);
104
105 if (regresult != ERROR_SUCCESS) {
106 return NULL;
107 }
108
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) {
113 return NULL;
114 }
115
116 /* find the size for the OEM name text */
117 regsize = sizeof(regvalue);
118 regresult = RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, &regsize);
119 if (regresult == ERROR_SUCCESS) {
120 /* allocate enough memory for the OEM name text ... */
121 name = (char *) SDL_malloc(regsize);
122 if ( name ) {
123 /* ... and read it from the registry */
124 regresult = RegQueryValueExA(hKey,
125 REGSTR_VAL_JOYOEMNAME, 0, 0,
126 (LPBYTE) name, &regsize);
127 }
128 }
129 RegCloseKey(hKey);
130
131 return(name);
132}
133
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.
138 */
139int SDL_SYS_JoystickInit(void)
140{
141 int i;
142 int maxdevs;
143 int numdevs;
144 JOYINFOEX joyinfo;
145 JOYCAPS joycaps;
146 MMRESULT result;
147
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;
152 }
153
154 /* Loop over all potential joystick devices */
155 numdevs = 0;
156 maxdevs = joyGetNumDevs();
157 for ( i = JOYSTICKID1; i < maxdevs && numdevs < MAX_JOYSTICKS; ++i ) {
158
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);
168 numdevs++;
169 }
170 }
171 }
172 return(numdevs);
173}
174
175/* Function to get the device-dependent name of a joystick */
176const char *SDL_SYS_JoystickName(int index)
177{
178 if ( SYS_JoystickName[index] != NULL ) {
179 return(SYS_JoystickName[index]);
180 } else {
181 return(SYS_Joystick[index].szPname);
182 }
183}
184
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.
189 */
190int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
191{
192 int index, i;
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];
196
197
198 /* shortcut */
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;
212
213 /* allocate memory for system specific hardware data */
214 joystick->hwdata = (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
215 if (joystick->hwdata == NULL)
216 {
217 SDL_OutOfMemory();
218 return(-1);
219 }
220 SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
221
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]);
230 } else {
231 joystick->hwdata->transaxis[i].offset = 0;
232 joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
233 }
234 }
235
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 ) {
240 joystick->nhats = 1;
241 } else {
242 joystick->nhats = 0;
243 }
244 return(0);
245}
246
247static Uint8 TranslatePOV(DWORD value)
248{
249 Uint8 pos;
250
251 pos = SDL_HAT_CENTERED;
252 if ( value != JOY_POVCENTERED ) {
253 if ( (value > JOY_POVLEFT) || (value < JOY_POVRIGHT) ) {
254 pos |= SDL_HAT_UP;
255 }
256 if ( (value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD) ) {
257 pos |= SDL_HAT_RIGHT;
258 }
259 if ( (value > JOY_POVRIGHT) && (value < JOY_POVLEFT) ) {
260 pos |= SDL_HAT_DOWN;
261 }
262 if ( value > JOY_POVBACKWARD ) {
263 pos |= SDL_HAT_LEFT;
264 }
265 }
266 return(pos);
267}
268
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.
273 */
274void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
275{
276 MMRESULT result;
277 int i;
278 DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
279 JOY_RETURNR, JOY_RETURNU, JOY_RETURNV };
280 DWORD pos[MAX_AXES];
281 struct _transaxis *transaxis;
282 int value, change;
283 JOYINFOEX joyinfo;
284
285 joyinfo.dwSize = sizeof(joyinfo);
286 joyinfo.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS;
287 if ( ! joystick->hats ) {
288 joyinfo.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS);
289 }
290 result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
291 if ( result != JOYERR_NOERROR ) {
292 SetMMerror("joyGetPosEx", result);
293 return;
294 }
295
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;
303
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);
311 }
312 }
313 }
314
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);
321 }
322 } else {
323 if ( joystick->buttons[i] ) {
324 SDL_PrivateJoystickButton(joystick, (Uint8)i, SDL_RELEASED);
325 }
326 }
327 }
328 }
329
330 /* joystick hat events */
331 if ( joyinfo.dwFlags & JOY_RETURNPOV ) {
332 Uint8 pos;
333
334 pos = TranslatePOV(joyinfo.dwPOV);
335 if ( pos != joystick->hats[0] ) {
336 SDL_PrivateJoystickHat(joystick, 0, pos);
337 }
338 }
339}
340
341/* Function to close a joystick after use */
342void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
343{
344 if (joystick->hwdata != NULL) {
345 /* free system specific hardware data */
346 SDL_free(joystick->hwdata);
347 joystick->hwdata = NULL;
348 }
349}
350
351/* Function to perform any system-specific joystick related cleanup */
352void SDL_SYS_JoystickQuit(void)
353{
354 int i;
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;
359 }
360 }
361}
362
363
364/* implementation functions */
365void SetMMerror(char *function, int code)
366{
367 static char *error;
368 static char errbuf[1024];
369
370 errbuf[0] = 0;
371 switch (code)
372 {
373 case MMSYSERR_NODRIVER:
374 error = "Joystick driver not present";
375 break;
376
377 case MMSYSERR_INVALPARAM:
378 case JOYERR_PARMS:
379 error = "Invalid parameter(s)";
380 break;
381
382 case MMSYSERR_BADDEVICEID:
383 error = "Bad device ID";
384 break;
385
386 case JOYERR_UNPLUGGED:
387 error = "Joystick not attached";
388 break;
389
390 case JOYERR_NOCANDO:
391 error = "Can't capture joystick input";
392 break;
393
394 default:
395 SDL_snprintf(errbuf, SDL_arraysize(errbuf),
396 "%s: Unknown Multimedia system error: 0x%x",
397 function, code);
398 break;
399 }
400
401 if ( ! errbuf[0] ) {
402 SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function, error);
403 }
404 SDL_SetError("%s", errbuf);
405}
406
407#endif /* SDL_JOYSTICK_WINMM */