slouken@0
|
1 |
/*
|
slouken@0
|
2 |
SDL - Simple DirectMedia Layer
|
slouken@0
|
3 |
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
|
slouken@0
|
4 |
|
slouken@0
|
5 |
This library is free software; you can redistribute it and/or
|
slouken@0
|
6 |
modify it under the terms of the GNU Library General Public
|
slouken@0
|
7 |
License as published by the Free Software Foundation; either
|
slouken@0
|
8 |
version 2 of the License, or (at your option) any later version.
|
slouken@0
|
9 |
|
slouken@0
|
10 |
This library is distributed in the hope that it will be useful,
|
slouken@0
|
11 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
slouken@0
|
12 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
slouken@0
|
13 |
Library General Public License for more details.
|
slouken@0
|
14 |
|
slouken@0
|
15 |
You should have received a copy of the GNU Library General Public
|
slouken@0
|
16 |
License along with this library; if not, write to the Free
|
slouken@0
|
17 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
slouken@0
|
18 |
|
slouken@0
|
19 |
Sam Lantinga
|
slouken@0
|
20 |
slouken@devolution.com
|
slouken@0
|
21 |
*/
|
slouken@0
|
22 |
|
slouken@0
|
23 |
#ifdef SAVE_RCSID
|
slouken@0
|
24 |
static char rcsid =
|
slouken@0
|
25 |
"@(#) $Id$";
|
slouken@0
|
26 |
#endif
|
slouken@0
|
27 |
|
slouken@0
|
28 |
/* This is the system specific header for the SDL joystick API */
|
slouken@0
|
29 |
|
slouken@0
|
30 |
#include <stdio.h> /* For the definition of NULL */
|
slouken@0
|
31 |
#include <stdlib.h> /* For getenv() prototype */
|
slouken@0
|
32 |
#include <string.h>
|
slouken@0
|
33 |
#include <sys/stat.h>
|
slouken@0
|
34 |
#include <unistd.h>
|
slouken@0
|
35 |
#include <fcntl.h>
|
slouken@0
|
36 |
#include <sys/ioctl.h>
|
slouken@0
|
37 |
#include <limits.h> /* For the definition of PATH_MAX */
|
slouken@0
|
38 |
|
slouken@0
|
39 |
#include <linux/joystick.h>
|
slouken@0
|
40 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
41 |
#include <linux/input.h>
|
slouken@0
|
42 |
#endif
|
slouken@0
|
43 |
|
slouken@0
|
44 |
#include "SDL_error.h"
|
slouken@0
|
45 |
#include "SDL_joystick.h"
|
slouken@0
|
46 |
#include "SDL_sysjoystick.h"
|
slouken@0
|
47 |
#include "SDL_joystick_c.h"
|
slouken@0
|
48 |
|
slouken@0
|
49 |
/* Define this if you want to map axes to hats and trackballs */
|
slouken@0
|
50 |
#define FANCY_HATS_AND_BALLS
|
slouken@0
|
51 |
|
slouken@0
|
52 |
#ifdef FANCY_HATS_AND_BALLS
|
slouken@0
|
53 |
/* Special joystick configurations:
|
slouken@0
|
54 |
'JoystickName' Naxes Nhats Nballs
|
slouken@0
|
55 |
*/
|
slouken@0
|
56 |
static const char *special_joysticks[] = {
|
slouken@0
|
57 |
"'MadCatz Panther XL' 3 2 1", /* We don't handle a rudder (axis 8) */
|
slouken@0
|
58 |
"'SideWinder Precision Pro' 4 1 0",
|
slouken@0
|
59 |
"'SideWinder 3D Pro' 4 1 0",
|
slouken@0
|
60 |
"'Microsoft SideWinder 3D Pro' 4 1 0",
|
slouken@0
|
61 |
"'Microsoft SideWinder Dual Strike USB version 1.0' 2 1 0",
|
slouken@0
|
62 |
"'WingMan Interceptor' 3 3 0",
|
slouken@0
|
63 |
/* WingMan Extreme Analog - not recognized by default
|
slouken@0
|
64 |
"'Analog 3-axis 4-button joystick' 2 1",
|
slouken@0
|
65 |
*/
|
slouken@0
|
66 |
"'WingMan Extreme Digital 3D' 4 1 0",
|
slouken@0
|
67 |
NULL
|
slouken@0
|
68 |
};
|
slouken@0
|
69 |
#else
|
slouken@0
|
70 |
#undef USE_INPUT_EVENTS
|
slouken@0
|
71 |
#endif
|
slouken@0
|
72 |
|
slouken@0
|
73 |
/* The maximum number of joysticks we'll detect */
|
slouken@0
|
74 |
#define MAX_JOYSTICKS 32
|
slouken@0
|
75 |
|
slouken@0
|
76 |
/* A list of available joysticks */
|
slouken@0
|
77 |
static char *SDL_joylist[MAX_JOYSTICKS];
|
slouken@0
|
78 |
|
slouken@0
|
79 |
/* The private structure used to keep track of a joystick */
|
slouken@0
|
80 |
struct joystick_hwdata {
|
slouken@0
|
81 |
int fd;
|
slouken@0
|
82 |
/* The current linux joystick driver maps hats to two axes */
|
slouken@0
|
83 |
int analog_hat; /* Well, except for analog hats */
|
slouken@0
|
84 |
struct hwdata_hat {
|
slouken@0
|
85 |
int axis[2];
|
slouken@0
|
86 |
} *hats;
|
slouken@0
|
87 |
/* The current linux joystick driver maps balls to two axes */
|
slouken@0
|
88 |
struct hwdata_ball {
|
slouken@0
|
89 |
int axis[2];
|
slouken@0
|
90 |
} *balls;
|
slouken@0
|
91 |
|
slouken@0
|
92 |
/* Support for the Linux 2.4 unified input interface */
|
slouken@0
|
93 |
SDL_bool is_hid;
|
slouken@0
|
94 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
95 |
Uint8 key_map[KEY_MAX-BTN_MISC];
|
slouken@0
|
96 |
Uint8 abs_map[ABS_MAX];
|
slouken@0
|
97 |
struct axis_correct {
|
slouken@0
|
98 |
int used;
|
slouken@0
|
99 |
int coef[3];
|
slouken@0
|
100 |
} abs_correct[ABS_MAX];
|
slouken@0
|
101 |
#endif
|
slouken@0
|
102 |
};
|
slouken@0
|
103 |
|
slouken@0
|
104 |
static char *mystrdup(const char *string)
|
slouken@0
|
105 |
{
|
slouken@0
|
106 |
char *newstring;
|
slouken@0
|
107 |
|
slouken@0
|
108 |
newstring = (char *)malloc(strlen(string)+1);
|
slouken@0
|
109 |
if ( newstring ) {
|
slouken@0
|
110 |
strcpy(newstring, string);
|
slouken@0
|
111 |
}
|
slouken@0
|
112 |
return(newstring);
|
slouken@0
|
113 |
}
|
slouken@0
|
114 |
|
slouken@0
|
115 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
116 |
#define test_bit(nr, addr) \
|
slouken@0
|
117 |
(((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
|
slouken@0
|
118 |
|
slouken@0
|
119 |
static int EV_IsJoystick(int fd)
|
slouken@0
|
120 |
{
|
slouken@0
|
121 |
unsigned long evbit[40];
|
slouken@0
|
122 |
unsigned long keybit[40];
|
slouken@0
|
123 |
unsigned long absbit[40];
|
slouken@0
|
124 |
|
slouken@0
|
125 |
if ( (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
|
slouken@0
|
126 |
(ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
|
slouken@0
|
127 |
(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) ) {
|
slouken@0
|
128 |
return(0);
|
slouken@0
|
129 |
}
|
slouken@0
|
130 |
if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
|
slouken@0
|
131 |
test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) &&
|
slouken@0
|
132 |
(test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_A, keybit) || test_bit(BTN_1, keybit)))) return 0;
|
slouken@0
|
133 |
return(1);
|
slouken@0
|
134 |
}
|
slouken@0
|
135 |
|
slouken@0
|
136 |
#endif /* USE_INPUT_EVENTS */
|
slouken@0
|
137 |
|
slouken@0
|
138 |
/* Function to scan the system for joysticks */
|
slouken@0
|
139 |
int SDL_SYS_JoystickInit(void)
|
slouken@0
|
140 |
{
|
slouken@0
|
141 |
/* The base path of the joystick devices */
|
slouken@0
|
142 |
const char *joydev_pattern[2] = {
|
slouken@0
|
143 |
"/dev/js%d",
|
slouken@0
|
144 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
145 |
"/dev/input/event%d"
|
slouken@211
|
146 |
#endif
|
slouken@0
|
147 |
"/dev/input/js%d"
|
slouken@0
|
148 |
};
|
slouken@0
|
149 |
int numjoysticks;
|
slouken@0
|
150 |
int i, j, done;
|
slouken@0
|
151 |
int fd;
|
slouken@0
|
152 |
char path[PATH_MAX];
|
slouken@0
|
153 |
dev_t dev_nums[MAX_JOYSTICKS]; /* major/minor device numbers */
|
slouken@0
|
154 |
struct stat sb;
|
slouken@0
|
155 |
int n, duplicate;
|
slouken@0
|
156 |
|
slouken@0
|
157 |
numjoysticks = 0;
|
slouken@0
|
158 |
|
slouken@0
|
159 |
/* First see if the user specified a joystick to use */
|
slouken@0
|
160 |
if ( getenv("SDL_JOYSTICK_DEVICE") != NULL ) {
|
slouken@0
|
161 |
strncpy(path, getenv("SDL_JOYSTICK_DEVICE"), sizeof(path));
|
slouken@0
|
162 |
path[sizeof(path)-1] = '\0';
|
slouken@0
|
163 |
if ( stat(path, &sb) == 0 ) {
|
slouken@0
|
164 |
fd = open(path, O_RDONLY, 0);
|
slouken@0
|
165 |
if ( fd >= 0 ) {
|
slouken@0
|
166 |
/* Assume the user knows what they're doing. */
|
slouken@0
|
167 |
SDL_joylist[numjoysticks] = mystrdup(path);
|
slouken@0
|
168 |
if ( SDL_joylist[numjoysticks] ) {
|
slouken@0
|
169 |
dev_nums[numjoysticks] = sb.st_rdev;
|
slouken@0
|
170 |
++numjoysticks;
|
slouken@0
|
171 |
}
|
slouken@0
|
172 |
close(fd);
|
slouken@0
|
173 |
}
|
slouken@0
|
174 |
}
|
slouken@0
|
175 |
}
|
slouken@0
|
176 |
for ( i=0; i<SDL_TABLESIZE(joydev_pattern); ++i ) {
|
slouken@0
|
177 |
done = 0;
|
slouken@0
|
178 |
for ( j=0; (j < MAX_JOYSTICKS) && !done; ++j ) {
|
slouken@0
|
179 |
sprintf(path, joydev_pattern[i], j);
|
slouken@0
|
180 |
|
slouken@0
|
181 |
/* rcg06302000 replaced access(F_OK) call with stat().
|
slouken@0
|
182 |
* stat() will fail if the file doesn't exist, so it's
|
slouken@0
|
183 |
* equivalent behaviour.
|
slouken@0
|
184 |
*/
|
slouken@0
|
185 |
if ( stat(path, &sb) == 0 ) {
|
slouken@0
|
186 |
/* Check to make sure it's not already in list.
|
slouken@0
|
187 |
* This happens when we see a stick via symlink.
|
slouken@0
|
188 |
*/
|
slouken@0
|
189 |
duplicate = 0;
|
slouken@0
|
190 |
for (n=0; (n<numjoysticks) && !duplicate; ++n) {
|
slouken@0
|
191 |
if ( sb.st_rdev == dev_nums[n] ) {
|
slouken@0
|
192 |
duplicate = 1;
|
slouken@0
|
193 |
}
|
slouken@0
|
194 |
}
|
slouken@0
|
195 |
if (duplicate) {
|
slouken@0
|
196 |
continue;
|
slouken@0
|
197 |
}
|
slouken@0
|
198 |
|
slouken@0
|
199 |
fd = open(path, O_RDONLY, 0);
|
slouken@0
|
200 |
if ( fd < 0 ) {
|
slouken@0
|
201 |
continue;
|
slouken@0
|
202 |
}
|
slouken@0
|
203 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
204 |
#ifdef DEBUG_INPUT_EVENTS
|
slouken@0
|
205 |
printf("Checking %s\n", path);
|
slouken@0
|
206 |
#endif
|
slouken@0
|
207 |
if ( (i > 0) && ! EV_IsJoystick(fd) ) {
|
slouken@0
|
208 |
close(fd);
|
slouken@0
|
209 |
continue;
|
slouken@0
|
210 |
}
|
slouken@0
|
211 |
#endif
|
slouken@0
|
212 |
close(fd);
|
slouken@0
|
213 |
|
slouken@0
|
214 |
/* We're fine, add this joystick */
|
slouken@0
|
215 |
SDL_joylist[numjoysticks] = mystrdup(path);
|
slouken@0
|
216 |
if ( SDL_joylist[numjoysticks] ) {
|
slouken@0
|
217 |
dev_nums[numjoysticks] = sb.st_rdev;
|
slouken@0
|
218 |
++numjoysticks;
|
slouken@0
|
219 |
}
|
slouken@0
|
220 |
} else {
|
slouken@0
|
221 |
done = 1;
|
slouken@0
|
222 |
}
|
slouken@0
|
223 |
}
|
slouken@211
|
224 |
/* This is a special case...
|
slouken@211
|
225 |
If we're looking at the /dev/input event devices, and we found
|
slouken@211
|
226 |
at least one, then we don't want to look at the input joystick
|
slouken@211
|
227 |
devices, since they're built on top of devices that we've already
|
slouken@211
|
228 |
seen, so we're done.
|
slouken@211
|
229 |
*/
|
slouken@211
|
230 |
if ( i > 0 && j > 0 ) {
|
slouken@211
|
231 |
done = 1;
|
slouken@211
|
232 |
}
|
slouken@0
|
233 |
}
|
slouken@0
|
234 |
return(numjoysticks);
|
slouken@0
|
235 |
}
|
slouken@0
|
236 |
|
slouken@0
|
237 |
/* Function to get the device-dependent name of a joystick */
|
slouken@0
|
238 |
const char *SDL_SYS_JoystickName(int index)
|
slouken@0
|
239 |
{
|
slouken@0
|
240 |
int fd;
|
slouken@0
|
241 |
static char namebuf[128];
|
slouken@0
|
242 |
char *name;
|
slouken@0
|
243 |
|
slouken@0
|
244 |
name = NULL;
|
slouken@0
|
245 |
fd = open(SDL_joylist[index], O_RDONLY, 0);
|
slouken@0
|
246 |
if ( fd >= 0 ) {
|
slouken@0
|
247 |
if (
|
slouken@0
|
248 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
249 |
(ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) &&
|
slouken@0
|
250 |
#endif
|
slouken@0
|
251 |
(ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) <= 0) ) {
|
slouken@0
|
252 |
name = SDL_joylist[index];
|
slouken@0
|
253 |
} else {
|
slouken@0
|
254 |
name = namebuf;
|
slouken@0
|
255 |
}
|
slouken@0
|
256 |
close(fd);
|
slouken@0
|
257 |
}
|
slouken@0
|
258 |
return name;
|
slouken@0
|
259 |
}
|
slouken@0
|
260 |
|
slouken@0
|
261 |
#ifdef FANCY_HATS_AND_BALLS
|
slouken@0
|
262 |
|
slouken@0
|
263 |
static int allocate_hatdata(SDL_Joystick *joystick)
|
slouken@0
|
264 |
{
|
slouken@0
|
265 |
int i;
|
slouken@0
|
266 |
|
slouken@0
|
267 |
joystick->hwdata->hats = (struct hwdata_hat *)malloc(
|
slouken@0
|
268 |
joystick->nhats * sizeof(struct hwdata_hat));
|
slouken@0
|
269 |
if ( joystick->hwdata->hats == NULL ) {
|
slouken@0
|
270 |
return(-1);
|
slouken@0
|
271 |
}
|
slouken@0
|
272 |
for ( i=0; i<joystick->nhats; ++i ) {
|
slouken@0
|
273 |
joystick->hwdata->hats[i].axis[0] = 1;
|
slouken@0
|
274 |
joystick->hwdata->hats[i].axis[1] = 1;
|
slouken@0
|
275 |
}
|
slouken@0
|
276 |
return(0);
|
slouken@0
|
277 |
}
|
slouken@0
|
278 |
|
slouken@0
|
279 |
static int allocate_balldata(SDL_Joystick *joystick)
|
slouken@0
|
280 |
{
|
slouken@0
|
281 |
int i;
|
slouken@0
|
282 |
|
slouken@0
|
283 |
joystick->hwdata->balls = (struct hwdata_ball *)malloc(
|
slouken@0
|
284 |
joystick->nballs * sizeof(struct hwdata_ball));
|
slouken@0
|
285 |
if ( joystick->hwdata->balls == NULL ) {
|
slouken@0
|
286 |
return(-1);
|
slouken@0
|
287 |
}
|
slouken@0
|
288 |
for ( i=0; i<joystick->nballs; ++i ) {
|
slouken@0
|
289 |
joystick->hwdata->balls[i].axis[0] = 0;
|
slouken@0
|
290 |
joystick->hwdata->balls[i].axis[1] = 0;
|
slouken@0
|
291 |
}
|
slouken@0
|
292 |
return(0);
|
slouken@0
|
293 |
}
|
slouken@0
|
294 |
|
slouken@0
|
295 |
static SDL_bool ConfigJoystick(SDL_Joystick *joystick,
|
slouken@0
|
296 |
const char *name, const char *config)
|
slouken@0
|
297 |
{
|
slouken@0
|
298 |
char cfg_name[128];
|
slouken@0
|
299 |
SDL_bool handled;
|
slouken@0
|
300 |
|
slouken@0
|
301 |
if ( config == NULL ) {
|
slouken@0
|
302 |
return(SDL_FALSE);
|
slouken@0
|
303 |
}
|
slouken@0
|
304 |
strcpy(cfg_name, "");
|
slouken@0
|
305 |
if ( *config == '\'' ) {
|
slouken@0
|
306 |
sscanf(config, "'%[^']s'", cfg_name);
|
slouken@0
|
307 |
config += strlen(cfg_name)+2;
|
slouken@0
|
308 |
} else {
|
slouken@0
|
309 |
sscanf(config, "%s", cfg_name);
|
slouken@0
|
310 |
config += strlen(cfg_name);
|
slouken@0
|
311 |
}
|
slouken@0
|
312 |
handled = SDL_FALSE;
|
slouken@0
|
313 |
if ( strcmp(cfg_name, name) == 0 ) {
|
slouken@0
|
314 |
/* Get the number of axes, hats and balls for this joystick */
|
slouken@0
|
315 |
int joystick_axes = joystick->naxes;
|
slouken@0
|
316 |
sscanf(config, "%d %d %d",
|
slouken@0
|
317 |
&joystick->naxes, &joystick->nhats, &joystick->nballs);
|
slouken@0
|
318 |
|
slouken@0
|
319 |
/* Allocate the extra data for mapping them */
|
slouken@0
|
320 |
if ( joystick->nhats > 0 ) {
|
slouken@0
|
321 |
/* HACK: Analog hats map to only one axis */
|
slouken@0
|
322 |
if (joystick_axes == (joystick->naxes+joystick->nhats)){
|
slouken@0
|
323 |
joystick->hwdata->analog_hat = 1;
|
slouken@0
|
324 |
} else {
|
slouken@0
|
325 |
if ( allocate_hatdata(joystick) < 0 ) {
|
slouken@0
|
326 |
joystick->nhats = 0;
|
slouken@0
|
327 |
}
|
slouken@0
|
328 |
joystick->hwdata->analog_hat = 0;
|
slouken@0
|
329 |
}
|
slouken@0
|
330 |
}
|
slouken@0
|
331 |
if ( joystick->nballs > 0 ) {
|
slouken@0
|
332 |
if ( allocate_balldata(joystick) < 0 ) {
|
slouken@0
|
333 |
joystick->nballs = 0;
|
slouken@0
|
334 |
}
|
slouken@0
|
335 |
}
|
slouken@0
|
336 |
handled = SDL_TRUE;
|
slouken@0
|
337 |
}
|
slouken@0
|
338 |
return(handled);
|
slouken@0
|
339 |
}
|
slouken@0
|
340 |
|
slouken@0
|
341 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
342 |
|
slouken@0
|
343 |
static SDL_bool EV_ConfigJoystick(SDL_Joystick *joystick, int fd)
|
slouken@0
|
344 |
{
|
slouken@0
|
345 |
int i;
|
slouken@0
|
346 |
unsigned long keybit[40];
|
slouken@0
|
347 |
unsigned long absbit[40];
|
slouken@0
|
348 |
unsigned long relbit[40];
|
slouken@0
|
349 |
|
slouken@0
|
350 |
/* See if this device uses the new unified event API */
|
slouken@0
|
351 |
if ( (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
|
slouken@0
|
352 |
(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
|
slouken@0
|
353 |
(ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) ) {
|
slouken@0
|
354 |
joystick->hwdata->is_hid = SDL_TRUE;
|
slouken@0
|
355 |
|
slouken@0
|
356 |
/* Get the number of buttons, axes, and other thingamajigs */
|
slouken@0
|
357 |
for ( i=BTN_JOYSTICK; i < KEY_MAX; ++i ) {
|
slouken@0
|
358 |
if ( test_bit(i, keybit) ) {
|
slouken@0
|
359 |
#ifdef DEBUG_INPUT_EVENTS
|
slouken@0
|
360 |
printf("Joystick has button: 0x%x\n", i);
|
slouken@0
|
361 |
#endif
|
slouken@0
|
362 |
joystick->hwdata->key_map[i-BTN_MISC] =
|
slouken@0
|
363 |
joystick->nbuttons;
|
slouken@0
|
364 |
++joystick->nbuttons;
|
slouken@0
|
365 |
}
|
slouken@0
|
366 |
}
|
slouken@0
|
367 |
for ( i=BTN_MISC; i < BTN_JOYSTICK; ++i ) {
|
slouken@0
|
368 |
if ( test_bit(i, keybit) ) {
|
slouken@0
|
369 |
#ifdef DEBUG_INPUT_EVENTS
|
slouken@0
|
370 |
printf("Joystick has button: 0x%x\n", i);
|
slouken@0
|
371 |
#endif
|
slouken@0
|
372 |
joystick->hwdata->key_map[i-BTN_MISC] =
|
slouken@0
|
373 |
joystick->nbuttons;
|
slouken@0
|
374 |
++joystick->nbuttons;
|
slouken@0
|
375 |
}
|
slouken@0
|
376 |
}
|
slouken@0
|
377 |
for ( i=0; i<ABS_MAX; ++i ) {
|
slouken@0
|
378 |
/* Skip hats */
|
slouken@0
|
379 |
if ( i == ABS_HAT0X ) {
|
slouken@0
|
380 |
i = ABS_HAT3Y;
|
slouken@0
|
381 |
continue;
|
slouken@0
|
382 |
}
|
slouken@0
|
383 |
if ( test_bit(i, absbit) ) {
|
slouken@0
|
384 |
int values[5];
|
slouken@0
|
385 |
|
slouken@0
|
386 |
ioctl(fd, EVIOCGABS(i), values);
|
slouken@0
|
387 |
#ifdef DEBUG_INPUT_EVENTS
|
slouken@0
|
388 |
printf("Joystick has absolute axis: %x\n", i);
|
slouken@0
|
389 |
printf("Values = { %d, %d, %d, %d, %d }\n",
|
slouken@0
|
390 |
values[0], values[1],
|
slouken@0
|
391 |
values[2], values[3], values[4]);
|
slouken@0
|
392 |
#endif /* DEBUG_INPUT_EVENTS */
|
slouken@0
|
393 |
joystick->hwdata->abs_map[i] = joystick->naxes;
|
slouken@0
|
394 |
if ( values[1] == values[2] ) {
|
slouken@0
|
395 |
joystick->hwdata->abs_correct[i].used = 0;
|
slouken@0
|
396 |
} else {
|
slouken@0
|
397 |
joystick->hwdata->abs_correct[i].used = 1;
|
slouken@0
|
398 |
joystick->hwdata->abs_correct[i].coef[0] =
|
slouken@0
|
399 |
(values[2] + values[1]) / 2 - values[4];
|
slouken@0
|
400 |
joystick->hwdata->abs_correct[i].coef[1] =
|
slouken@0
|
401 |
(values[2] + values[1]) / 2 + values[4];
|
slouken@0
|
402 |
joystick->hwdata->abs_correct[i].coef[2] =
|
slouken@0
|
403 |
(1 << 29) / ((values[2] - values[1]) / 2 - 2 * values[4]);
|
slouken@0
|
404 |
}
|
slouken@0
|
405 |
++joystick->naxes;
|
slouken@0
|
406 |
}
|
slouken@0
|
407 |
}
|
slouken@0
|
408 |
for ( i=ABS_HAT0X; i <= ABS_HAT3Y; i += 2 ) {
|
slouken@0
|
409 |
if ( test_bit(i, absbit) || test_bit(i+1, absbit) ) {
|
slouken@0
|
410 |
#ifdef DEBUG_INPUT_EVENTS
|
slouken@0
|
411 |
printf("Joystick has hat %d\n",(i-ABS_HAT0X)/2);
|
slouken@0
|
412 |
#endif
|
slouken@0
|
413 |
++joystick->nhats;
|
slouken@0
|
414 |
}
|
slouken@0
|
415 |
}
|
slouken@0
|
416 |
if ( test_bit(REL_X, relbit) || test_bit(REL_Y, relbit) ) {
|
slouken@0
|
417 |
++joystick->nballs;
|
slouken@0
|
418 |
}
|
slouken@0
|
419 |
|
slouken@0
|
420 |
/* Allocate data to keep track of these thingamajigs */
|
slouken@0
|
421 |
if ( joystick->nhats > 0 ) {
|
slouken@0
|
422 |
if ( allocate_hatdata(joystick) < 0 ) {
|
slouken@0
|
423 |
joystick->nhats = 0;
|
slouken@0
|
424 |
}
|
slouken@0
|
425 |
}
|
slouken@0
|
426 |
if ( joystick->nballs > 0 ) {
|
slouken@0
|
427 |
if ( allocate_balldata(joystick) < 0 ) {
|
slouken@0
|
428 |
joystick->nballs = 0;
|
slouken@0
|
429 |
}
|
slouken@0
|
430 |
}
|
slouken@0
|
431 |
}
|
slouken@0
|
432 |
return(joystick->hwdata->is_hid);
|
slouken@0
|
433 |
}
|
slouken@0
|
434 |
|
slouken@0
|
435 |
#endif /* USE_INPUT_EVENTS */
|
slouken@0
|
436 |
|
slouken@0
|
437 |
#endif /* FANCY_HATS_AND_BALLS */
|
slouken@0
|
438 |
|
slouken@0
|
439 |
/* Function to open a joystick for use.
|
slouken@0
|
440 |
The joystick to open is specified by the index field of the joystick.
|
slouken@0
|
441 |
This should fill the nbuttons and naxes fields of the joystick structure.
|
slouken@0
|
442 |
It returns 0, or -1 if there is an error.
|
slouken@0
|
443 |
*/
|
slouken@0
|
444 |
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
|
slouken@0
|
445 |
{
|
slouken@0
|
446 |
#ifdef FANCY_HATS_AND_BALLS
|
slouken@0
|
447 |
const char *name;
|
slouken@0
|
448 |
int i;
|
slouken@0
|
449 |
#endif
|
slouken@0
|
450 |
int fd;
|
slouken@0
|
451 |
unsigned char n;
|
slouken@0
|
452 |
|
slouken@0
|
453 |
/* Open the joystick and set the joystick file descriptor */
|
slouken@0
|
454 |
fd = open(SDL_joylist[joystick->index], O_RDONLY, 0);
|
slouken@0
|
455 |
if ( fd < 0 ) {
|
slouken@0
|
456 |
SDL_SetError("Unable to open %s\n",
|
slouken@0
|
457 |
SDL_joylist[joystick->index]);
|
slouken@0
|
458 |
return(-1);
|
slouken@0
|
459 |
}
|
slouken@0
|
460 |
joystick->hwdata = (struct joystick_hwdata *)
|
slouken@0
|
461 |
malloc(sizeof(*joystick->hwdata));
|
slouken@0
|
462 |
if ( joystick->hwdata == NULL ) {
|
slouken@0
|
463 |
SDL_OutOfMemory();
|
slouken@0
|
464 |
close(fd);
|
slouken@0
|
465 |
return(-1);
|
slouken@0
|
466 |
}
|
slouken@0
|
467 |
memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
|
slouken@0
|
468 |
joystick->hwdata->fd = fd;
|
slouken@0
|
469 |
|
slouken@0
|
470 |
/* Set the joystick to non-blocking read mode */
|
slouken@0
|
471 |
fcntl(fd, F_SETFL, O_NONBLOCK);
|
slouken@0
|
472 |
|
slouken@0
|
473 |
/* Get the number of buttons and axes on the joystick */
|
slouken@0
|
474 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
475 |
if ( ! EV_ConfigJoystick(joystick, fd) )
|
slouken@0
|
476 |
#endif
|
slouken@0
|
477 |
{
|
slouken@0
|
478 |
if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) {
|
slouken@0
|
479 |
joystick->naxes = 2;
|
slouken@0
|
480 |
} else {
|
slouken@0
|
481 |
joystick->naxes = n;
|
slouken@0
|
482 |
}
|
slouken@0
|
483 |
if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) {
|
slouken@0
|
484 |
joystick->nbuttons = 2;
|
slouken@0
|
485 |
} else {
|
slouken@0
|
486 |
joystick->nbuttons = n;
|
slouken@0
|
487 |
}
|
slouken@0
|
488 |
#ifdef FANCY_HATS_AND_BALLS
|
slouken@0
|
489 |
/* Check for special joystick support */
|
slouken@0
|
490 |
name = SDL_SYS_JoystickName(joystick->index);
|
slouken@0
|
491 |
for ( i=0; special_joysticks[i]; ++i ) {
|
slouken@0
|
492 |
if (ConfigJoystick(joystick,name,special_joysticks[i])){
|
slouken@0
|
493 |
break;
|
slouken@0
|
494 |
}
|
slouken@0
|
495 |
}
|
slouken@0
|
496 |
if ( special_joysticks[i] == NULL ) {
|
slouken@0
|
497 |
ConfigJoystick(joystick, name,
|
slouken@0
|
498 |
getenv("SDL_LINUX_JOYSTICK"));
|
slouken@0
|
499 |
}
|
slouken@0
|
500 |
#endif /* FANCY_HATS_AND_BALLS */
|
slouken@0
|
501 |
}
|
slouken@0
|
502 |
return(0);
|
slouken@0
|
503 |
}
|
slouken@0
|
504 |
|
slouken@0
|
505 |
static __inline__
|
slouken@0
|
506 |
void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value)
|
slouken@0
|
507 |
{
|
slouken@0
|
508 |
struct hwdata_hat *the_hat;
|
slouken@0
|
509 |
const Uint8 position_map[3][3] = {
|
slouken@0
|
510 |
{ SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP },
|
slouken@0
|
511 |
{ SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT },
|
slouken@0
|
512 |
{ SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN }
|
slouken@0
|
513 |
};
|
slouken@0
|
514 |
|
slouken@0
|
515 |
the_hat = &stick->hwdata->hats[hat];
|
slouken@0
|
516 |
if ( value < 0 ) {
|
slouken@0
|
517 |
value = 0;
|
slouken@0
|
518 |
} else
|
slouken@0
|
519 |
if ( value == 0 ) {
|
slouken@0
|
520 |
value = 1;
|
slouken@0
|
521 |
} else
|
slouken@0
|
522 |
if ( value > 0 ) {
|
slouken@0
|
523 |
value = 2;
|
slouken@0
|
524 |
}
|
slouken@0
|
525 |
if ( value != the_hat->axis[axis] ) {
|
slouken@0
|
526 |
the_hat->axis[axis] = value;
|
slouken@0
|
527 |
SDL_PrivateJoystickHat(stick, hat,
|
slouken@0
|
528 |
position_map[the_hat->axis[1]][the_hat->axis[0]]);
|
slouken@0
|
529 |
}
|
slouken@0
|
530 |
}
|
slouken@0
|
531 |
|
slouken@0
|
532 |
/* This was necessary for the Wingman Extreme Analog joystick */
|
slouken@0
|
533 |
static __inline__
|
slouken@0
|
534 |
void HandleAnalogHat(SDL_Joystick *stick, Uint8 hat, int value)
|
slouken@0
|
535 |
{
|
slouken@0
|
536 |
const Uint8 position_map[] = {
|
slouken@0
|
537 |
SDL_HAT_UP,
|
slouken@0
|
538 |
SDL_HAT_RIGHT,
|
slouken@0
|
539 |
SDL_HAT_DOWN,
|
slouken@0
|
540 |
SDL_HAT_LEFT,
|
slouken@0
|
541 |
SDL_HAT_CENTERED
|
slouken@0
|
542 |
};
|
slouken@0
|
543 |
SDL_PrivateJoystickHat(stick, hat, position_map[(value/16000)+2]);
|
slouken@0
|
544 |
}
|
slouken@0
|
545 |
|
slouken@0
|
546 |
static __inline__
|
slouken@0
|
547 |
void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
|
slouken@0
|
548 |
{
|
slouken@0
|
549 |
stick->hwdata->balls[ball].axis[axis] += value;
|
slouken@0
|
550 |
}
|
slouken@0
|
551 |
|
slouken@0
|
552 |
/* Function to update the state of a joystick - called as a device poll.
|
slouken@0
|
553 |
* This function shouldn't update the joystick structure directly,
|
slouken@0
|
554 |
* but instead should call SDL_PrivateJoystick*() to deliver events
|
slouken@0
|
555 |
* and update joystick device state.
|
slouken@0
|
556 |
*/
|
slouken@0
|
557 |
static __inline__ void JS_HandleEvents(SDL_Joystick *joystick)
|
slouken@0
|
558 |
{
|
slouken@0
|
559 |
struct js_event events[32];
|
slouken@0
|
560 |
int i, len;
|
slouken@0
|
561 |
Uint8 other_axis;
|
slouken@0
|
562 |
|
slouken@0
|
563 |
while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
|
slouken@0
|
564 |
len /= sizeof(events[0]);
|
slouken@0
|
565 |
for ( i=0; i<len; ++i ) {
|
slouken@0
|
566 |
switch (events[i].type & ~JS_EVENT_INIT) {
|
slouken@0
|
567 |
case JS_EVENT_AXIS:
|
slouken@0
|
568 |
if ( events[i].number < joystick->naxes ) {
|
slouken@0
|
569 |
SDL_PrivateJoystickAxis(joystick,
|
slouken@0
|
570 |
events[i].number, events[i].value);
|
slouken@0
|
571 |
break;
|
slouken@0
|
572 |
}
|
slouken@0
|
573 |
events[i].number -= joystick->naxes;
|
slouken@0
|
574 |
if ( joystick->hwdata->analog_hat ) {
|
slouken@0
|
575 |
other_axis = events[i].number;
|
slouken@0
|
576 |
if ( other_axis < joystick->nhats ) {
|
slouken@0
|
577 |
HandleAnalogHat(joystick, other_axis,
|
slouken@0
|
578 |
events[i].value);
|
slouken@0
|
579 |
break;
|
slouken@0
|
580 |
}
|
slouken@0
|
581 |
} else {
|
slouken@0
|
582 |
other_axis = (events[i].number / 2);
|
slouken@0
|
583 |
if ( other_axis < joystick->nhats ) {
|
slouken@0
|
584 |
HandleHat(joystick, other_axis,
|
slouken@0
|
585 |
events[i].number%2,
|
slouken@0
|
586 |
events[i].value);
|
slouken@0
|
587 |
break;
|
slouken@0
|
588 |
}
|
slouken@0
|
589 |
}
|
slouken@0
|
590 |
events[i].number -= joystick->nhats*2;
|
slouken@0
|
591 |
other_axis = (events[i].number / 2);
|
slouken@0
|
592 |
if ( other_axis < joystick->nballs ) {
|
slouken@0
|
593 |
HandleBall(joystick, other_axis,
|
slouken@0
|
594 |
events[i].number%2,
|
slouken@0
|
595 |
events[i].value);
|
slouken@0
|
596 |
break;
|
slouken@0
|
597 |
}
|
slouken@0
|
598 |
break;
|
slouken@0
|
599 |
case JS_EVENT_BUTTON:
|
slouken@0
|
600 |
SDL_PrivateJoystickButton(joystick,
|
slouken@0
|
601 |
events[i].number, events[i].value);
|
slouken@0
|
602 |
break;
|
slouken@0
|
603 |
default:
|
slouken@0
|
604 |
/* ?? */
|
slouken@0
|
605 |
break;
|
slouken@0
|
606 |
}
|
slouken@0
|
607 |
}
|
slouken@0
|
608 |
}
|
slouken@0
|
609 |
}
|
slouken@0
|
610 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
611 |
static __inline__ int EV_AxisCorrect(SDL_Joystick *joystick, int which, int value)
|
slouken@0
|
612 |
{
|
slouken@0
|
613 |
struct axis_correct *correct;
|
slouken@0
|
614 |
|
slouken@0
|
615 |
correct = &joystick->hwdata->abs_correct[which];
|
slouken@0
|
616 |
if ( correct->used ) {
|
slouken@0
|
617 |
if ( value > correct->coef[0] ) {
|
slouken@0
|
618 |
if ( value < correct->coef[1] ) {
|
slouken@0
|
619 |
return 0;
|
slouken@0
|
620 |
}
|
slouken@0
|
621 |
value -= correct->coef[1];
|
slouken@0
|
622 |
} else {
|
slouken@0
|
623 |
value -= correct->coef[0];
|
slouken@0
|
624 |
}
|
slouken@0
|
625 |
value *= correct->coef[2];
|
slouken@0
|
626 |
value >>= 14;
|
slouken@0
|
627 |
}
|
slouken@0
|
628 |
/* Clamp and return */
|
slouken@0
|
629 |
if ( value < -32767 ) {
|
slouken@0
|
630 |
value = -32767;
|
slouken@0
|
631 |
} else
|
slouken@0
|
632 |
if ( value > 32767 ) {
|
slouken@0
|
633 |
value = 32767;
|
slouken@0
|
634 |
}
|
slouken@0
|
635 |
return value;
|
slouken@0
|
636 |
}
|
slouken@0
|
637 |
|
slouken@0
|
638 |
static __inline__ void EV_HandleEvents(SDL_Joystick *joystick)
|
slouken@0
|
639 |
{
|
slouken@0
|
640 |
struct input_event events[32];
|
slouken@0
|
641 |
int i, len;
|
slouken@0
|
642 |
int code;
|
slouken@0
|
643 |
|
slouken@0
|
644 |
while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
|
slouken@0
|
645 |
len /= sizeof(events[0]);
|
slouken@0
|
646 |
for ( i=0; i<len; ++i ) {
|
slouken@0
|
647 |
code = events[i].code;
|
slouken@0
|
648 |
switch (events[i].type) {
|
slouken@0
|
649 |
case EV_KEY:
|
slouken@0
|
650 |
if ( code >= BTN_MISC ) {
|
slouken@0
|
651 |
code -= BTN_MISC;
|
slouken@0
|
652 |
SDL_PrivateJoystickButton(joystick,
|
slouken@0
|
653 |
joystick->hwdata->key_map[code],
|
slouken@0
|
654 |
events[i].value);
|
slouken@0
|
655 |
}
|
slouken@0
|
656 |
break;
|
slouken@0
|
657 |
case EV_ABS:
|
slouken@0
|
658 |
switch (code) {
|
slouken@0
|
659 |
case ABS_HAT0X:
|
slouken@0
|
660 |
case ABS_HAT0Y:
|
slouken@0
|
661 |
case ABS_HAT1X:
|
slouken@0
|
662 |
case ABS_HAT1Y:
|
slouken@0
|
663 |
case ABS_HAT2X:
|
slouken@0
|
664 |
case ABS_HAT2Y:
|
slouken@0
|
665 |
case ABS_HAT3X:
|
slouken@0
|
666 |
case ABS_HAT3Y:
|
slouken@0
|
667 |
code -= ABS_HAT0X;
|
slouken@0
|
668 |
HandleHat(joystick, code/2, code%2,
|
slouken@0
|
669 |
events[i].value);
|
slouken@0
|
670 |
break;
|
slouken@0
|
671 |
default:
|
slouken@0
|
672 |
events[i].value = EV_AxisCorrect(joystick, code, events[i].value);
|
slouken@0
|
673 |
SDL_PrivateJoystickAxis(joystick,
|
slouken@0
|
674 |
joystick->hwdata->abs_map[code],
|
slouken@0
|
675 |
events[i].value);
|
slouken@0
|
676 |
break;
|
slouken@0
|
677 |
}
|
slouken@0
|
678 |
break;
|
slouken@0
|
679 |
case EV_REL:
|
slouken@0
|
680 |
switch (code) {
|
slouken@0
|
681 |
case REL_X:
|
slouken@0
|
682 |
case REL_Y:
|
slouken@0
|
683 |
code -= REL_X;
|
slouken@0
|
684 |
HandleBall(joystick, code/2, code%2,
|
slouken@0
|
685 |
events[i].value);
|
slouken@0
|
686 |
break;
|
slouken@0
|
687 |
default:
|
slouken@0
|
688 |
break;
|
slouken@0
|
689 |
}
|
slouken@0
|
690 |
break;
|
slouken@0
|
691 |
default:
|
slouken@0
|
692 |
break;
|
slouken@0
|
693 |
}
|
slouken@0
|
694 |
}
|
slouken@0
|
695 |
}
|
slouken@0
|
696 |
}
|
slouken@0
|
697 |
#endif /* USE_INPUT_EVENTS */
|
slouken@0
|
698 |
|
slouken@0
|
699 |
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
|
slouken@0
|
700 |
{
|
slouken@0
|
701 |
int i;
|
slouken@0
|
702 |
|
slouken@0
|
703 |
#ifdef USE_INPUT_EVENTS
|
slouken@0
|
704 |
if ( joystick->hwdata->is_hid )
|
slouken@0
|
705 |
EV_HandleEvents(joystick);
|
slouken@0
|
706 |
else
|
slouken@0
|
707 |
#endif
|
slouken@0
|
708 |
JS_HandleEvents(joystick);
|
slouken@0
|
709 |
|
slouken@0
|
710 |
/* Deliver ball motion updates */
|
slouken@0
|
711 |
for ( i=0; i<joystick->nballs; ++i ) {
|
slouken@0
|
712 |
int xrel, yrel;
|
slouken@0
|
713 |
|
slouken@0
|
714 |
xrel = joystick->hwdata->balls[i].axis[0];
|
slouken@0
|
715 |
yrel = joystick->hwdata->balls[i].axis[1];
|
slouken@0
|
716 |
if ( xrel || yrel ) {
|
slouken@0
|
717 |
joystick->hwdata->balls[i].axis[0] = 0;
|
slouken@0
|
718 |
joystick->hwdata->balls[i].axis[1] = 0;
|
slouken@0
|
719 |
SDL_PrivateJoystickBall(joystick, (Uint8)i, xrel, yrel);
|
slouken@0
|
720 |
}
|
slouken@0
|
721 |
}
|
slouken@0
|
722 |
}
|
slouken@0
|
723 |
|
slouken@0
|
724 |
/* Function to close a joystick after use */
|
slouken@0
|
725 |
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
|
slouken@0
|
726 |
{
|
slouken@0
|
727 |
if ( joystick->hwdata ) {
|
slouken@0
|
728 |
close(joystick->hwdata->fd);
|
slouken@0
|
729 |
if ( joystick->hwdata->hats ) {
|
slouken@0
|
730 |
free(joystick->hwdata->hats);
|
slouken@0
|
731 |
}
|
slouken@0
|
732 |
if ( joystick->hwdata->balls ) {
|
slouken@0
|
733 |
free(joystick->hwdata->balls);
|
slouken@0
|
734 |
}
|
slouken@0
|
735 |
free(joystick->hwdata);
|
slouken@0
|
736 |
joystick->hwdata = NULL;
|
slouken@0
|
737 |
}
|
slouken@0
|
738 |
}
|
slouken@0
|
739 |
|
slouken@0
|
740 |
/* Function to perform any system-specific joystick related cleanup */
|
slouken@0
|
741 |
void SDL_SYS_JoystickQuit(void)
|
slouken@0
|
742 |
{
|
slouken@0
|
743 |
int i;
|
slouken@0
|
744 |
|
slouken@0
|
745 |
for ( i=0; SDL_joylist[i]; ++i ) {
|
slouken@0
|
746 |
free(SDL_joylist[i]);
|
slouken@0
|
747 |
}
|
slouken@0
|
748 |
SDL_joylist[0] = NULL;
|
slouken@0
|
749 |
}
|
slouken@0
|
750 |
|