SDL  2.0
SDL_sysjoystick.m
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 /* This is the iOS implementation of the SDL joystick API */
24 #include "SDL_sysjoystick_c.h"
25 
26 /* needed for SDL_IPHONE_MAX_GFORCE macro */
27 #include "SDL_config_iphoneos.h"
28 
29 #include "SDL_joystick.h"
30 #include "SDL_hints.h"
31 #include "SDL_stdinc.h"
32 #include "../SDL_sysjoystick.h"
33 #include "../SDL_joystick_c.h"
34 
35 #if !SDL_EVENTS_DISABLED
36 #include "../../events/SDL_events_c.h"
37 #endif
38 
39 #import <CoreMotion/CoreMotion.h>
40 
41 #ifdef SDL_JOYSTICK_MFI
42 #import <GameController/GameController.h>
43 
44 static id connectObserver = nil;
45 static id disconnectObserver = nil;
46 #endif /* SDL_JOYSTICK_MFI */
47 
48 static const char *accelerometerName = "iOS Accelerometer";
49 static CMMotionManager *motionManager = nil;
50 
52 
53 static int numjoysticks = 0;
55 
57 GetDeviceForIndex(int device_index)
58 {
60  int i = 0;
61 
62  while (i < device_index) {
63  if (device == NULL) {
64  return NULL;
65  }
66  device = device->next;
67  i++;
68  }
69 
70  return device;
71 }
72 
73 static void
75 {
76 #ifdef SDL_JOYSTICK_MFI
77  const char *name = NULL;
78  /* Explicitly retain the controller because SDL_JoystickDeviceItem is a
79  * struct, and ARC doesn't work with structs. */
80  device->controller = (__bridge GCController *) CFBridgingRetain(controller);
81 
82  if (controller.vendorName) {
83  name = controller.vendorName.UTF8String;
84  }
85 
86  if (!name) {
87  name = "MFi Gamepad";
88  }
89 
90  device->name = SDL_strdup(name);
91 
92  device->guid.data[0] = 'M';
93  device->guid.data[1] = 'F';
94  device->guid.data[2] = 'i';
95  device->guid.data[3] = 'G';
96  device->guid.data[4] = 'a';
97  device->guid.data[5] = 'm';
98  device->guid.data[6] = 'e';
99  device->guid.data[7] = 'p';
100  device->guid.data[8] = 'a';
101  device->guid.data[9] = 'd';
102 
103  if (controller.extendedGamepad) {
104  device->guid.data[10] = 1;
105  } else if (controller.gamepad) {
106  device->guid.data[10] = 2;
107  }
108 
109  if (controller.extendedGamepad) {
110  device->naxes = 6; /* 2 thumbsticks and 2 triggers */
111  device->nhats = 1; /* d-pad */
112  device->nbuttons = 7; /* ABXY, shoulder buttons, pause button */
113  } else if (controller.gamepad) {
114  device->naxes = 0; /* no traditional analog inputs */
115  device->nhats = 1; /* d-pad */
116  device->nbuttons = 7; /* ABXY, shoulder buttons, pause button */
117  }
118  /* TODO: Handle micro profiles on tvOS. */
119 
120  /* This will be set when the first button press of the controller is
121  * detected. */
122  controller.playerIndex = -1;
123 #endif
124 }
125 
126 static void
128 {
130 #if !SDL_EVENTS_DISABLED
132 #endif
133 
134  while (device != NULL) {
135  if (device->controller == controller) {
136  return;
137  }
138  device = device->next;
139  }
140 
142  if (device == NULL) {
143  return;
144  }
145 
146  SDL_zerop(device);
147 
148  device->accelerometer = accelerometer;
149  device->instance_id = instancecounter++;
150 
151  if (accelerometer) {
152  device->name = SDL_strdup(accelerometerName);
153  device->naxes = 3; /* Device acceleration in the x, y, and z axes. */
154  device->nhats = 0;
155  device->nbuttons = 0;
156 
157  /* Use the accelerometer name as a GUID. */
158  SDL_memcpy(&device->guid.data, device->name, SDL_min(sizeof(SDL_JoystickGUID), SDL_strlen(device->name)));
159  } else if (controller) {
160  SDL_SYS_AddMFIJoystickDevice(device, controller);
161  }
162 
163  if (deviceList == NULL) {
164  deviceList = device;
165  } else {
166  SDL_JoystickDeviceItem *lastdevice = deviceList;
167  while (lastdevice->next != NULL) {
168  lastdevice = lastdevice->next;
169  }
170  lastdevice->next = device;
171  }
172 
173  ++numjoysticks;
174 
175 #if !SDL_EVENTS_DISABLED
176  event.type = SDL_JOYDEVICEADDED;
177 
178  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
179  event.jdevice.which = numjoysticks - 1;
180  if ((SDL_EventOK == NULL) ||
181  (*SDL_EventOK)(SDL_EventOKParam, &event)) {
182  SDL_PushEvent(&event);
183  }
184  }
185 #endif /* !SDL_EVENTS_DISABLED */
186 }
187 
188 static SDL_JoystickDeviceItem *
190 {
194 #if !SDL_EVENTS_DISABLED
196 #endif
197 
198  if (device == NULL) {
199  return NULL;
200  }
201 
202  next = device->next;
203 
204  while (item != NULL) {
205  if (item == device) {
206  break;
207  }
208  prev = item;
209  item = item->next;
210  }
211 
212  /* Unlink the device item from the device list. */
213  if (prev) {
214  prev->next = device->next;
215  } else if (device == deviceList) {
216  deviceList = device->next;
217  }
218 
219  if (device->joystick) {
220  device->joystick->hwdata = NULL;
221  }
222 
223 #ifdef SDL_JOYSTICK_MFI
224  @autoreleasepool {
225  if (device->controller) {
226  /* The controller was explicitly retained in the struct, so it
227  * should be explicitly released before freeing the struct. */
228  GCController *controller = CFBridgingRelease((__bridge CFTypeRef)(device->controller));
229  controller.controllerPausedHandler = nil;
230  device->controller = nil;
231  }
232  }
233 #endif /* SDL_JOYSTICK_MFI */
234 
235  --numjoysticks;
236 
237 #if !SDL_EVENTS_DISABLED
238  event.type = SDL_JOYDEVICEREMOVED;
239 
240  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
241  event.jdevice.which = device->instance_id;
242  if ((SDL_EventOK == NULL) ||
243  (*SDL_EventOK)(SDL_EventOKParam, &event)) {
244  SDL_PushEvent(&event);
245  }
246  }
247 #endif /* !SDL_EVENTS_DISABLED */
248 
249  SDL_free(device->name);
250  SDL_free(device);
251 
252  return next;
253 }
254 
255 /* Function to scan the system for joysticks.
256  * Joystick 0 should be the system default joystick.
257  * It should return 0, or -1 on an unrecoverable fatal error.
258  */
259 int
261 {
262  @autoreleasepool {
263  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
265 
266  if (!hint || SDL_atoi(hint)) {
267  /* Default behavior, accelerometer as joystick */
269  }
270 
271 #ifdef SDL_JOYSTICK_MFI
272  /* GameController.framework was added in iOS 7. */
273  if (![GCController class]) {
274  return numjoysticks;
275  }
276 
277  for (GCController *controller in [GCController controllers]) {
279  }
280 
281  connectObserver = [center addObserverForName:GCControllerDidConnectNotification
282  object:nil
283  queue:nil
284  usingBlock:^(NSNotification *note) {
285  GCController *controller = note.object;
286  SDL_SYS_AddJoystickDevice(controller, SDL_FALSE);
287  }];
288 
289  disconnectObserver = [center addObserverForName:GCControllerDidDisconnectNotification
290  object:nil
291  queue:nil
292  usingBlock:^(NSNotification *note) {
293  GCController *controller = note.object;
294  SDL_JoystickDeviceItem *device = deviceList;
295  while (device != NULL) {
296  if (device->controller == controller) {
297  SDL_SYS_RemoveJoystickDevice(device);
298  break;
299  }
300  device = device->next;
301  }
302  }];
303 #endif /* SDL_JOYSTICK_MFI */
304  }
305 
306  return numjoysticks;
307 }
308 
310 {
311  return numjoysticks;
312 }
313 
315 {
316 }
317 
318 /* Function to get the device-dependent name of a joystick */
319 const char *
321 {
322  SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
323  return device ? device->name : "Unknown";
324 }
325 
326 /* Function to perform the mapping from device index to the instance id for this index */
328 {
329  SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
330  return device ? device->instance_id : 0;
331 }
332 
333 /* Function to open a joystick for use.
334  The joystick to open is specified by the device index.
335  This should fill the nbuttons and naxes fields of the joystick structure.
336  It returns 0, or -1 if there is an error.
337  */
338 int
339 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
340 {
341  SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
342  if (device == NULL) {
343  return SDL_SetError("Could not open Joystick: no hardware device for the specified index");
344  }
345 
346  joystick->hwdata = device;
347  joystick->instance_id = device->instance_id;
348 
349  joystick->naxes = device->naxes;
350  joystick->nhats = device->nhats;
351  joystick->nbuttons = device->nbuttons;
352  joystick->nballs = 0;
353 
354  device->joystick = joystick;
355 
356  @autoreleasepool {
357  if (device->accelerometer) {
358  if (motionManager == nil) {
359  motionManager = [[CMMotionManager alloc] init];
360  }
361 
362  /* Shorter times between updates can significantly increase CPU usage. */
363  motionManager.accelerometerUpdateInterval = 0.1;
364  [motionManager startAccelerometerUpdates];
365  } else {
366 #ifdef SDL_JOYSTICK_MFI
367  GCController *controller = device->controller;
368  controller.controllerPausedHandler = ^(GCController *c) {
369  if (joystick->hwdata) {
370  ++joystick->hwdata->num_pause_presses;
371  }
372  };
373 #endif /* SDL_JOYSTICK_MFI */
374  }
375  }
376 
377  return 0;
378 }
379 
380 /* Function to determine if this joystick is attached to the system right now */
381 SDL_bool
383 {
384  return joystick->hwdata != NULL;
385 }
386 
387 static void
389 {
390  const float maxgforce = SDL_IPHONE_MAX_GFORCE;
391  const SInt16 maxsint16 = 0x7FFF;
392  CMAcceleration accel;
393 
394  @autoreleasepool {
395  if (!motionManager.isAccelerometerActive) {
396  return;
397  }
398 
399  accel = motionManager.accelerometerData.acceleration;
400  }
401 
402  /*
403  Convert accelerometer data from floating point to Sint16, which is what
404  the joystick system expects.
405 
406  To do the conversion, the data is first clamped onto the interval
407  [-SDL_IPHONE_MAX_G_FORCE, SDL_IPHONE_MAX_G_FORCE], then the data is multiplied
408  by MAX_SINT16 so that it is mapped to the full range of an Sint16.
409 
410  You can customize the clamped range of this function by modifying the
411  SDL_IPHONE_MAX_GFORCE macro in SDL_config_iphoneos.h.
412 
413  Once converted to Sint16, the accelerometer data no longer has coherent
414  units. You can convert the data back to units of g-force by multiplying
415  it in your application's code by SDL_IPHONE_MAX_GFORCE / 0x7FFF.
416  */
417 
418  /* clamp the data */
419  accel.x = SDL_min(SDL_max(accel.x, -maxgforce), maxgforce);
420  accel.y = SDL_min(SDL_max(accel.y, -maxgforce), maxgforce);
421  accel.z = SDL_min(SDL_max(accel.z, -maxgforce), maxgforce);
422 
423  /* pass in data mapped to range of SInt16 */
424  SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16);
425  SDL_PrivateJoystickAxis(joystick, 1, -(accel.y / maxgforce) * maxsint16);
426  SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16);
427 }
428 
429 #ifdef SDL_JOYSTICK_MFI
430 static Uint8
431 SDL_SYS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad)
432 {
433  Uint8 hat = 0;
434 
435  if (dpad.up.isPressed) {
436  hat |= SDL_HAT_UP;
437  } else if (dpad.down.isPressed) {
438  hat |= SDL_HAT_DOWN;
439  }
440 
441  if (dpad.left.isPressed) {
442  hat |= SDL_HAT_LEFT;
443  } else if (dpad.right.isPressed) {
444  hat |= SDL_HAT_RIGHT;
445  }
446 
447  if (hat == 0) {
448  return SDL_HAT_CENTERED;
449  }
450 
451  return hat;
452 }
453 #endif
454 
455 static void
457 {
458 #ifdef SDL_JOYSTICK_MFI
459  @autoreleasepool {
460  GCController *controller = joystick->hwdata->controller;
461  Uint8 hatstate = SDL_HAT_CENTERED;
462  int i;
463  int updateplayerindex = 0;
464 
465  if (controller.extendedGamepad) {
466  GCExtendedGamepad *gamepad = controller.extendedGamepad;
467 
468  /* Axis order matches the XInput Windows mappings. */
469  Sint16 axes[] = {
470  (Sint16) (gamepad.leftThumbstick.xAxis.value * 32767),
471  (Sint16) (gamepad.leftThumbstick.yAxis.value * -32767),
472  (Sint16) ((gamepad.leftTrigger.value * 65535) - 32768),
473  (Sint16) (gamepad.rightThumbstick.xAxis.value * 32767),
474  (Sint16) (gamepad.rightThumbstick.yAxis.value * -32767),
475  (Sint16) ((gamepad.rightTrigger.value * 65535) - 32768),
476  };
477 
478  /* Button order matches the XInput Windows mappings. */
479  Uint8 buttons[] = {
480  gamepad.buttonA.isPressed, gamepad.buttonB.isPressed,
481  gamepad.buttonX.isPressed, gamepad.buttonY.isPressed,
482  gamepad.leftShoulder.isPressed,
483  gamepad.rightShoulder.isPressed,
484  };
485 
486  hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad);
487 
488  for (i = 0; i < SDL_arraysize(axes); i++) {
489  /* The triggers (axes 2 and 5) are resting at -32768 but SDL
490  * initializes its values to 0. We only want to make sure the
491  * player index is up to date if the user actually moves an axis. */
492  if ((i != 2 && i != 5) || axes[i] != -32768) {
493  updateplayerindex |= (joystick->axes[i] != axes[i]);
494  }
495  SDL_PrivateJoystickAxis(joystick, i, axes[i]);
496  }
497 
498  for (i = 0; i < SDL_arraysize(buttons); i++) {
499  updateplayerindex |= (joystick->buttons[i] != buttons[i]);
500  SDL_PrivateJoystickButton(joystick, i, buttons[i]);
501  }
502  } else if (controller.gamepad) {
503  GCGamepad *gamepad = controller.gamepad;
504 
505  /* Button order matches the XInput Windows mappings. */
506  Uint8 buttons[] = {
507  gamepad.buttonA.isPressed, gamepad.buttonB.isPressed,
508  gamepad.buttonX.isPressed, gamepad.buttonY.isPressed,
509  gamepad.leftShoulder.isPressed,
510  gamepad.rightShoulder.isPressed,
511  };
512 
513  hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad);
514 
515  for (i = 0; i < SDL_arraysize(buttons); i++) {
516  updateplayerindex |= (joystick->buttons[i] != buttons[i]);
517  SDL_PrivateJoystickButton(joystick, i, buttons[i]);
518  }
519  }
520  /* TODO: Handle micro profiles on tvOS. */
521 
522  if (joystick->nhats > 0) {
523  updateplayerindex |= (joystick->hats[0] != hatstate);
524  SDL_PrivateJoystickHat(joystick, 0, hatstate);
525  }
526 
527  for (i = 0; i < joystick->hwdata->num_pause_presses; i++) {
528  /* The pause button is always last. */
529  Uint8 pausebutton = joystick->nbuttons - 1;
530 
531  SDL_PrivateJoystickButton(joystick, pausebutton, SDL_PRESSED);
532  SDL_PrivateJoystickButton(joystick, pausebutton, SDL_RELEASED);
533 
534  updateplayerindex = YES;
535  }
536 
537  joystick->hwdata->num_pause_presses = 0;
538 
539  if (updateplayerindex && controller.playerIndex == -1) {
540  BOOL usedPlayerIndexSlots[4] = {NO, NO, NO, NO};
541 
542  /* Find the player index of all other connected controllers. */
543  for (GCController *c in [GCController controllers]) {
544  if (c != controller && c.playerIndex >= 0) {
545  usedPlayerIndexSlots[c.playerIndex] = YES;
546  }
547  }
548 
549  /* Set this controller's player index to the first unused index.
550  * FIXME: This logic isn't great... but SDL doesn't expose this
551  * concept in its external API, so we don't have much to go on. */
552  for (i = 0; i < SDL_arraysize(usedPlayerIndexSlots); i++) {
553  if (!usedPlayerIndexSlots[i]) {
554  controller.playerIndex = i;
555  break;
556  }
557  }
558  }
559  }
560 #endif
561 }
562 
563 /* Function to update the state of a joystick - called as a device poll.
564  * This function shouldn't update the joystick structure directly,
565  * but instead should call SDL_PrivateJoystick*() to deliver events
566  * and update joystick device state.
567  */
568 void
570 {
571  SDL_JoystickDeviceItem *device = joystick->hwdata;
572 
573  if (device == NULL) {
574  return;
575  }
576 
577  if (device->accelerometer) {
578  SDL_SYS_AccelerometerUpdate(joystick);
579  } else if (device->controller) {
580  SDL_SYS_MFIJoystickUpdate(joystick);
581  }
582 }
583 
584 /* Function to close a joystick after use */
585 void
587 {
588  SDL_JoystickDeviceItem *device = joystick->hwdata;
589 
590  if (device == NULL) {
591  return;
592  }
593 
594  device->joystick = NULL;
595 
596  @autoreleasepool {
597  if (device->accelerometer) {
598  [motionManager stopAccelerometerUpdates];
599  } else if (device->controller) {
600 #ifdef SDL_JOYSTICK_MFI
601  GCController *controller = device->controller;
602  controller.controllerPausedHandler = nil;
603  controller.playerIndex = -1;
604 #endif
605  }
606  }
607 }
608 
609 /* Function to perform any system-specific joystick related cleanup */
610 void
612 {
613  @autoreleasepool {
614 #ifdef SDL_JOYSTICK_MFI
615  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
616 
617  if (connectObserver) {
618  [center removeObserver:connectObserver name:GCControllerDidConnectNotification object:nil];
619  connectObserver = nil;
620  }
621 
622  if (disconnectObserver) {
623  [center removeObserver:disconnectObserver name:GCControllerDidDisconnectNotification object:nil];
624  disconnectObserver = nil;
625  }
626 #endif /* SDL_JOYSTICK_MFI */
627 
628  while (deviceList != NULL) {
629  SDL_SYS_RemoveJoystickDevice(deviceList);
630  }
631 
632  motionManager = nil;
633  }
634 
635  numjoysticks = 0;
636 }
637 
639 SDL_SYS_JoystickGetDeviceGUID( int device_index )
640 {
641  SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
643  if (device) {
644  guid = device->guid;
645  } else {
646  SDL_zero(guid);
647  }
648  return guid;
649 }
650 
653 {
655  if (joystick->hwdata) {
656  guid = joystick->hwdata->guid;
657  } else {
658  SDL_zero(guid);
659  }
660  return guid;
661 }
662 
663 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_min(x, y)
Definition: SDL_stdinc.h:345
SDL_JoystickGUID guid
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:542
int SDL_SYS_NumJoysticks()
static SDL_JoystickDeviceItem * deviceList
SDL_Joystick * joystick
static void SDL_SYS_MFIJoystickUpdate(SDL_Joystick *joystick)
#define SDL_GetHint
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:618
#define SDL_ENABLE
Definition: SDL_events.h:718
static const char * accelerometerName
struct joystick_hwdata * next
GLuint const GLchar * name
void SDL_SYS_JoystickQuit(void)
static SDL_JoystickDeviceItem * GetDeviceForIndex(int device_index)
Uint8 data[16]
Definition: SDL_joystick.h:69
#define SDL_zerop(x)
Definition: SDL_stdinc.h:356
#define SDL_max(x, y)
Definition: SDL_stdinc.h:346
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:501
SDL_bool
Definition: SDL_stdinc.h:126
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:209
#define SDL_memcpy
#define SDL_HINT_ACCELEROMETER_AS_JOYSTICK
A variable controlling whether the Android / iOS built-in accelerometer should be listed as a joystic...
Definition: SDL_hints.h:289
#define SDL_GetEventState(type)
Definition: SDL_events.h:731
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:72
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:211
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
struct _cl_event * event
void SDL_free(void *mem)
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
SDL_EventFilter SDL_EventOK
Definition: SDL_events.c:40
static void SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller)
#define SDL_PushEvent
const GLubyte * c
void SDL_SYS_JoystickDetect()
#define SDL_zero(x)
Definition: SDL_stdinc.h:355
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
#define SDL_atoi
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:42
int SDL_SYS_JoystickInit(void)
void * SDL_EventOKParam
Definition: SDL_events.c:41
#define SDL_IPHONE_MAX_GFORCE
#define NULL
Definition: begin_code.h:143
#define SDL_SetError
static void SDL_SYS_AccelerometerUpdate(SDL_Joystick *joystick)
static SDL_JoystickID instancecounter
#define SDL_strlen
#define SDL_strdup
struct SDL_joylist_item * item
static SDL_JoystickDeviceItem * SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device)
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
static int numjoysticks
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
General event structure.
Definition: SDL_events.h:521
#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
GLuint in
#define SDL_HAT_UP
Definition: SDL_joystick.h:208
static void SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:210
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
GCController __unsafe_unretained * controller
int16_t Sint16
A signed 16-bit integer type.
Definition: SDL_stdinc.h:143
Uint32 type
Definition: SDL_events.h:523
static CMMotionManager * motionManager