b286de23732f769a220d7775d45b2efbfaadbd63
[rocksndiamonds.git] / src / libgame / joystick.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * joystick.c                                               *
12 ***********************************************************/
13
14 #if defined(PLATFORM_FREEBSD)
15 #include <machine/joystick.h>
16 #endif
17
18 #include "joystick.h"
19 #include "misc.h"
20
21
22 /* ========================================================================= */
23 /* platform dependent joystick functions                                     */
24 /* ========================================================================= */
25
26 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
27 void UnixInitJoysticks()
28 {
29   static boolean unix_joystick_subsystem_initialized = FALSE;
30   boolean print_warning = !unix_joystick_subsystem_initialized;
31   int i;
32
33   for (i = 0; i < MAX_PLAYERS; i++)
34   {
35     char *device_name = setup.input[i].joy.device_name;
36
37     /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
38     if (joystick.fd[i] != -1)
39     {
40       close(joystick.fd[i]);
41       joystick.fd[i] = -1;
42     }
43
44     if (!setup.input[i].use_joystick)
45       continue;
46
47     if (access(device_name, R_OK) != 0)
48     {
49       if (print_warning)
50         Error(ERR_WARN, "cannot access joystick device '%s'", device_name);
51
52       continue;
53     }
54
55     if ((joystick.fd[i] = open(device_name, O_RDONLY)) < 0)
56     {
57       if (print_warning)
58         Error(ERR_WARN, "cannot open joystick device '%s'", device_name);
59
60       continue;
61     }
62
63     joystick.status = JOYSTICK_ACTIVATED;
64   }
65
66   unix_joystick_subsystem_initialized = TRUE;
67 }
68
69 boolean UnixReadJoystick(int fd, int *x, int *y, boolean *b1, boolean *b2)
70 {
71 #if defined(PLATFORM_FREEBSD)
72   struct joystick joy_ctrl;
73 #else
74   struct joystick_control
75   {
76     int buttons;
77     int x;
78     int y;
79   } joy_ctrl;
80 #endif
81
82   if (read(fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
83     return FALSE;
84
85   if (x != NULL)
86     *x = joy_ctrl.x;
87   if (y != NULL)
88     *y = joy_ctrl.y;
89
90 #if defined(PLATFORM_FREEBSD)
91   if (b1 != NULL)
92     *b1 = joy_ctrl.b1;
93   if (b2 != NULL)
94     *b2 = joy_ctrl.b2;
95 #else
96   if (b1 != NULL)
97     *b1 = joy_ctrl.buttons & 1;
98   if (b2 != NULL)
99     *b2 = joy_ctrl.buttons & 2;
100 #endif
101
102   return TRUE;
103 }
104 #endif /* PLATFORM_UNIX && !TARGET_SDL */
105
106
107 /* ========================================================================= */
108 /* platform independent joystick functions                                   */
109 /* ========================================================================= */
110
111 #define TRANSLATE_JOYSYMBOL_TO_JOYNAME  0
112 #define TRANSLATE_JOYNAME_TO_JOYSYMBOL  1
113
114 void translate_joyname(int *joysymbol, char **name, int mode)
115 {
116   static struct
117   {
118     int joysymbol;
119     char *name;
120   } translate_joy[] =
121   {
122     { JOY_LEFT,         "joystick_left" },
123     { JOY_RIGHT,        "joystick_right" },
124     { JOY_UP,           "joystick_up" },
125     { JOY_DOWN,         "joystick_down" },
126     { JOY_BUTTON_1,     "joystick_button_1" },
127     { JOY_BUTTON_2,     "joystick_button_2" },
128   };
129
130   int i;
131
132   if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME)
133   {
134     *name = "[undefined]";
135
136     for (i = 0; i < 6; i++)
137     {
138       if (*joysymbol == translate_joy[i].joysymbol)
139       {
140         *name = translate_joy[i].name;
141         break;
142       }
143     }
144   }
145   else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL)
146   {
147     *joysymbol = 0;
148
149     for (i = 0; i < 6; i++)
150     {
151       if (strEqual(*name, translate_joy[i].name))
152       {
153         *joysymbol = translate_joy[i].joysymbol;
154         break;
155       }
156     }
157   }
158 }
159
160 char *getJoyNameFromJoySymbol(int joysymbol)
161 {
162   char *name;
163
164   translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME);
165   return name;
166 }
167
168 int getJoySymbolFromJoyName(char *name)
169 {
170   int joysymbol;
171
172   translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL);
173   return joysymbol;
174 }
175
176 int getJoystickNrFromDeviceName(char *device_name)
177 {
178   char c;
179   int joystick_nr = 0;
180
181   if (device_name == NULL || device_name[0] == '\0')
182     return 0;
183
184   c = device_name[strlen(device_name) - 1];
185
186   if (c >= '0' && c <= '9')
187     joystick_nr = (int)(c - '0');
188
189   if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS)
190     joystick_nr = 0;
191
192   return joystick_nr;
193 }
194
195 char *getDeviceNameFromJoystickNr(int joystick_nr)
196 {
197   static char *joystick_device_name[MAX_PLAYERS] =
198   {
199     DEV_JOYSTICK_0,
200     DEV_JOYSTICK_1,
201     DEV_JOYSTICK_2,
202     DEV_JOYSTICK_3
203   };
204
205   return (joystick_nr >= 0 && joystick_nr <= 3 ?
206           joystick_device_name[joystick_nr] : "");
207 }
208
209 static int JoystickPositionPercent(int center, int border, int actual)
210 {
211   long range, position;
212   int percent;
213
214   if (border < center && actual > center)
215     return 0;
216   if (border > center && actual < center)
217     return 0;
218
219   range = ABS(border - center);
220   position = ABS(actual - center);
221
222   percent = (int)(position * 100 / range);
223
224   if (percent > 100)
225     percent = 100;
226
227   return percent;
228 }
229
230 void CheckJoystickData()
231 {
232   int i;
233   int distance = 100;
234
235   for (i = 0; i < MAX_PLAYERS; i++)
236   {
237     if (setup.input[i].joy.xleft >= setup.input[i].joy.xmiddle)
238       setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance;
239     if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle)
240       setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance;
241
242     if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle)
243       setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance;
244     if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle)
245       setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance;
246   }
247 }
248
249 int Joystick(int player_nr)
250 {
251   int joystick_fd = joystick.fd[player_nr];
252   int js_x, js_y;
253   boolean js_b1, js_b2;
254   int left, right, up, down;
255   int result = JOY_NO_ACTION;
256
257   if (joystick.status != JOYSTICK_ACTIVATED)
258     return JOY_NO_ACTION;
259
260   if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
261     return JOY_NO_ACTION;
262
263   if (!ReadJoystick(joystick_fd, &js_x, &js_y, &js_b1, &js_b2))
264   {
265     Error(ERR_WARN, "cannot read joystick device '%s'",
266           setup.input[player_nr].joy.device_name);
267
268     joystick.status = JOYSTICK_NOT_AVAILABLE;
269     return JOY_NO_ACTION;
270   }
271
272   left  = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
273                                   setup.input[player_nr].joy.xleft,  js_x);
274   right = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
275                                   setup.input[player_nr].joy.xright, js_x);
276   up    = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
277                                   setup.input[player_nr].joy.yupper, js_y);
278   down  = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
279                                   setup.input[player_nr].joy.ylower, js_y);
280
281   if (left > JOYSTICK_PERCENT)
282     result |= JOY_LEFT;
283   else if (right > JOYSTICK_PERCENT)
284     result |= JOY_RIGHT;
285   if (up > JOYSTICK_PERCENT)
286     result |= JOY_UP;
287   else if (down > JOYSTICK_PERCENT)
288     result |= JOY_DOWN;
289
290   if (js_b1)
291     result |= JOY_BUTTON_1;
292   if (js_b2)
293     result |= JOY_BUTTON_2;
294
295   return result;
296 }
297
298 int JoystickButton(int player_nr)
299 {
300   static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 };
301   int joy_button = (Joystick(player_nr) & JOY_BUTTON);
302   int result;
303
304   if (joy_button)
305   {
306     if (last_joy_button[player_nr])
307       result = JOY_BUTTON_PRESSED;
308     else
309       result = JOY_BUTTON_NEW_PRESSED;
310   }
311   else
312   {
313     if (last_joy_button[player_nr])
314       result = JOY_BUTTON_NEW_RELEASED;
315     else
316       result = JOY_BUTTON_NOT_PRESSED;
317   }
318
319   last_joy_button[player_nr] = joy_button;
320   return result;
321 }
322
323 int AnyJoystick()
324 {
325   int i;
326   int result = 0;
327
328   for (i = 0; i < MAX_PLAYERS; i++)
329     result |= Joystick(i);
330
331   return result;
332 }
333
334 int AnyJoystickButton()
335 {
336   int i;
337   int result = JOY_BUTTON_NOT_PRESSED;
338
339   for (i = 0; i < MAX_PLAYERS; i++)
340   {
341     result = JoystickButton(i);
342     if (result != JOY_BUTTON_NOT_PRESSED)
343       break;
344   }
345
346   return result;
347 }
348
349 void DeactivateJoystick()
350 {
351   /* Temporarily deactivate joystick. This is needed for calibration
352      screens, where the player has to select a joystick device that
353      should be calibrated. If there is a totally uncalibrated joystick
354      active, it may be impossible (due to messed up input from joystick)
355      to select the joystick device to calibrate even when trying to use
356      the mouse or keyboard to select the device. */
357
358   if (joystick.status & JOYSTICK_AVAILABLE)
359     joystick.status &= ~JOYSTICK_ACTIVE;
360 }
361
362 void ActivateJoystick()
363 {
364   /* reactivate temporarily deactivated joystick */
365
366   if (joystick.status & JOYSTICK_AVAILABLE)
367     joystick.status |= JOYSTICK_ACTIVE;
368 }