1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2006 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_BEOS
25
26/* This is the system specific header for the SDL joystick API */
27
28#include <be/support/String.h>
29#include <be/device/Joystick.h>
30
31extern "C" {
32
33#include "SDL_joystick.h"
34#include "../SDL_sysjoystick.h"
35#include "../SDL_joystick_c.h"
36
37
38/* The maximum number of joysticks we'll detect */
39#define MAX_JOYSTICKS	16
40
41/* A list of available joysticks */
42static char *SDL_joyport[MAX_JOYSTICKS];
43static char *SDL_joyname[MAX_JOYSTICKS];
44
45/* The private structure used to keep track of a joystick */
46struct joystick_hwdata {
47	BJoystick *stick;
48	uint8 *new_hats;
49	int16 *new_axes;
50};
51
52/* Function to scan the system for joysticks.
53 * This function should set SDL_numjoysticks to the number of available
54 * joysticks.  Joystick 0 should be the system default joystick.
55 * It should return 0, or -1 on an unrecoverable fatal error.
56 */
57int SDL_SYS_JoystickInit(void)
58{
59	BJoystick joystick;
60	int numjoysticks;
61	int i;
62	int32 nports;
63	char name[B_OS_NAME_LENGTH];
64
65	/* Search for attached joysticks */
66	nports = joystick.CountDevices();
67	numjoysticks = 0;
68	SDL_memset(SDL_joyport, 0, (sizeof SDL_joyport));
69	SDL_memset(SDL_joyname, 0, (sizeof SDL_joyname));
70	for ( i=0; (SDL_numjoysticks < MAX_JOYSTICKS) && (i < nports); ++i ) {
71		if ( joystick.GetDeviceName(i, name) == B_OK ) {
72			if ( joystick.Open(name) != B_ERROR ) {
73				BString stick_name;
74				joystick.GetControllerName(&stick_name);
75				SDL_joyport[numjoysticks] = strdup(name);
76				SDL_joyname[numjoysticks] =
77					           strdup(stick_name.String());
78				numjoysticks++;
79				joystick.Close();
80			}
81		}
82	}
83	return(numjoysticks);
84}
85
86/* Function to get the device-dependent name of a joystick */
87const char *SDL_SYS_JoystickName(int index)
88{
89	return SDL_joyname[index];
90}
91
92/* Function to open a joystick for use.
93   The joystick to open is specified by the index field of the joystick.
94   This should fill the nbuttons and naxes fields of the joystick structure.
95   It returns 0, or -1 if there is an error.
96 */
97int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
98{
99	BJoystick *stick;
100
101	/* Create the joystick data structure */
102	joystick->hwdata = (struct joystick_hwdata *)
103	                   SDL_malloc(sizeof(*joystick->hwdata));
104	if ( joystick->hwdata == NULL ) {
105		SDL_OutOfMemory();
106		return(-1);
107	}
108	SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
109	stick = new BJoystick;
110	joystick->hwdata->stick = stick;
111
112	/* Open the requested joystick for use */
113	if ( stick->Open(SDL_joyport[joystick->index]) == B_ERROR ) {
114		SDL_SetError("Unable to open joystick");
115		SDL_SYS_JoystickClose(joystick);
116		return(-1);
117	}
118
119	/* Set the joystick to calibrated mode */
120	stick->EnableCalibration();
121
122	/* Get the number of buttons, hats, and axes on the joystick */
123	joystick->nbuttons = stick->CountButtons();
124	joystick->naxes = stick->CountAxes();
125	joystick->nhats = stick->CountHats();
126
127	joystick->hwdata->new_axes = (int16 *)
128	                  SDL_malloc(joystick->naxes*sizeof(int16));
129	joystick->hwdata->new_hats = (uint8 *)
130	                  SDL_malloc(joystick->nhats*sizeof(uint8));
131	if ( ! joystick->hwdata->new_hats || ! joystick->hwdata->new_axes ) {
132		SDL_OutOfMemory();
133		SDL_SYS_JoystickClose(joystick);
134		return(-1);
135	}
136
137	/* We're done! */
138	return(0);
139}
140
141/* Function to update the state of a joystick - called as a device poll.
142 * This function shouldn't update the joystick structure directly,
143 * but instead should call SDL_PrivateJoystick*() to deliver events
144 * and update joystick device state.
145 */
146void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
147{
148	static const Uint8 hat_map[9] = {
149             SDL_HAT_CENTERED,
150             SDL_HAT_UP,
151             SDL_HAT_RIGHTUP,
152             SDL_HAT_RIGHT,
153             SDL_HAT_RIGHTDOWN,
154             SDL_HAT_DOWN,
155             SDL_HAT_LEFTDOWN,
156             SDL_HAT_LEFT,
157             SDL_HAT_LEFTUP
158	};
159	const int JITTER = (32768/10);	/* 10% jitter threshold (ok?) */
160
161	BJoystick *stick;
162	int i, change;
163	int16 *axes;
164	uint8 *hats;
165	uint32 buttons;
166
167	/* Set up data pointers */
168	stick = joystick->hwdata->stick;
169	axes = joystick->hwdata->new_axes;
170	hats = joystick->hwdata->new_hats;
171
172	/* Get the new joystick state */
173	stick->Update();
174	stick->GetAxisValues(axes);
175	stick->GetHatValues(hats);
176	buttons = stick->ButtonValues();
177
178	/* Generate axis motion events */
179	for ( i=0; i<joystick->naxes; ++i ) {
180		change = ((int32)axes[i] - joystick->axes[i]);
181		if ( (change > JITTER) || (change < -JITTER) ) {
182			SDL_PrivateJoystickAxis(joystick, i, axes[i]);
183		}
184	}
185
186	/* Generate hat change events */
187	for ( i=0; i<joystick->nhats; ++i ) {
188		if ( hats[i] != joystick->hats[i] ) {
189			SDL_PrivateJoystickHat(joystick, i, hat_map[hats[i]]);
190		}
191	}
192
193	/* Generate button events */
194	for ( i=0; i<joystick->nbuttons; ++i ) {
195		if ( (buttons&0x01) != joystick->buttons[i] ) {
196			SDL_PrivateJoystickButton(joystick, i, (buttons&0x01));
197		}
198		buttons >>= 1;
199	}
200}
201
202/* Function to close a joystick after use */
203void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
204{
205	if ( joystick->hwdata ) {
206		joystick->hwdata->stick->Close();
207		delete joystick->hwdata->stick;
208		if ( joystick->hwdata->new_hats ) {
209			SDL_free(joystick->hwdata->new_hats);
210		}
211		if ( joystick->hwdata->new_axes ) {
212			SDL_free(joystick->hwdata->new_axes);
213		}
214		SDL_free(joystick->hwdata);
215		joystick->hwdata = NULL;
216	}
217}
218
219/* Function to perform any system-specific joystick related cleanup */
220void SDL_SYS_JoystickQuit(void)
221{
222	int i;
223
224	for ( i=0; SDL_joyport[i]; ++i ) {
225		SDL_free(SDL_joyport[i]);
226	}
227	SDL_joyport[0] = NULL;
228
229	for ( i=0; SDL_joyname[i]; ++i ) {
230		SDL_free(SDL_joyname[i]);
231	}
232	SDL_joyname[0] = NULL;
233}
234
235}; // extern "C"
236
237#endif /* SDL_JOYSTICK_BEOS */
238