added hat support for sdl joysticks
[btb/d2x.git] / arch / sdl / joy.c
1 /* $Id: joy.c,v 1.10 2003-03-27 02:26:02 btb Exp $ */
2 /*
3  *
4  * SDL joystick support
5  *
6  *
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <conf.h>
11 #endif
12
13 #include <string.h>   // for memset
14 #include <SDL.h>
15
16 #include "joy.h"
17 #include "error.h"
18 #include "timer.h"
19 #include "console.h"
20 #include "event.h"
21
22 #define MAX_JOYSTICKS 16
23 #define MAX_AXES 32
24
25 #define MAX_AXES_PER_JOYSTICK 8
26 #define MAX_BUTTONS_PER_JOYSTICK 16
27 #define MAX_HATS_PER_JOYSTICK 4
28
29
30 char joy_present = 0;
31 int num_joysticks = 0;
32
33 int joy_deadzone = 0;
34
35 struct joybutton {
36         int state;
37         int last_state;
38         fix time_went_down;
39         int num_downs;
40         int num_ups;
41 };
42
43 struct joyaxis {
44         int             value;
45         int             min_val;
46         int             center_val;
47         int             max_val;
48 };
49
50 static struct joyinfo {
51         int n_axes;
52         int n_buttons;
53         struct joyaxis axes[MAX_AXES];
54         struct joybutton buttons[MAX_BUTTONS+(MAX_HATS_PER_JOYSTICK*4)];
55 } Joystick;
56
57 static struct {
58         SDL_Joystick *handle;
59         int n_axes;
60         int n_buttons;
61         int n_hats;
62         int hat_map[MAX_HATS_PER_JOYSTICK];  //Note: Descent expects hats to be buttons, so these are indices into Joystick.buttons
63         int axis_map[MAX_AXES_PER_JOYSTICK];
64         int button_map[MAX_BUTTONS_PER_JOYSTICK];
65 } SDL_Joysticks[MAX_JOYSTICKS];
66
67 void joy_button_handler(SDL_JoyButtonEvent *jbe)
68 {
69         int button;
70
71         button = SDL_Joysticks[jbe->which].button_map[jbe->button];
72
73         Joystick.buttons[button].state = jbe->state;
74
75         switch (jbe->type) {
76         case SDL_JOYBUTTONDOWN:
77                 Joystick.buttons[button].time_went_down
78                         = timer_get_fixed_seconds();
79                 Joystick.buttons[button].num_downs++;
80                 break;
81         case SDL_JOYBUTTONUP:
82                 Joystick.buttons[button].num_ups++;
83                 break;
84         }
85 }
86
87 void joy_hat_handler(SDL_JoyHatEvent *jhe)
88 {
89         int hat = SDL_Joysticks[jhe->which].hat_map[jhe->hat];
90         int hbi;
91
92         //Save last state of the hat-button
93         Joystick.buttons[hat  ].last_state = Joystick.buttons[hat  ].state;
94         Joystick.buttons[hat+1].last_state = Joystick.buttons[hat+1].state;
95         Joystick.buttons[hat+2].last_state = Joystick.buttons[hat+2].state;
96         Joystick.buttons[hat+3].last_state = Joystick.buttons[hat+3].state;
97
98         //get current state of the hat-button
99         Joystick.buttons[hat  ].state = ((jhe->value & SDL_HAT_UP)>0);
100         Joystick.buttons[hat+1].state = ((jhe->value & SDL_HAT_RIGHT)>0);
101         Joystick.buttons[hat+2].state = ((jhe->value & SDL_HAT_DOWN)>0);
102         Joystick.buttons[hat+3].state = ((jhe->value & SDL_HAT_LEFT)>0);
103
104         //determine if a hat-button up or down event based on state and last_state
105         for(hbi=0;hbi<4;hbi++)
106         {
107                 if(     !Joystick.buttons[hat+hbi].last_state && Joystick.buttons[hat+hbi].state) //last_state up, current state down
108                 {
109                         Joystick.buttons[hat+hbi].time_went_down
110                                 = timer_get_fixed_seconds();
111                         Joystick.buttons[hat+hbi].num_downs++;
112                 }
113                 else if(Joystick.buttons[hat+hbi].last_state && !Joystick.buttons[hat+hbi].state)  //last_state down, current state up
114                 {
115                         Joystick.buttons[hat+hbi].num_ups ++;
116                 }
117         }
118 }
119
120 void joy_axis_handler(SDL_JoyAxisEvent *jae)
121 {
122         int axis;
123
124         axis = SDL_Joysticks[jae->which].axis_map[jae->axis];
125         
126         Joystick.axes[axis].value = jae->value;
127 }
128
129
130 /* ----------------------------------------------- */
131
132 int joy_init()
133 {
134         int i,j,n;
135
136         if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
137                 con_printf(CON_VERBOSE, "sdl-joystick: initialisation failed: %s.",SDL_GetError());
138                 return 0;
139         }
140
141         memset(&Joystick,0,sizeof(Joystick));
142
143         n = SDL_NumJoysticks();
144
145         con_printf(CON_VERBOSE, "sdl-joystick: found %d joysticks\n", n);
146         for (i = 0; i < n; i++) {
147                 con_printf(CON_VERBOSE, "sdl-joystick %d: %s\n", i, SDL_JoystickName(i));
148                 SDL_Joysticks[num_joysticks].handle = SDL_JoystickOpen(i);
149                 if (SDL_Joysticks[num_joysticks].handle) {
150                         joy_present = 1;
151
152                         SDL_Joysticks[num_joysticks].n_axes
153                                 = SDL_JoystickNumAxes(SDL_Joysticks[num_joysticks].handle);
154                         if(SDL_Joysticks[num_joysticks].n_axes > MAX_AXES_PER_JOYSTICK)
155                         {
156                                 Warning("sdl-joystick: found %d axes, only %d supported.  Game may be unstable.\n", SDL_Joysticks[num_joysticks].n_axes, MAX_AXES_PER_JOYSTICK);
157                                 SDL_Joysticks[num_joysticks].n_axes = MAX_AXES_PER_JOYSTICK;
158                         }
159
160                         SDL_Joysticks[num_joysticks].n_buttons
161                                 = SDL_JoystickNumButtons(SDL_Joysticks[num_joysticks].handle);
162                         if(SDL_Joysticks[num_joysticks].n_buttons > MAX_BUTTONS_PER_JOYSTICK)
163                         {
164                                 Warning("sdl-joystick: found %d buttons, only %d supported.  Game may be unstable.\n", SDL_Joysticks[num_joysticks].n_buttons, MAX_BUTTONS_PER_JOYSTICK);
165                                 SDL_Joysticks[num_joysticks].n_buttons = MAX_BUTTONS_PER_JOYSTICK;
166                         }
167
168                         SDL_Joysticks[num_joysticks].n_hats
169                                 = SDL_JoystickNumHats(SDL_Joysticks[num_joysticks].handle);
170                         if(SDL_Joysticks[num_joysticks].n_hats > MAX_HATS_PER_JOYSTICK)
171                         {
172                                 Warning("sdl-joystick: found %d hats, only %d supported.  Game may be unstable.\n", SDL_Joysticks[num_joysticks].n_hats, MAX_HATS_PER_JOYSTICK);
173                                 SDL_Joysticks[num_joysticks].n_hats = MAX_HATS_PER_JOYSTICK;
174                         }
175
176                         con_printf(CON_VERBOSE, "sdl-joystick: %d axes\n", SDL_Joysticks[num_joysticks].n_axes);
177                         con_printf(CON_VERBOSE, "sdl-joystick: %d buttons\n", SDL_Joysticks[num_joysticks].n_buttons);
178                         con_printf(CON_VERBOSE, "sdl-joystick: %d hats\n", SDL_Joysticks[num_joysticks].n_hats);
179
180                         for (j=0; j < SDL_Joysticks[num_joysticks].n_axes; j++)
181                                 SDL_Joysticks[num_joysticks].axis_map[j] = Joystick.n_axes++;
182                         for (j=0; j < SDL_Joysticks[num_joysticks].n_buttons; j++)
183                                 SDL_Joysticks[num_joysticks].button_map[j] = Joystick.n_buttons++;
184                         for (j=0; j < SDL_Joysticks[num_joysticks].n_hats; j++)
185                         {
186                                 SDL_Joysticks[num_joysticks].hat_map[j] = Joystick.n_buttons;
187                                 Joystick.n_buttons += 4; //a hat counts as four buttons
188                         }
189
190                         num_joysticks++;
191                 }
192                 else
193                         con_printf(CON_VERBOSE, "sdl-joystick: initialization failed!\n");
194                 con_printf(CON_VERBOSE, "sdl-joystick: %d axes (total)\n", Joystick.n_axes);
195                 con_printf(CON_VERBOSE, "sdl-joystick: %d buttons (total)\n", Joystick.n_buttons);
196         }
197                 
198         return joy_present;
199 }
200
201 void joy_close()
202 {
203         while (num_joysticks)
204                 SDL_JoystickClose(SDL_Joysticks[--num_joysticks].handle);
205 }
206
207 void joy_get_pos(int *x, int *y)
208 {
209         int axis[MAX_AXES];
210
211         if (!num_joysticks) {
212                 *x=*y=0;
213                 return;
214         }
215
216         joystick_read_raw_axis (JOY_ALL_AXIS, axis);
217
218         *x = joy_get_scaled_reading( axis[0], 0 );
219         *y = joy_get_scaled_reading( axis[1], 1 );
220 }
221
222 int joy_get_btns()
223 {
224 #if 0 // This is never used?
225         int i, buttons = 0;
226         for (i=0; i++; i<buttons) {
227                 switch (Joystick.buttons[i].state) {
228                 case SDL_PRESSED:
229                         buttons |= 1<<i;
230                         break;
231                 case SDL_RELEASED:
232                         break;
233                 }
234         }
235         return buttons;
236 #else
237         return 0;
238 #endif
239 }
240
241 int joy_get_button_down_cnt( int btn )
242 {
243         int num_downs;
244
245         if (!num_joysticks)
246                 return 0;
247
248         event_poll();
249
250         num_downs = Joystick.buttons[btn].num_downs;
251         Joystick.buttons[btn].num_downs = 0;
252
253         return num_downs;
254 }
255
256 fix joy_get_button_down_time(int btn)
257 {
258         fix time = F0_0;
259
260         if (!num_joysticks)
261                 return 0;
262
263         event_poll();
264
265         switch (Joystick.buttons[btn].state) {
266         case SDL_PRESSED:
267                 time = timer_get_fixed_seconds() - Joystick.buttons[btn].time_went_down;
268                 Joystick.buttons[btn].time_went_down = timer_get_fixed_seconds();
269                 break;
270         case SDL_RELEASED:
271                 time = 0;
272                 break;
273         }
274
275         return time;
276 }
277
278 ubyte joystick_read_raw_axis( ubyte mask, int * axis )
279 {
280         int i;
281         
282         if (!num_joysticks)
283                 return 0;
284
285         event_poll();
286
287         for (i = 0; i <= JOY_NUM_AXES; i++) {
288                 axis[i] = Joystick.axes[i].value;
289         }
290
291         return 0;
292 }
293
294 void joy_flush()
295 {
296         int i;
297
298         if (!num_joysticks)
299                 return;
300
301         for (i = 0; i < Joystick.n_buttons; i++) {
302                 Joystick.buttons[i].time_went_down = 0;
303                 Joystick.buttons[i].num_downs = 0;
304         }
305         
306 }
307
308 int joy_get_button_state( int btn )
309 {
310         if (!num_joysticks)
311                 return 0;
312
313         if(btn >= Joystick.n_buttons)
314                 return 0;
315
316         event_poll();
317
318         return Joystick.buttons[btn].state;
319 }
320
321 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
322 {
323         int i;
324
325         for (i = 0; i < JOY_NUM_AXES; i++) {
326                 axis_center[i] = Joystick.axes[i].center_val;
327                 axis_min[i] = Joystick.axes[i].min_val;
328                 axis_max[i] = Joystick.axes[i].max_val;
329         }
330 }
331
332 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
333 {
334         int i;
335
336         for (i = 0; i < JOY_NUM_AXES; i++) {
337                 Joystick.axes[i].center_val = axis_center[i];
338                 Joystick.axes[i].min_val = axis_min[i];
339                 Joystick.axes[i].max_val = axis_max[i];
340         }
341 }
342
343 int joy_get_scaled_reading( int raw, int axis_num )
344 {
345 #if 1
346         return raw/256;
347 #else
348         int d, x;
349
350         raw -= Joystick.axes[axis_num].center_val;
351         
352         if (raw < 0)
353                 d = Joystick.axes[axis_num].center_val - Joystick.axes[axis_num].min_val;
354         else if (raw > 0)
355                 d = Joystick.axes[axis_num].max_val - Joystick.axes[axis_num].center_val;
356         else
357                 d = 0;
358         
359         if (d)
360                 x = ((raw << 7) / d);
361         else
362                 x = 0;
363         
364         if ( x < -128 )
365                 x = -128;
366         if ( x > 127 )
367                 x = 127;
368         
369         d =  (joy_deadzone) * 6;
370         if ((x > (-1*d)) && (x < d))
371                 x = 0;
372         
373         return x;
374 #endif
375 }
376
377 void joy_set_slow_reading( int flag )
378 {
379 }