1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 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_MACOS
25
26/*  SDL stuff  --  "SDL_sysjoystick.c"
27    MacOS joystick functions by Frederick Reitberger
28
29    The code that follows is meant for SDL.  Use at your own risk.
30*/
31
32#include <InputSprocket.h>
33
34#include "SDL_joystick.h"
35#include "../SDL_sysjoystick.h"
36#include "../SDL_joystick_c.h"
37
38
39/*  The max number of joysticks we will detect  */
40#define     MAX_JOYSTICKS       16
41/*  Limit ourselves to 32 elements per device  */
42#define     kMaxReferences      32
43
44#define		ISpSymmetricAxisToFloat(axis)	((((float) axis) - kISpAxisMiddle) / (kISpAxisMaximum-kISpAxisMiddle))
45#define		ISpAsymmetricAxisToFloat(axis)	(((float) axis) / (kISpAxisMaximum))
46
47
48static  ISpDeviceReference  SYS_Joysticks[MAX_JOYSTICKS];
49static  ISpElementListReference SYS_Elements[MAX_JOYSTICKS];
50static  ISpDeviceDefinition     SYS_DevDef[MAX_JOYSTICKS];
51
52struct joystick_hwdata
53{
54    char name[64];
55/*    Uint8   id;*/
56    ISpElementReference refs[kMaxReferences];
57    /*  gonna need some sort of mapping info  */
58};
59
60
61/* Function to scan the system for joysticks.
62 * Joystick 0 should be the system default joystick.
63 * This function should return the number of available joysticks, or -1
64 * on an unrecoverable fatal error.
65 */
66int SDL_SYS_JoystickInit(void)
67{
68    static ISpDeviceClass classes[4] = {
69        kISpDeviceClass_Joystick,
70    #if kISpDeviceClass_Gamepad
71        kISpDeviceClass_Gamepad,
72    #endif
73        kISpDeviceClass_Wheel,
74        0
75    };
76    OSErr   err;
77    int     i;
78    UInt32  count, numJoysticks;
79
80    if ( (Ptr)0 == (Ptr)ISpStartup ) {
81        SDL_SetError("InputSprocket not installed");
82        return -1;  //  InputSprocket not installed
83    }
84
85    if( (Ptr)0 == (Ptr)ISpGetVersion ) {
86        SDL_SetError("InputSprocket not version 1.1 or newer");
87        return -1;  //  old version of ISp (not at least 1.1)
88    }
89
90    ISpStartup();
91
92    /* Get all the joysticks */
93    numJoysticks = 0;
94    for ( i=0; classes[i]; ++i ) {
95        count = 0;
96        err = ISpDevices_ExtractByClass(
97            classes[i],
98            MAX_JOYSTICKS-numJoysticks,
99            &count,
100            &SYS_Joysticks[numJoysticks]);
101        numJoysticks += count;
102    }
103
104    for(i = 0; i < numJoysticks; i++)
105    {
106        ISpDevice_GetDefinition(
107            SYS_Joysticks[i], sizeof(ISpDeviceDefinition),
108            &SYS_DevDef[i]);
109
110        err = ISpElementList_New(
111            0, NULL,
112            &SYS_Elements[i], 0);
113
114        if (err) {
115            SDL_OutOfMemory();
116            return -1;
117        }
118
119        ISpDevice_GetElementList(
120            SYS_Joysticks[i],
121            &SYS_Elements[i]);
122    }
123
124    ISpDevices_Deactivate(numJoysticks, SYS_Joysticks);
125
126    return numJoysticks;
127}
128
129/* Function to get the device-dependent name of a joystick */
130const char *SDL_SYS_JoystickName(int index)
131{
132    static char name[64];
133    int len;
134
135    /*  convert pascal string to c-string  */
136    len = SYS_DevDef[index].deviceName[0];
137    if ( len >= sizeof(name) ) {
138        len = (sizeof(name) - 1);
139    }
140    SDL_memcpy(name, &SYS_DevDef[index].deviceName[1], len);
141    name[len] = '\0';
142
143    return name;
144}
145
146/* Function to open a joystick for use.
147   The joystick to open is specified by the index field of the joystick.
148   This should fill the nbuttons and naxes fields of the joystick structure.
149   It returns 0, or -1 if there is an error.
150 */
151int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
152{
153    int     index;
154    UInt32  count, gotCount, count2;
155    long    numAxis, numButtons, numHats, numBalls;
156
157    count = kMaxReferences;
158    count2 = 0;
159    numAxis = numButtons = numHats = numBalls = 0;
160
161    index = joystick->index;
162
163    /* allocate memory for system specific hardware data */
164    joystick->hwdata = (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata));
165    if (joystick->hwdata == NULL)
166    {
167		SDL_OutOfMemory();
168		return(-1);
169    }
170    SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
171    SDL_strlcpy(joystick->hwdata->name, SDL_SYS_JoystickName(index), SDL_arraysize(joystick->hwdata->name));
172    joystick->name = joystick->hwdata->name;
173
174    ISpElementList_ExtractByKind(
175        SYS_Elements[index],
176        kISpElementKind_Axis,
177        count,
178        &gotCount,
179        joystick->hwdata->refs);
180
181    numAxis = gotCount;
182    count -= gotCount;
183    count2 += gotCount;
184
185    ISpElementList_ExtractByKind(
186        SYS_Elements[index],
187        kISpElementKind_DPad,
188        count,
189        &gotCount,
190        &(joystick->hwdata->refs[count2]));
191
192    numHats = gotCount;
193    count -= gotCount;
194    count2 += gotCount;
195
196    ISpElementList_ExtractByKind(
197        SYS_Elements[index],
198        kISpElementKind_Button,
199        count,
200        &gotCount,
201        &(joystick->hwdata->refs[count2]));
202
203    numButtons = gotCount;
204    count -= gotCount;
205    count2 += gotCount;
206
207    joystick->naxes = numAxis;
208    joystick->nhats = numHats;
209    joystick->nballs = numBalls;
210    joystick->nbuttons = numButtons;
211
212    ISpDevices_Activate(
213        1,
214        &SYS_Joysticks[index]);
215
216    return 0;
217}
218
219/* Function to update the state of a joystick - called as a device poll.
220 * This function shouldn't update the joystick structure directly,
221 * but instead should call SDL_PrivateJoystick*() to deliver events
222 * and update joystick device state.
223 */
224void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
225{
226    int     i, j;
227    ISpAxisData     a;
228    ISpDPadData     b;
229    //ISpDeltaData    c;
230    ISpButtonData   d;
231
232    for(i = 0, j = 0; i < joystick->naxes; i++, j++)
233    {
234        Sint16 value;
235
236        ISpElement_GetSimpleState(
237            joystick->hwdata->refs[j],
238            &a);
239        value = (ISpSymmetricAxisToFloat(a)* 32767.0);
240        if ( value != joystick->axes[i] ) {
241            SDL_PrivateJoystickAxis(joystick, i, value);
242        }
243    }
244
245    for(i = 0; i < joystick->nhats; i++, j++)
246    {
247        Uint8 pos;
248
249        ISpElement_GetSimpleState(
250            joystick->hwdata->refs[j],
251            &b);
252        switch(b) {
253            case kISpPadIdle:
254                pos = SDL_HAT_CENTERED;
255                break;
256            case kISpPadLeft:
257                pos = SDL_HAT_LEFT;
258                break;
259            case kISpPadUpLeft:
260                pos = SDL_HAT_LEFTUP;
261                break;
262            case kISpPadUp:
263                pos = SDL_HAT_UP;
264                break;
265            case kISpPadUpRight:
266                pos = SDL_HAT_RIGHTUP;
267                break;
268            case kISpPadRight:
269                pos = SDL_HAT_RIGHT;
270                break;
271            case kISpPadDownRight:
272                pos = SDL_HAT_RIGHTDOWN;
273                break;
274            case kISpPadDown:
275                pos = SDL_HAT_DOWN;
276                break;
277            case kISpPadDownLeft:
278                pos = SDL_HAT_LEFTDOWN;
279                break;
280        }
281        if ( pos != joystick->hats[i] ) {
282            SDL_PrivateJoystickHat(joystick, i, pos);
283        }
284    }
285
286    for(i = 0; i < joystick->nballs; i++, j++)
287    {
288        /*  ignore balls right now  */
289    }
290
291    for(i = 0; i < joystick->nbuttons; i++, j++)
292    {
293        ISpElement_GetSimpleState(
294            joystick->hwdata->refs[j],
295            &d);
296        if ( d != joystick->buttons[i] ) {
297            SDL_PrivateJoystickButton(joystick, i, d);
298        }
299    }
300}
301
302/* Function to close a joystick after use */
303void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
304{
305    int index;
306
307    index = joystick->index;
308
309    ISpDevices_Deactivate(
310        1,
311        &SYS_Joysticks[index]);
312}
313
314/* Function to perform any system-specific joystick related cleanup */
315void SDL_SYS_JoystickQuit(void)
316{
317    ISpShutdown();
318}
319
320#endif /* SDL_JOYSTICK_MACOS */
321