-
Notifications
You must be signed in to change notification settings - Fork 0
/
ifr_joystick.c
302 lines (243 loc) · 6.43 KB
/
ifr_joystick.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/* =================================================== */
/* Intelligent FRAC. (C) 2000 Michael Glickman */
/* --------------------------------------------------- */
/* See LICENSE regarding distribution policy and */
/* conditions of use. */
/* =================================================== */
#include "ifr.h"
#if defined(USE_JOYSTICK) && HAVE_LINUX_JOYSTICK_H
#define JOYSTICK_ON
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/joystick.h>
#define joy_normalize_axis(vcur, vmin, vmax, vnormal) \
if (vcur < vmin) vmin = vcur; \
if (vcur > vmax) vmax = vcur; \
vnormal = (vcur-vmin) * 3 / (vmax-vmin+1)
extern const char *JoyDevName;
static int joy_fd = -1;
#define JoyEventsMax 32767l
#define JoyEventsMin -32767l
#define BUTTONS_TIMEOUT1 100
#define BUTTONS_TIMEOUT2 400
#define AXES_TIMEOUT1 100
#define AXES_TIMEOUT2 150
long JoyXMin, JoyXMax;
long JoyYMin, JoyYMax;
static long joy_x, joy_y;
static int joy_buttons;
static unsigned long btn_next_clock=0, axes_next_clock=0;
#endif
int JoyVersion = 0, JoyEventDriven = 0;
int JoyInUse, JoyClassic;
int JoyButtonCount = 2;
char JoyTypeName[65] = "";
ACTION JoyButtonActions[JOY_MAX_BUTTON_COUNT];
#ifdef JOYSTICK_ON
static int joystick_read(void)
{
#if defined(USE_JOYSTICK_EVENTS) && defined(JS_EVENT_INIT)
if (JoyEventDriven)
{ struct js_event joyEvent;
unsigned short eType, eNumber; /* Actually 8 bits would be enough */
signed short eValue;
int mask;
while(read(joy_fd, &joyEvent, sizeof(struct js_event)) > 0)
{ eType = joyEvent.type;
eNumber = joyEvent.number;
eValue = joyEvent.value;
switch(eType & ~JS_EVENT_INIT)
{ case JS_EVENT_BUTTON:
mask = 1 << eNumber;
if (eValue) joy_buttons |= mask;
else joy_buttons &= ~mask;
break;
case JS_EVENT_AXIS:
if (eNumber == 0) joy_x = eValue;
else
if (eNumber == 1) joy_y = eValue;
break;
}
}
return 1;
}
else
#endif
#ifdef JS_RETURN
{ struct JS_DATA_TYPE js;
if (read (joy_fd, &js, JS_RETURN) != JS_RETURN)
{ close(joy_fd); joy_fd = -1;
return 0;
}
joy_x = js.x;
joy_y = js.y;
joy_buttons = js.buttons;
}
return 1;
#else
return 0;
#endif
}
/* No calibration for event-driven joystick */
static int joystick_calibrate(void)
{
if (JoyEventDriven)
{
JoyXMin = JoyYMin = JoyEventsMin;
JoyXMax = JoyYMax = JoyEventsMax;
}
else
{
JoyXMin = JoyYMin = 0;
if (!joystick_read()) return 0;
JoyXMax = joy_x * 2;
JoyYMax = joy_y * 2;
}
btn_next_clock = start_clock(BUTTONS_TIMEOUT1);
axes_next_clock = start_clock(AXES_TIMEOUT1);
return 1;
}
static ACTION joystick_process_buttons(void)
{ ACTION act = ACT_NONE;
int i;
unsigned long timeout = BUTTONS_TIMEOUT1;
if (!time_up(btn_next_clock)) return ACT_NONE;
for (i=0; i<JoyButtonCount; i++)
{ if (joy_buttons & (1<<i))
{ act = JoyButtonActions[i];
timeout = BUTTONS_TIMEOUT2;
break;
}
}
btn_next_clock = start_clock_from(btn_next_clock, timeout);
return act;
}
static ACTION joystick_process_axes(void)
{ int joy_normal_x, joy_normal_y;
ACTION act;
static const ACTION joy_actions[] =
{ ACT_BACKLEFT, ACT_BACK, ACT_BACKRIGHT,
ACT_LEFT, ACT_NONE, ACT_RIGHT,
ACT_FRONTLEFT, ACT_FRONT, ACT_FRONTRIGHT
};
if (!time_up(axes_next_clock)) return ACT_NONE;
joy_normalize_axis(joy_x, JoyXMin, JoyXMax, joy_normal_x);
joy_normalize_axis(joy_y, JoyYMin, JoyYMax, joy_normal_y);
act = joy_actions[joy_normal_y * 3 + joy_normal_x];
axes_next_clock = start_clock_from(axes_next_clock,
act == ACT_NONE ? AXES_TIMEOUT1 : AXES_TIMEOUT2);
return act;
}
#endif
int joystick_start(void)
{
#ifdef JOYSTICK_ON
if (JoyDevName == NULL || JoyInUse == 0) return 0;
if (joy_fd >= 0) goto JoyCalibrate;
joy_fd = open(JoyDevName, O_RDONLY);
if (joy_fd < 0) return 0;
JoyVersion = 0x000800;
JoyEventDriven = 0;
JoyButtonCount = 2;
strcpy(JoyTypeName, "UNKNOWN");
#ifdef JSIOCGVERSION
if (ioctl(joy_fd, JSIOCGVERSION, &JoyVersion) >= 0)
{
/* This check is inherited from itetris, and
I sincerely don't remember what is special about 1.2.8 */
#ifdef USE_JOYSTICK_EVENTS
JoyEventDriven = (JoyClassic == 0 && JoyVersion >= 0x010208);
if (JoyEventDriven)
fcntl(joy_fd, F_SETFL, O_NONBLOCK);
#endif
#ifdef JSIOCGNAME
if (ioctl(joy_fd, JSIOCGNAME(sizeof(JoyTypeName)), &JoyTypeName) >= 0) ;
JoyTypeName[sizeof(JoyTypeName)-1] = '\0';
#endif
if (JoyVersion <= 0x01020D && strstr(JoyTypeName, "nalog"))
printf ("-----------------------------------------------------\n"
"Warning. This joystick driver might work improperly!\n"
" Use driver 0.8.0, or upgrade to 1.2.14+\n"
"-----------------------------------------------------\n"
);
#ifdef JSIOCGBUTTONS
if (ioctl(joy_fd, JSIOCGBUTTONS, &JoyButtonCount) >= 0)
{ if (JoyButtonCount < 2) JoyButtonCount = 2;
if (JoyButtonCount > JOY_MAX_BUTTON_COUNT)
JoyButtonCount = JOY_MAX_BUTTON_COUNT;
}
#endif
}
#endif /* def JSIOCGVERSION */
JoyCalibrate:
if (joystick_calibrate()) return 1;
close(joy_fd); joy_fd = -1;
#endif // JOYSTICK_ON
return 0;
}
void joystick_stop(void)
{
#ifdef JOYSTICK_ON
if (joy_fd >= 0)
{ close(joy_fd);
joy_fd = -1;
}
#endif
return;
}
int joystick_status(void)
{
#ifdef JOYSTICK_ON
return (joy_fd >= 0);
#else
return -1;
#endif
}
ACTION joystick_interface_routine(PLAYER *player)
{ ACTION act = ACT_NONE;
#ifdef JOYSTICK_ON
if ((player==NULL || player->type==0) && joy_fd >= 0)
{
joystick_read();
act = joystick_process_buttons();
if (act == ACT_NONE)
act = joystick_process_axes();
}
#endif
return act;
}
int get_joystick_axes(long *x, long *y, int *xp, int *yp)
{
#ifdef JOYSTICK_ON
if (joy_fd >= 0)
{ *x = joy_x;
*y = joy_y;
*xp = (int) (((joy_x - JoyXMin) * 100) / (JoyXMax - JoyXMin));
*yp = (int) (((joy_y - JoyYMin) * 100) / (JoyYMax - JoyYMin));
return 1;
}
#endif
return 0;
}
void flush_joystick(void)
{
#ifdef JOYSTICK_ON
/*
#if defined(USE_JOYSTICK_EVENTS) && defined(JS_EVENT_INIT)
if (JoyEventDriven)
{ struct js_event joyEvent;
while(read(joy_fd, &joyEvent, sizeof(struct js_event)) > 0);
}
#endif
*/
joy_buttons = 0;
joy_x = (JoyXMin + JoyXMax) / 2;
joy_y = (JoyYMin + JoyYMax) / 2;
#endif
return;
}