fixed joystick naming convention from file descriptor to joystick number
[rocksndiamonds.git] / src / libgame / joystick.c
1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // joystick.c
10 // ============================================================================
11
12 #if defined(PLATFORM_FREEBSD)
13 #include <machine/joystick.h>
14 #endif
15
16 #include "joystick.h"
17 #include "misc.h"
18
19
20 /* ========================================================================= */
21 /* platform independent joystick functions                                   */
22 /* ========================================================================= */
23
24 #define TRANSLATE_JOYSYMBOL_TO_JOYNAME  0
25 #define TRANSLATE_JOYNAME_TO_JOYSYMBOL  1
26
27 void translate_joyname(int *joysymbol, char **name, int mode)
28 {
29   static struct
30   {
31     int joysymbol;
32     char *name;
33   } translate_joy[] =
34   {
35     { JOY_LEFT,         "joystick_left" },
36     { JOY_RIGHT,        "joystick_right" },
37     { JOY_UP,           "joystick_up" },
38     { JOY_DOWN,         "joystick_down" },
39     { JOY_BUTTON_1,     "joystick_button_1" },
40     { JOY_BUTTON_2,     "joystick_button_2" },
41   };
42
43   int i;
44
45   if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME)
46   {
47     *name = "[undefined]";
48
49     for (i = 0; i < 6; i++)
50     {
51       if (*joysymbol == translate_joy[i].joysymbol)
52       {
53         *name = translate_joy[i].name;
54         break;
55       }
56     }
57   }
58   else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL)
59   {
60     *joysymbol = 0;
61
62     for (i = 0; i < 6; i++)
63     {
64       if (strEqual(*name, translate_joy[i].name))
65       {
66         *joysymbol = translate_joy[i].joysymbol;
67         break;
68       }
69     }
70   }
71 }
72
73 char *getJoyNameFromJoySymbol(int joysymbol)
74 {
75   char *name;
76
77   translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME);
78   return name;
79 }
80
81 int getJoySymbolFromJoyName(char *name)
82 {
83   int joysymbol;
84
85   translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL);
86   return joysymbol;
87 }
88
89 int getJoystickNrFromDeviceName(char *device_name)
90 {
91   char c;
92   int joystick_nr = 0;
93
94   if (device_name == NULL || device_name[0] == '\0')
95     return 0;
96
97   c = device_name[strlen(device_name) - 1];
98
99   if (c >= '0' && c <= '9')
100     joystick_nr = (int)(c - '0');
101
102   if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS)
103     joystick_nr = 0;
104
105   return joystick_nr;
106 }
107
108 char *getDeviceNameFromJoystickNr(int joystick_nr)
109 {
110   static char *joystick_device_name[MAX_PLAYERS] =
111   {
112     DEV_JOYSTICK_0,
113     DEV_JOYSTICK_1,
114     DEV_JOYSTICK_2,
115     DEV_JOYSTICK_3
116   };
117
118   return (joystick_nr >= 0 && joystick_nr <= 3 ?
119           joystick_device_name[joystick_nr] : "");
120 }
121
122 static int JoystickPositionPercent(int center, int border, int actual)
123 {
124   int range, position;
125   int percent;
126
127   if (border < center && actual > center)
128     return 0;
129   if (border > center && actual < center)
130     return 0;
131
132   range = ABS(border - center);
133   position = ABS(actual - center);
134
135   percent = (int)(position * 100 / range);
136
137   if (percent > 100)
138     percent = 100;
139
140   return percent;
141 }
142
143 void CheckJoystickData()
144 {
145   int i;
146   int distance = 100;
147
148   for (i = 0; i < MAX_PLAYERS; i++)
149   {
150     if (setup.input[i].joy.xleft >= setup.input[i].joy.xmiddle)
151       setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance;
152     if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle)
153       setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance;
154
155     if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle)
156       setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance;
157     if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle)
158       setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance;
159   }
160 }
161
162 int JoystickExt(int player_nr, boolean use_as_joystick_nr)
163 {
164   int joystick_nr = joystick.nr[player_nr];
165   int js_x, js_y;
166   boolean js_b1, js_b2;
167   int left, right, up, down;
168   int result = JOY_NO_ACTION;
169
170   if (use_as_joystick_nr)
171     joystick_nr = player_nr;
172
173   if (joystick.status != JOYSTICK_ACTIVATED)
174     return JOY_NO_ACTION;
175
176   if (joystick_nr < 0)
177     return JOY_NO_ACTION;
178
179   if (!ReadJoystick(joystick_nr, &js_x, &js_y, &js_b1, &js_b2))
180   {
181     Error(ERR_WARN, "cannot read joystick device '%s'",
182           setup.input[player_nr].joy.device_name);
183
184     joystick.status = JOYSTICK_NOT_AVAILABLE;
185     return JOY_NO_ACTION;
186   }
187
188   left  = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
189                                   setup.input[player_nr].joy.xleft,  js_x);
190   right = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
191                                   setup.input[player_nr].joy.xright, js_x);
192   up    = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
193                                   setup.input[player_nr].joy.yupper, js_y);
194   down  = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
195                                   setup.input[player_nr].joy.ylower, js_y);
196
197   if (left > JOYSTICK_PERCENT)
198     result |= JOY_LEFT;
199   else if (right > JOYSTICK_PERCENT)
200     result |= JOY_RIGHT;
201   if (up > JOYSTICK_PERCENT)
202     result |= JOY_UP;
203   else if (down > JOYSTICK_PERCENT)
204     result |= JOY_DOWN;
205
206   if (js_b1)
207     result |= JOY_BUTTON_1;
208   if (js_b2)
209     result |= JOY_BUTTON_2;
210
211   return result;
212 }
213
214 int Joystick(int player_nr)
215 {
216   return JoystickExt(player_nr, FALSE);
217 }
218
219 int JoystickButtonExt(int player_nr, boolean use_as_joystick_nr)
220 {
221   static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 };
222   int joy_button = (JoystickExt(player_nr, use_as_joystick_nr) & JOY_BUTTON);
223   int result;
224
225   if (joy_button)
226   {
227     if (last_joy_button[player_nr])
228       result = JOY_BUTTON_PRESSED;
229     else
230       result = JOY_BUTTON_NEW_PRESSED;
231   }
232   else
233   {
234     if (last_joy_button[player_nr])
235       result = JOY_BUTTON_NEW_RELEASED;
236     else
237       result = JOY_BUTTON_NOT_PRESSED;
238   }
239
240   last_joy_button[player_nr] = joy_button;
241   return result;
242 }
243
244 int JoystickButton(int player_nr)
245 {
246   return JoystickButtonExt(player_nr, FALSE);
247 }
248
249 int AnyJoystick()
250 {
251   int i;
252   int result = 0;
253
254   for (i = 0; i < MAX_PLAYERS; i++)
255     result |= JoystickExt(i, TRUE);
256
257   return result;
258 }
259
260 int AnyJoystickButton()
261 {
262   int i;
263   int result = JOY_BUTTON_NOT_PRESSED;
264
265   for (i = 0; i < MAX_PLAYERS; i++)
266   {
267     result = JoystickButtonExt(i, TRUE);
268     if (result != JOY_BUTTON_NOT_PRESSED)
269       break;
270   }
271
272   return result;
273 }
274
275 void DeactivateJoystick()
276 {
277   /* Temporarily deactivate joystick. This is needed for calibration
278      screens, where the player has to select a joystick device that
279      should be calibrated. If there is a totally uncalibrated joystick
280      active, it may be impossible (due to messed up input from joystick)
281      to select the joystick device to calibrate even when trying to use
282      the mouse or keyboard to select the device. */
283
284   if (joystick.status & JOYSTICK_AVAILABLE)
285     joystick.status &= ~JOYSTICK_ACTIVE;
286 }
287
288 void ActivateJoystick()
289 {
290   /* reactivate temporarily deactivated joystick */
291
292   if (joystick.status & JOYSTICK_AVAILABLE)
293     joystick.status |= JOYSTICK_ACTIVE;
294 }