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