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