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