changed event filter to not set as SDL event filter, but call it manually
[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 Joystick(int player_nr)
163 {
164   int joystick_fd = joystick.fd[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 (joystick.status != JOYSTICK_ACTIVATED)
171     return JOY_NO_ACTION;
172
173   if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
174     return JOY_NO_ACTION;
175
176   if (!ReadJoystick(joystick_fd, &js_x, &js_y, &js_b1, &js_b2))
177   {
178     Error(ERR_WARN, "cannot read joystick device '%s'",
179           setup.input[player_nr].joy.device_name);
180
181     joystick.status = JOYSTICK_NOT_AVAILABLE;
182     return JOY_NO_ACTION;
183   }
184
185   left  = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
186                                   setup.input[player_nr].joy.xleft,  js_x);
187   right = JoystickPositionPercent(setup.input[player_nr].joy.xmiddle,
188                                   setup.input[player_nr].joy.xright, js_x);
189   up    = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
190                                   setup.input[player_nr].joy.yupper, js_y);
191   down  = JoystickPositionPercent(setup.input[player_nr].joy.ymiddle,
192                                   setup.input[player_nr].joy.ylower, js_y);
193
194   if (left > JOYSTICK_PERCENT)
195     result |= JOY_LEFT;
196   else if (right > JOYSTICK_PERCENT)
197     result |= JOY_RIGHT;
198   if (up > JOYSTICK_PERCENT)
199     result |= JOY_UP;
200   else if (down > JOYSTICK_PERCENT)
201     result |= JOY_DOWN;
202
203   if (js_b1)
204     result |= JOY_BUTTON_1;
205   if (js_b2)
206     result |= JOY_BUTTON_2;
207
208   return result;
209 }
210
211 int JoystickButton(int player_nr)
212 {
213   static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 };
214   int joy_button = (Joystick(player_nr) & JOY_BUTTON);
215   int result;
216
217   if (joy_button)
218   {
219     if (last_joy_button[player_nr])
220       result = JOY_BUTTON_PRESSED;
221     else
222       result = JOY_BUTTON_NEW_PRESSED;
223   }
224   else
225   {
226     if (last_joy_button[player_nr])
227       result = JOY_BUTTON_NEW_RELEASED;
228     else
229       result = JOY_BUTTON_NOT_PRESSED;
230   }
231
232   last_joy_button[player_nr] = joy_button;
233   return result;
234 }
235
236 int AnyJoystick()
237 {
238   int i;
239   int result = 0;
240
241   for (i = 0; i < MAX_PLAYERS; i++)
242     result |= Joystick(i);
243
244   return result;
245 }
246
247 int AnyJoystickButton()
248 {
249   int i;
250   int result = JOY_BUTTON_NOT_PRESSED;
251
252   for (i = 0; i < MAX_PLAYERS; i++)
253   {
254     result = JoystickButton(i);
255     if (result != JOY_BUTTON_NOT_PRESSED)
256       break;
257   }
258
259   return result;
260 }
261
262 void DeactivateJoystick()
263 {
264   /* Temporarily deactivate joystick. This is needed for calibration
265      screens, where the player has to select a joystick device that
266      should be calibrated. If there is a totally uncalibrated joystick
267      active, it may be impossible (due to messed up input from joystick)
268      to select the joystick device to calibrate even when trying to use
269      the mouse or keyboard to select the device. */
270
271   if (joystick.status & JOYSTICK_AVAILABLE)
272     joystick.status &= ~JOYSTICK_ACTIVE;
273 }
274
275 void ActivateJoystick()
276 {
277   /* reactivate temporarily deactivated joystick */
278
279   if (joystick.status & JOYSTICK_AVAILABLE)
280     joystick.status |= JOYSTICK_ACTIVE;
281 }