SDL  2.0
SDL_mmjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2019 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
156 SDL_SYS_JoystickInit(void)
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
193 SDL_SYS_NumJoysticks(void)
194 {
195  return SDL_SYS_numjoysticks;
196 }
197 
198 void
199 SDL_SYS_JoystickDetect(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 */
215 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_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 static Uint8
283 TranslatePOV(DWORD value)
284 {
285  Uint8 pos;
286 
287  pos = SDL_HAT_CENTERED;
288  if (value != JOY_POVCENTERED) {
289  if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) {
290  pos |= SDL_HAT_UP;
291  }
292  if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) {
293  pos |= SDL_HAT_RIGHT;
294  }
295  if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) {
296  pos |= SDL_HAT_DOWN;
297  }
298  if (value > JOY_POVBACKWARD) {
299  pos |= SDL_HAT_LEFT;
300  }
301  }
302  return (pos);
303 }
304 
305 /* Function to update the state of a joystick - called as a device poll.
306  * This function shouldn't update the joystick structure directly,
307  * but instead should call SDL_PrivateJoystick*() to deliver events
308  * and update joystick device state.
309  */
310 void
311 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
312 {
313  MMRESULT result;
314  int i;
315  DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ,
316  JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
317  };
318  DWORD pos[MAX_AXES];
319  struct _transaxis *transaxis;
320  int value;
321  JOYINFOEX joyinfo;
322 
323  joyinfo.dwSize = sizeof(joyinfo);
324  joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS;
325  if (!joystick->hats) {
326  joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS);
327  }
328  result = joyGetPosEx(joystick->hwdata->id, &joyinfo);
329  if (result != JOYERR_NOERROR) {
330  SetMMerror("joyGetPosEx", result);
331  return;
332  }
333 
334  /* joystick motion events */
335  pos[0] = joyinfo.dwXpos;
336  pos[1] = joyinfo.dwYpos;
337  pos[2] = joyinfo.dwZpos;
338  pos[3] = joyinfo.dwRpos;
339  pos[4] = joyinfo.dwUpos;
340  pos[5] = joyinfo.dwVpos;
341 
342  transaxis = joystick->hwdata->transaxis;
343  for (i = 0; i < joystick->naxes; i++) {
344  if (joyinfo.dwFlags & flags[i]) {
345  value = (int) (((float) pos[i] + transaxis[i].offset) * transaxis[i].scale);
346  SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value);
347  }
348  }
349 
350  /* joystick button events */
351  if (joyinfo.dwFlags & JOY_RETURNBUTTONS) {
352  for (i = 0; i < joystick->nbuttons; ++i) {
353  if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) {
355  } else {
357  }
358  }
359  }
360 
361  /* joystick hat events */
362  if (joyinfo.dwFlags & JOY_RETURNPOV) {
363  SDL_PrivateJoystickHat(joystick, 0, TranslatePOV(joyinfo.dwPOV));
364  }
365 }
366 
367 /* Function to close a joystick after use */
368 void
369 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
370 {
371  SDL_free(joystick->hwdata);
372 }
373 
374 /* Function to perform any system-specific joystick related cleanup */
375 void
376 SDL_SYS_JoystickQuit(void)
377 {
378  int i;
379  for (i = 0; i < MAX_JOYSTICKS; i++) {
380  SDL_free(SYS_JoystickName[i]);
381  SYS_JoystickName[i] = NULL;
382  }
383 }
384 
385 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
386 {
387  SDL_JoystickGUID guid;
388  /* the GUID is just the first 16 chars of the name for now */
389  const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
390  SDL_zero( guid );
391  SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
392  return guid;
393 }
394 
395 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
396 {
397  SDL_JoystickGUID guid;
398  /* the GUID is just the first 16 chars of the name for now */
399  const char *name = joystick->name;
400  SDL_zero( guid );
401  SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
402  return guid;
403 }
404 
405 
406 /* implementation functions */
407 void
408 SetMMerror(char *function, int code)
409 {
410  static char *error;
411  static char errbuf[1024];
412 
413  errbuf[0] = 0;
414  switch (code) {
415  case MMSYSERR_NODRIVER:
416  error = "Joystick driver not present";
417  break;
418 
419  case MMSYSERR_INVALPARAM:
420  case JOYERR_PARMS:
421  error = "Invalid parameter(s)";
422  break;
423 
424  case MMSYSERR_BADDEVICEID:
425  error = "Bad device ID";
426  break;
427 
428  case JOYERR_UNPLUGGED:
429  error = "Joystick not attached";
430  break;
431 
432  case JOYERR_NOCANDO:
433  error = "Can't capture joystick input";
434  break;
435 
436  default:
437  SDL_snprintf(errbuf, SDL_arraysize(errbuf),
438  "%s: Unknown Multimedia system error: 0x%x",
439  function, code);
440  break;
441  }
442 
443  if (!errbuf[0]) {
444  SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
445  error);
446  }
447  SDL_SetError("%s", errbuf);
448 }
449 
450 #endif /* SDL_JOYSTICK_WINMM */
451 
452 /* vi: set ts=4 sw=4 expandtab: */
SDL_zero
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SYS_Joystick
JoyStick_DeviceData * SYS_Joystick
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
SDL_events.h
offset
GLintptr offset
Definition: SDL_opengl_glext.h:538
scale
GLenum GLenum GLenum GLenum GLenum scale
Definition: SDL_opengl_glext.h:9375
SDL_HAT_CENTERED
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:329
NULL
#define NULL
Definition: begin_code.h:167
SDL_HAT_DOWN
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:332
SDL_joystick.h
joystick_hwdata::joystick
SDL_Joystick * joystick
Definition: SDL_sysjoystick_c.h:42
index
GLuint index
Definition: SDL_opengl_glext.h:660
SDL_RELEASED
#define SDL_RELEASED
Definition: SDL_events.h:49
result
GLuint64EXT * result
Definition: SDL_opengl_glext.h:9432
SDL_PrivateJoystickAxis
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:833
SDL_JoystickID
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
SDL_PRESSED
#define SDL_PRESSED
Definition: SDL_events.h:50
Sint16
int16_t Sint16
Definition: SDL_stdinc.h:185
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:387
SDL_JOYSTICK_AXIS_MIN
#define SDL_JOYSTICK_AXIS_MIN
Definition: SDL_joystick.h:302
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:660
SDL_PrivateJoystickButton
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:966
SDL_HAT_LEFT
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:333
SDL_min
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
SDL_JOYSTICK_AXIS_MAX
#define SDL_JOYSTICK_AXIS_MAX
Definition: SDL_joystick.h:301
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_PrivateJoystickHat
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:890
id
GLuint id
Definition: SDL_opengl_glext.h:528
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_HAT_RIGHT
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:331
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:698
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_snprintf
#define SDL_snprintf
Definition: SDL_dynapi_overrides.h:40
SDL_strlen
#define SDL_strlen
Definition: SDL_dynapi_overrides.h:393
SDL_HAT_UP
#define SDL_HAT_UP
Definition: SDL_joystick.h:330
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
flags
GLbitfield flags
Definition: SDL_opengl_glext.h:1480
SDL_JoystickGUID
Definition: SDL_joystick.h:70
i
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
joystick_hwdata
Definition: SDL_sysjoystick_c.h:46
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179