SDL  2.0
SDL_mmjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #ifdef SDL_JOYSTICK_WINMM
24 
25 /* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */
26 
27 #include "../../core/windows/SDL_windows.h"
28 #include <mmsystem.h>
29 #include <regstr.h>
30 
31 #include "SDL_events.h"
32 #include "SDL_joystick.h"
33 #include "../SDL_sysjoystick.h"
34 #include "../SDL_joystick_c.h"
35 
36 #ifdef REGSTR_VAL_JOYOEMNAME
37 #undef REGSTR_VAL_JOYOEMNAME
38 #endif
39 #define REGSTR_VAL_JOYOEMNAME "OEMName"
40 
41 #define MAX_JOYSTICKS 16
42 #define MAX_AXES 6 /* each joystick can have up to 6 axes */
43 #define MAX_BUTTONS 32 /* and 32 buttons */
44 #define AXIS_MIN -32768 /* minimum value for axis coordinate */
45 #define AXIS_MAX 32767 /* maximum value for axis coordinate */
46 /* limit axis to 256 possible positions to filter out noise */
47 #define JOY_AXIS_THRESHOLD (((AXIS_MAX)-(AXIS_MIN))/256)
48 #define JOY_BUTTON_FLAG(n) (1<<n)
49 
50 
51 /* array to hold joystick ID values */
52 static UINT SYS_JoystickID[MAX_JOYSTICKS];
53 static JOYCAPSA SYS_Joystick[MAX_JOYSTICKS];
54 static char *SYS_JoystickName[MAX_JOYSTICKS];
55 
56 /* The private structure used to keep track of a joystick */
57 struct joystick_hwdata
58 {
59  /* joystick ID */
60  UINT id;
61 
62  /* values used to translate device-specific coordinates into
63  SDL-standard ranges */
64  struct _transaxis
65  {
66  int offset;
67  float scale;
68  } transaxis[6];
69 };
70 
71 /* Convert a Windows Multimedia API return code to a text message */
72 static void SetMMerror(char *function, int code);
73 
74 
75 static char *
76 GetJoystickName(int index, const char *szRegKey)
77 {
78  /* added 7/24/2004 by Eckhard Stolberg */
79  /*
80  see if there is a joystick for the current
81  index (1-16) listed in the registry
82  */
83  char *name = NULL;
84  HKEY hTopKey;
85  HKEY hKey;
86  DWORD regsize;
87  LONG regresult;
88  char regkey[256];
89  char regvalue[256];
90  char regname[256];
91 
92  SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s\\%s",
93  REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR);
94  hTopKey = HKEY_LOCAL_MACHINE;
95  regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
96  if (regresult != ERROR_SUCCESS) {
97  hTopKey = HKEY_CURRENT_USER;
98  regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
99  }
100  if (regresult != ERROR_SUCCESS) {
101  return NULL;
102  }
103 
104  /* find the registry key name for the joystick's properties */
105  regsize = sizeof(regname);
106  SDL_snprintf(regvalue, SDL_arraysize(regvalue), "Joystick%d%s", index + 1,
107  REGSTR_VAL_JOYOEMNAME);
108  regresult =
109  RegQueryValueExA(hKey, regvalue, 0, 0, (LPBYTE) regname, &regsize);
110  RegCloseKey(hKey);
111 
112  if (regresult != ERROR_SUCCESS) {
113  return NULL;
114  }
115 
116  /* open that registry key */
117  SDL_snprintf(regkey, SDL_arraysize(regkey), "%s\\%s", REGSTR_PATH_JOYOEM,
118  regname);
119  regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey);
120  if (regresult != ERROR_SUCCESS) {
121  return NULL;
122  }
123 
124  /* find the size for the OEM name text */
125  regsize = sizeof(regvalue);
126  regresult =
127  RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, &regsize);
128  if (regresult == ERROR_SUCCESS) {
129  /* allocate enough memory for the OEM name text ... */
130  name = (char *) SDL_malloc(regsize);
131  if (name) {
132  /* ... and read it from the registry */
133  regresult = RegQueryValueExA(hKey,
134  REGSTR_VAL_JOYOEMNAME, 0, 0,
135  (LPBYTE) name, &regsize);
136  }
137  }
138  RegCloseKey(hKey);
139 
140  return (name);
141 }
142 
143 static int SDL_SYS_numjoysticks = 0;
144 
145 /* Function to scan the system for joysticks.
146  * Joystick 0 should be the system default joystick.
147  * It should return 0, or -1 on an unrecoverable fatal error.
148  */
149 int
151 {
152  int i;
153  int maxdevs;
154  JOYINFOEX joyinfo;
155  JOYCAPSA joycaps;
156  MMRESULT result;
157 
158  /* Reset the joystick ID & name mapping tables */
159  for (i = 0; i < MAX_JOYSTICKS; ++i) {
160  SYS_JoystickID[i] = 0;
161  SYS_JoystickName[i] = NULL;
162  }
163 
164  /* Loop over all potential joystick devices */
165  SDL_SYS_numjoysticks = 0;
166  maxdevs = joyGetNumDevs();
167  for (i = JOYSTICKID1; i < maxdevs && SDL_SYS_numjoysticks < MAX_JOYSTICKS; ++i) {
168 
169  joyinfo.dwSize = sizeof(joyinfo);
170  joyinfo.dwFlags = JOY_RETURNALL;
171  result = joyGetPosEx(i, &joyinfo);
172  if (result == JOYERR_NOERROR) {
173  result = joyGetDevCapsA(i, &joycaps, sizeof(joycaps));
174  if (result == JOYERR_NOERROR) {
175  SYS_JoystickID[SDL_SYS_numjoysticks] = i;
176  SYS_Joystick[SDL_SYS_numjoysticks] = joycaps;
177  SYS_JoystickName[SDL_SYS_numjoysticks] =
178  GetJoystickName(i, joycaps.szRegKey);
179  SDL_SYS_numjoysticks++;
180  }
181  }
182  }
183  return (SDL_SYS_numjoysticks);
184 }
185 
187 {
188  return SDL_SYS_numjoysticks;
189 }
190 
192 {
193 }
194 
195 /* Function to get the device-dependent name of a joystick */
196 const char *
197 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
198 {
199  if (SYS_JoystickName[device_index] != NULL) {
200  return (SYS_JoystickName[device_index]);
201  } else {
202  return (SYS_Joystick[device_index].szPname);
203  }
204 }
205 
206 /* Function to perform the mapping from device index to the instance id for this index */
208 {
209  return device_index;
210 }
211 
212 /* Function to open a joystick for use.
213  The joystick to open is specified by the device index.
214  This should fill the nbuttons and naxes fields of the joystick structure.
215  It returns 0, or -1 if there is an error.
216  */
217 int
218 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
219 {
220  int index, i;
221  int caps_flags[MAX_AXES - 2] =
222  { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV };
223  int axis_min[MAX_AXES], axis_max[MAX_AXES];
224 
225 
226  /* shortcut */
227  index = device_index;
228  axis_min[0] = SYS_Joystick[index].wXmin;
229  axis_max[0] = SYS_Joystick[index].wXmax;
230  axis_min[1] = SYS_Joystick[index].wYmin;
231  axis_max[1] = SYS_Joystick[index].wYmax;
232  axis_min[2] = SYS_Joystick[index].wZmin;
233  axis_max[2] = SYS_Joystick[index].wZmax;
234  axis_min[3] = SYS_Joystick[index].wRmin;
235  axis_max[3] = SYS_Joystick[index].wRmax;
236  axis_min[4] = SYS_Joystick[index].wUmin;
237  axis_max[4] = SYS_Joystick[index].wUmax;
238  axis_min[5] = SYS_Joystick[index].wVmin;
239  axis_max[5] = SYS_Joystick[index].wVmax;
240 
241  /* allocate memory for system specific hardware data */
242  joystick->instance_id = device_index;
243  joystick->hwdata =
244  (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
245  if (joystick->hwdata == NULL) {
246  return SDL_OutOfMemory();
247  }
248  SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
249 
250  /* set hardware data */
251  joystick->hwdata->id = SYS_JoystickID[index];
252  for (i = 0; i < MAX_AXES; ++i) {
253  if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) {
254  joystick->hwdata->transaxis[i].offset = AXIS_MIN - axis_min[i];
255  joystick->hwdata->transaxis[i].scale =
256  (float) (AXIS_MAX - AXIS_MIN) / (axis_max[i] - axis_min[i]);
257  } else {
258  joystick->hwdata->transaxis[i].offset = 0;
259  joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */
260  }
261  }
262 
263  /* fill nbuttons, naxes, and nhats fields */
264  joystick->nbuttons = SYS_Joystick[index].wNumButtons;
265  joystick->naxes = SYS_Joystick[index].wNumAxes;
266  if (SYS_Joystick[index].wCaps & JOYCAPS_HASPOV) {
267  joystick->nhats = 1;
268  } else {
269  joystick->nhats = 0;
270  }
271  return (0);
272 }
273 
274 /* Function to determine if this joystick is attached to the system right now */
275 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
276 {
277  return SDL_TRUE;
278 }
279 
280 static Uint8
281 TranslatePOV(DWORD value)
282 {
283  Uint8 pos;
284 
285  pos = SDL_HAT_CENTERED;
286  if (value != JOY_POVCENTERED) {
287  if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) {
288  pos |= SDL_HAT_UP;
289  }
290  if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) {
291  pos |= SDL_HAT_RIGHT;
292  }
293  if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) {
294  pos |= SDL_HAT_DOWN;
295  }
296  if (value > JOY_POVBACKWARD) {
297  pos |= SDL_HAT_LEFT;
298  }
299  }
300  return (pos);
301 }
302 
303 /* Function to update the state of a joystick - called as a device poll.
304  * This function shouldn't update the joystick structure directly,
305  * but instead should call SDL_PrivateJoystick*() to deliver events
306  * and update joystick device state.
307  */
308 void
309 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
310 {
311  MMRESULT result;
312  int i;
313  DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
314  JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
315  };
316  DWORD pos[MAX_AXES];
317  struct _transaxis *transaxis;
318  int value, change;
319  JOYINFOEX joyinfo;
320 
321  joyinfo.dwSize = sizeof(joyinfo);
322  joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
323  if (!joystick->hats) {
324  joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
325  }
326  result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
327  if (result != JOYERR_NOERROR) {
328  SetMMerror("joyGetPosEx", result);
329  return;
330  }
331 
332  /* joystick motion events */
333  pos[0] = joyinfo.dwXpos;
334  pos[1] = joyinfo.dwYpos;
335  pos[2] = joyinfo.dwZpos;
336  pos[3] = joyinfo.dwRpos;
337  pos[4] = joyinfo.dwUpos;
338  pos[5] = joyinfo.dwVpos;
339 
340  transaxis = joystick->hwdata->transaxis;
341  for (i = 0; i < joystick->naxes; i++) {
342  if (joyinfo.dwFlags & flags[i]) {
343  value =
344  (int) (((float) pos[i] +
345  transaxis[i].offset) * transaxis[i].scale);
346  change = (value - joystick->axes[i]);
347  if ((change < -JOY_AXIS_THRESHOLD)
348  || (change > JOY_AXIS_THRESHOLD)) {
349  SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
350  }
351  }
352  }
353 
354  /* joystick button events */
355  if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
356  for (i = 0; i < joystick->nbuttons; ++i) {
357  if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
358  if (!joystick->buttons[i]) {
359  SDL_PrivateJoystickButton(joystick, (Uint8) i,
360  SDL_PRESSED);
361  }
362  } else {
363  if (joystick->buttons[i]) {
364  SDL_PrivateJoystickButton(joystick, (Uint8) i,
365  SDL_RELEASED);
366  }
367  }
368  }
369  }
370 
371  /* joystick hat events */
372  if (joyinfo.dwFlags & JOY_RETURNPOV) {
373  Uint8 pos;
374 
375  pos = TranslatePOV(joyinfo.dwPOV);
376  if (pos != joystick->hats[0]) {
377  SDL_PrivateJoystickHat(joystick, 0, pos);
378  }
379  }
380 }
381 
382 /* Function to close a joystick after use */
383 void
384 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
385 {
386  SDL_free(joystick->hwdata);
387 }
388 
389 /* Function to perform any system-specific joystick related cleanup */
390 void
392 {
393  int i;
394  for (i = 0; i < MAX_JOYSTICKS; i++) {
395  SDL_free(SYS_JoystickName[i]);
396  SYS_JoystickName[i] = NULL;
397  }
398 }
399 
401 {
403  /* the GUID is just the first 16 chars of the name for now */
404  const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
405  SDL_zero( guid );
406  SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
407  return guid;
408 }
409 
410 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
411 {
413  /* the GUID is just the first 16 chars of the name for now */
414  const char *name = joystick->name;
415  SDL_zero( guid );
416  SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
417  return guid;
418 }
419 
420 
421 /* implementation functions */
422 void
423 SetMMerror(char *function, int code)
424 {
425  static char *error;
426  static char errbuf[1024];
427 
428  errbuf[0] = 0;
429  switch (code) {
430  case MMSYSERR_NODRIVER:
431  error = "Joystick driver not present";
432  break;
433 
434  case MMSYSERR_INVALPARAM:
435  case JOYERR_PARMS:
436  error = "Invalid parameter(s)";
437  break;
438 
439  case MMSYSERR_BADDEVICEID:
440  error = "Bad device ID";
441  break;
442 
443  case JOYERR_UNPLUGGED:
444  error = "Joystick not attached";
445  break;
446 
447  case JOYERR_NOCANDO:
448  error = "Can't capture joystick input";
449  break;
450 
451  default:
452  SDL_snprintf(errbuf, SDL_arraysize(errbuf),
453  "%s: Unknown Multimedia system error: 0x%x",
454  function, code);
455  break;
456  }
457 
458  if (!errbuf[0]) {
459  SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
460  error);
461  }
462  SDL_SetError("%s", errbuf);
463 }
464 
465 #endif /* SDL_JOYSTICK_WINMM */
466 
467 /* vi: set ts=4 sw=4 expandtab: */
GLenum GLenum GLenum GLenum GLenum scale
JoyStick_DeviceData * SYS_Joystick
GLuint id
#define SDL_min(x, y)
Definition: SDL_stdinc.h:351
GLuint64EXT * result
SDL_JoystickGUID guid
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:608
int SDL_SYS_NumJoysticks()
SDL_Joystick * joystick
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:684
GLuint const GLchar * name
void SDL_SYS_JoystickQuit(void)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:567
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:209
#define SDL_memcpy
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:72
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:211
GLsizei const GLfloat * value
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:143
void SDL_free(void *mem)
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
void SDL_SYS_JoystickDetect()
#define SDL_zero(x)
Definition: SDL_stdinc.h:361
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
GLuint index
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
int SDL_SYS_JoystickInit(void)
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:130
GLintptr offset
#define SDL_SetError
#define SDL_strlen
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
#define SDL_snprintf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:90
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
GLbitfield flags
#define SDL_malloc
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:207
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_HAT_UP
Definition: SDL_joystick.h:208
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:210
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
#define SDL_memset
int16_t Sint16
A signed 16-bit integer type.
Definition: SDL_stdinc.h:147