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