comparison src/joystick/windows/SDL_mmjoystick.c @ 5062:e8916fe9cfc8

Fixed bug #925 Changed "win32" to "windows"
author Sam Lantinga <slouken@libsdl.org>
date Thu, 20 Jan 2011 18:04:05 -0800
parents src/joystick/win32/SDL_mmjoystick.c@f7b03b6838cb
children 327f181542f1
comparison
equal deleted inserted replaced
5061:9e9940eae455 5062:e8916fe9cfc8
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2010 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 */
49 static UINT SYS_JoystickID[MAX_JOYSTICKS];
50 static JOYCAPS SYS_Joystick[MAX_JOYSTICKS];
51 static char *SYS_JoystickName[MAX_JOYSTICKS];
52
53 /* The private structure used to keep track of a joystick */
54 struct 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 {
63 int offset;
64 float scale;
65 } transaxis[6];
66 };
67
68 /* Convert a Windows Multimedia API return code to a text message */
69 static void SetMMerror(char *function, int code);
70
71
72 static char *
73 GetJoystickName(int index, const char *szRegKey)
74 {
75 /* added 7/24/2004 by Eckhard Stolberg */
76 /*
77 see if there is a joystick for the current
78 index (1-16) listed in the registry
79 */
80 char *name = NULL;
81 HKEY hTopKey;
82 HKEY hKey;
83 DWORD regsize;
84 LONG regresult;
85 char regkey[256];
86 char regvalue[256];
87 char regname[256];
88
89 SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s\\%s",
90 REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR);
91 hTopKey = HKEY_LOCAL_MACHINE;
92 regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
93 if (regresult != ERROR_SUCCESS) {
94 hTopKey = HKEY_CURRENT_USER;
95 regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
96 }
97 if (regresult != ERROR_SUCCESS) {
98 return NULL;
99 }
100
101 /* find the registry key name for the joystick's properties */
102 regsize = sizeof(regname);
103 SDL_snprintf(regvalue, SDL_arraysize(regvalue), "Joystick%d%s", index + 1,
104 REGSTR_VAL_JOYOEMNAME);
105 regresult =
106 RegQueryValueExA(hKey, regvalue, 0, 0, (LPBYTE) regname, &regsize);
107 RegCloseKey(hKey);
108
109 if (regresult != ERROR_SUCCESS) {
110 return NULL;
111 }
112
113 /* open that registry key */
114 SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s", REGSTR_PATH_JOYOEM,
115 regname);
116 regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
117 if (regresult != ERROR_SUCCESS) {
118 return NULL;
119 }
120
121 /* find the size for the OEM name text */
122 regsize = sizeof(regvalue);
123 regresult =
124 RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, &regsize);
125 if (regresult == ERROR_SUCCESS) {
126 /* allocate enough memory for the OEM name text ... */
127 name = (char *) SDL_malloc(regsize);
128 if (name) {
129 /* ... and read it from the registry */
130 regresult = RegQueryValueExA(hKey,
131 REGSTR_VAL_JOYOEMNAME, 0, 0,
132 (LPBYTE) name, &regsize);
133 }
134 }
135 RegCloseKey(hKey);
136
137 return (name);
138 }
139
140 /* Function to scan the system for joysticks.
141 * This function should set SDL_numjoysticks to the number of available
142 * joysticks. Joystick 0 should be the system default joystick.
143 * It should return 0, or -1 on an unrecoverable fatal error.
144 */
145 int
146 SDL_SYS_JoystickInit(void)
147 {
148 int i;
149 int maxdevs;
150 int numdevs;
151 JOYINFOEX joyinfo;
152 JOYCAPS joycaps;
153 MMRESULT result;
154
155 /* Reset the joystick ID & name mapping tables */
156 for (i = 0; i < MAX_JOYSTICKS; ++i) {
157 SYS_JoystickID[i] = 0;
158 SYS_JoystickName[i] = NULL;
159 }
160
161 /* Loop over all potential joystick devices */
162 numdevs = 0;
163 maxdevs = joyGetNumDevs();
164 for (i = JOYSTICKID1; i < maxdevs && numdevs < MAX_JOYSTICKS; ++i) {
165
166 joyinfo.dwSize = sizeof(joyinfo);
167 joyinfo.dwFlags = JOY_RETURNALL;
168 result = joyGetPosEx(i, &joyinfo);
169 if (result == JOYERR_NOERROR) {
170 result = joyGetDevCaps(i, &joycaps, sizeof(joycaps));
171 if (result == JOYERR_NOERROR) {
172 SYS_JoystickID[numdevs] = i;
173 SYS_Joystick[numdevs] = joycaps;
174 SYS_JoystickName[numdevs] =
175 GetJoystickName(i, joycaps.szRegKey);
176 numdevs++;
177 }
178 }
179 }
180 return (numdevs);
181 }
182
183 /* Function to get the device-dependent name of a joystick */
184 const char *
185 SDL_SYS_JoystickName(int index)
186 {
187 if (SYS_JoystickName[index] != NULL) {
188 return (SYS_JoystickName[index]);
189 } else {
190 return (SYS_Joystick[index].szPname);
191 }
192 }
193
194 /* Function to open a joystick for use.
195 The joystick to open is specified by the index field of the joystick.
196 This should fill the nbuttons and naxes fields of the joystick structure.
197 It returns 0, or -1 if there is an error.
198 */
199 int
200 SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
201 {
202 int index, i;
203 int caps_flags[MAX_AXES - 2] =
204 { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
205 int axis_min[MAX_AXES], axis_max[MAX_AXES];
206
207
208 /* shortcut */
209 index = joystick->index;
210 axis_min[0] = SYS_Joystick[index].wXmin;
211 axis_max[0] = SYS_Joystick[index].wXmax;
212 axis_min[1] = SYS_Joystick[index].wYmin;
213 axis_max[1] = SYS_Joystick[index].wYmax;
214 axis_min[2] = SYS_Joystick[index].wZmin;
215 axis_max[2] = SYS_Joystick[index].wZmax;
216 axis_min[3] = SYS_Joystick[index].wRmin;
217 axis_max[3] = SYS_Joystick[index].wRmax;
218 axis_min[4] = SYS_Joystick[index].wUmin;
219 axis_max[4] = SYS_Joystick[index].wUmax;
220 axis_min[5] = SYS_Joystick[index].wVmin;
221 axis_max[5] = SYS_Joystick[index].wVmax;
222
223 /* allocate memory for system specific hardware data */
224 joystick->hwdata =
225 (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
226 if (joystick->hwdata == NULL) {
227 SDL_OutOfMemory();
228 return (-1);
229 }
230 SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
231
232 /* set hardware data */
233 joystick->hwdata->id = SYS_JoystickID[index];
234 for (i = 0; i < MAX_AXES; ++i) {
235 if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) {
236 joystick->hwdata->transaxis[i].offset = AXIS_MIN - axis_min[i];
237 joystick->hwdata->transaxis[i].scale =
238 (float) (AXIS_MAX - AXIS_MIN) / (axis_max[i] - axis_min[i]);
239 } else {
240 joystick->hwdata->transaxis[i].offset = 0;
241 joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
242 }
243 }
244
245 /* fill nbuttons, naxes, and nhats fields */
246 joystick->nbuttons = SYS_Joystick[index].wNumButtons;
247 joystick->naxes = SYS_Joystick[index].wNumAxes;
248 if (SYS_Joystick[index].wCaps & JOYCAPS_HASPOV) {
249 joystick->nhats = 1;
250 } else {
251 joystick->nhats = 0;
252 }
253 return (0);
254 }
255
256 static Uint8
257 TranslatePOV(DWORD value)
258 {
259 Uint8 pos;
260
261 pos = SDL_HAT_CENTERED;
262 if (value != JOY_POVCENTERED) {
263 if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) {
264 pos |= SDL_HAT_UP;
265 }
266 if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) {
267 pos |= SDL_HAT_RIGHT;
268 }
269 if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) {
270 pos |= SDL_HAT_DOWN;
271 }
272 if (value > JOY_POVBACKWARD) {
273 pos |= SDL_HAT_LEFT;
274 }
275 }
276 return (pos);
277 }
278
279 /* Function to update the state of a joystick - called as a device poll.
280 * This function shouldn't update the joystick structure directly,
281 * but instead should call SDL_PrivateJoystick*() to deliver events
282 * and update joystick device state.
283 */
284 void
285 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
286 {
287 MMRESULT result;
288 int i;
289 DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
290 JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
291 };
292 DWORD pos[MAX_AXES];
293 struct _transaxis *transaxis;
294 int value, change;
295 JOYINFOEX joyinfo;
296
297 joyinfo.dwSize = sizeof(joyinfo);
298 joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
299 if (!joystick->hats) {
300 joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
301 }
302 result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
303 if (result != JOYERR_NOERROR) {
304 SetMMerror("joyGetPosEx", result);
305 return;
306 }
307
308 /* joystick motion events */
309 pos[0] = joyinfo.dwXpos;
310 pos[1] = joyinfo.dwYpos;
311 pos[2] = joyinfo.dwZpos;
312 pos[3] = joyinfo.dwRpos;
313 pos[4] = joyinfo.dwUpos;
314 pos[5] = joyinfo.dwVpos;
315
316 transaxis = joystick->hwdata->transaxis;
317 for (i = 0; i < joystick->naxes; i++) {
318 if (joyinfo.dwFlags & flags[i]) {
319 value =
320 (int) (((float) pos[i] +
321 transaxis[i].offset) * transaxis[i].scale);
322 change = (value - joystick->axes[i]);
323 if ((change < -JOY_AXIS_THRESHOLD)
324 || (change > JOY_AXIS_THRESHOLD)) {
325 SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
326 }
327 }
328 }
329
330 /* joystick button events */
331 if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
332 for (i = 0; i < joystick->nbuttons; ++i) {
333 if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
334 if (!joystick->buttons[i]) {
335 SDL_PrivateJoystickButton(joystick, (Uint8) i,
336 SDL_PRESSED);
337 }
338 } else {
339 if (joystick->buttons[i]) {
340 SDL_PrivateJoystickButton(joystick, (Uint8) i,
341 SDL_RELEASED);
342 }
343 }
344 }
345 }
346
347 /* joystick hat events */
348 if (joyinfo.dwFlags & JOY_RETURNPOV) {
349 Uint8 pos;
350
351 pos = TranslatePOV(joyinfo.dwPOV);
352 if (pos != joystick->hats[0]) {
353 SDL_PrivateJoystickHat(joystick, 0, pos);
354 }
355 }
356 }
357
358 /* Function to close a joystick after use */
359 void
360 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
361 {
362 if (joystick->hwdata != NULL) {
363 /* free system specific hardware data */
364 SDL_free(joystick->hwdata);
365 joystick->hwdata = NULL;
366 }
367 }
368
369 /* Function to perform any system-specific joystick related cleanup */
370 void
371 SDL_SYS_JoystickQuit(void)
372 {
373 int i;
374 for (i = 0; i < MAX_JOYSTICKS; i++) {
375 if (SYS_JoystickName[i] != NULL) {
376 SDL_free(SYS_JoystickName[i]);
377 SYS_JoystickName[i] = NULL;
378 }
379 }
380 }
381
382
383 /* implementation functions */
384 void
385 SetMMerror(char *function, int code)
386 {
387 static char *error;
388 static char errbuf[1024];
389
390 errbuf[0] = 0;
391 switch (code) {
392 case MMSYSERR_NODRIVER:
393 error = "Joystick driver not present";
394 break;
395
396 case MMSYSERR_INVALPARAM:
397 case JOYERR_PARMS:
398 error = "Invalid parameter(s)";
399 break;
400
401 case MMSYSERR_BADDEVICEID:
402 error = "Bad device ID";
403 break;
404
405 case JOYERR_UNPLUGGED:
406 error = "Joystick not attached";
407 break;
408
409 case JOYERR_NOCANDO:
410 error = "Can't capture joystick input";
411 break;
412
413 default:
414 SDL_snprintf(errbuf, SDL_arraysize(errbuf),
415 "%s: Unknown Multimedia system error: 0x%x",
416 function, code);
417 break;
418 }
419
420 if (!errbuf[0]) {
421 SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
422 error);
423 }
424 SDL_SetError("%s", errbuf);
425 }
426
427 #endif /* SDL_JOYSTICK_WINMM */
428 /* vi: set ts=4 sw=4 expandtab: */