Descent3/ddio_lnx/lnxjoy.cpp
2024-04-16 12:56:40 -06:00

551 lines
14 KiB
C++

/*
* $Logfile: /DescentIII/Main/ddio_lnx/lnxjoy.cpp $
* $Revision: 1.4 $
* $Date: 2000/06/29 06:41:23 $
* $Author: icculus $
*
* Linux joystick routines
*
* $Log: lnxjoy.cpp,v $
* Revision 1.4 2000/06/29 06:41:23 icculus
* mad commits.
*
* Revision 1.3 2000/06/24 01:15:15 icculus
* patched to compile.
*
* Revision 1.2 2000/05/29 05:21:09 icculus
* Changed a fprintf(stderr, ...) to an mprintf()...
*
* Revision 1.1.1.1 2000/04/18 00:00:33 icculus
* initial checkin
*
*
* 9 8/22/99 5:55p Jeff
* fixed assert
*
* 8 8/19/99 3:46p Jeff
* removed mprintfs
*
* 7 8/19/99 3:22p Jeff
* added support for joystick driver version pre 1.0
*
* 6 8/18/99 9:47p Jeff
* joystick support! for kernel 2..2+ clients...need to handle before that
* still.
*
* 5 8/17/99 2:32p Jeff
* fixed joy_GetPos
*
* 4 7/14/99 9:06p Jeff
* added comment header
*
* $NoKeywords: $
*/
#include <linux/joystick.h>
#include "joystick.h"
#include "pserror.h"
#include "pstypes.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <memory.h>
#include <errno.h>
// rcg06182000 need this for specific joystick stuff.
#include "args.h"
#define JOY_DEV "/dev/js"
typedef struct tJoystickRecord {
bool valid; // is this a valid device.
bool remote; // is this device on another computer
bool use_old_driver; // use pre joystick 1.0 driver interface
tJoystick joy; // joystick
union {
int joyid;
} id; // information on accessing the device
tJoyInfo caps; // controller capabilities
tJoyPos pos; // current position
} tJoystickRecord;
// ---------------------------------------------------------------------------
// globals
static int specificJoy = 0;
static tJoystickRecord Joysticks[MAX_JOYSTICKS];
static int Joy_initialized = 0; // is our joystick system initialized?
void joy_Close();
bool joy_InitRemoteStick(tJoystick joy, char *server_adr, tJoystickRecord *stick);
void joy_GetState(tJoystick stick, tJoyPos *pos);
void joy_GetRemoteState(tJoystick stick, tJoyPos *pos);
int joyGetNumDevs(void);
// closes a stick
// closes connection with controller.
void joy_CloseStick(tJoystick joy);
// initializes a joystick
// if server_adr is valid, a link is opened to another machine with a controller.
bool joy_InitStick(tJoystick joy, char *server_adr);
// ---------------------------------------------------------------------------
// functions
// joystick system initialization
bool joy_Init(bool remote) {
int i;
// reinitialize joystick if already initialized.
if (Joy_initialized) {
joy_Close();
} else {
atexit(joy_Close);
}
// check if this OS supports joysticks
if (!joyGetNumDevs() && !remote) {
Joy_initialized = 0;
return false;
}
Joy_initialized = 1;
// rcg06182000 specific joystick support.
if (specificJoy) {
Joysticks[0].valid = false;
joy_InitStick((tJoystick)0, NULL);
} // if
else {
// initialize joystick list
for (i = 0; i < MAX_JOYSTICKS; i++) {
Joysticks[i].valid = false;
joy_InitStick((tJoystick)i, NULL);
}
} // else
return true;
}
void joy_Close() {
int i;
for (i = 0; i < MAX_JOYSTICKS; i++)
if (Joysticks[i].valid)
joy_CloseStick((i == 0) ? JOYSTICK_1 : (i == 1) ? JOYSTICK_2 : JOYSTICK_1);
}
// initializes a joystick
// if server_adr is valid, a link is opened to another machine with a controller.
bool joy_InitStick(tJoystick joy, char *server_adr) {
ASSERT(Joy_initialized);
// close down already open joystick.
if (Joysticks[(int)joy].valid)
joy_CloseStick(joy);
// okay, now if this is a remote joystick, open it
if (server_adr) {
return joy_InitRemoteStick(joy, server_adr, &Joysticks[(int)joy]);
} else {
int fd;
char joy_dev[32];
int num_of_axis = 0, num_of_buttons = 0;
char name_of_joystick[80];
// rcg06182000 specific joy support.
if (specificJoy)
strcpy(joy_dev, GameArgs[FindArgChar("-joystick", 'j') + 1]);
else
sprintf(joy_dev, "%s%d", JOY_DEV, (int)joy);
if ((fd = open(joy_dev, O_RDONLY)) == -1) {
if (errno == EBUSY) {
mprintf((0, "JOYSTICK: Couldn't open joystick %d, in use.", joy));
}
return false;
}
// determine what version of the joystick driver we are using
unsigned int version = 0;
ioctl(fd, JSIOCGVERSION, &version);
if (version < 0x10000) {
Joysticks[joy].use_old_driver = true;
} else {
Joysticks[joy].use_old_driver = false;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
if (Joysticks[joy].use_old_driver) {
num_of_axis = 2;
num_of_buttons = 2;
strcpy(name_of_joystick, "Generic");
mprintf((0, "Joystick %d opened: Using OLD JOYSTICK driver, %d buttons and %d axis\n", (int)joy, num_of_buttons,
num_of_axis));
Joysticks[joy].caps.minx = 0;
Joysticks[joy].caps.maxx = 255;
Joysticks[joy].caps.miny = 0;
Joysticks[joy].caps.maxy = 255;
Joysticks[joy].caps.minz = 0;
Joysticks[joy].caps.maxz = 255;
Joysticks[joy].caps.minr = 0;
Joysticks[joy].caps.maxr = 255;
Joysticks[joy].caps.minu = -32767;
Joysticks[joy].caps.maxu = 32767;
Joysticks[joy].caps.minv = -32767;
Joysticks[joy].caps.maxv = 32767;
} else {
ioctl(fd, JSIOCGAXES, &num_of_axis);
ioctl(fd, JSIOCGBUTTONS, &num_of_buttons);
ioctl(fd, JSIOCGNAME(80), &name_of_joystick);
mprintf((0, "Joystick %d opened: %s with %d buttons and %d axis\n", (int)joy, name_of_joystick, num_of_buttons,
num_of_axis));
Joysticks[joy].caps.minx = -32767;
Joysticks[joy].caps.maxx = 32767;
Joysticks[joy].caps.miny = -32767;
Joysticks[joy].caps.maxy = 32767;
Joysticks[joy].caps.minz = -32767;
Joysticks[joy].caps.maxz = 32767;
Joysticks[joy].caps.minr = -32767;
Joysticks[joy].caps.maxr = 32767;
Joysticks[joy].caps.minu = -32767;
Joysticks[joy].caps.maxu = 32767;
Joysticks[joy].caps.minv = -32767;
Joysticks[joy].caps.maxv = 32767;
}
Joysticks[joy].valid = true;
Joysticks[joy].remote = false;
Joysticks[joy].joy = joy;
Joysticks[joy].id.joyid = fd;
strcpy(Joysticks[joy].caps.name, name_of_joystick);
Joysticks[joy].caps.num_btns = num_of_buttons;
Joysticks[joy].caps.axes_mask = JOYFLAG_XVALID | JOYFLAG_YVALID;
if (num_of_axis > 2)
Joysticks[joy].caps.axes_mask |= JOYFLAG_ZVALID;
if (num_of_axis > 3)
Joysticks[joy].caps.axes_mask |= JOYFLAG_RVALID;
if (num_of_axis > 4) {
// rcg06182000 God, I hope this works.
// rcg06182000 Attempt to hack 2 more axes into this driver...
// rcg06182000 Before, it was just JOYFLAG_POVVALID...
Joysticks[joy].caps.axes_mask |= JOYFLAG_UVALID;
Joysticks[joy].caps.axes_mask |= JOYFLAG_VVALID;
Joysticks[joy].caps.axes_mask |= JOYFLAG_POVVALID;
} // if
memset(&Joysticks[joy].pos, 0, sizeof(tJoyPos));
return true;
}
return false;
}
// this function takes a server address and tries to initialize a stick that's on a machine
// running the remote control server.
bool joy_InitRemoteStick(tJoystick joy, char *server_adr, tJoystickRecord *stick) { return false; }
// closes a stick
// closes connection with controller.
void joy_CloseStick(tJoystick joy) {
ASSERT(Joysticks[(int)joy].valid);
if (Joysticks[(int)joy].remote) {
}
// CLOSE joystick here
close(Joysticks[(int)joy].id.joyid);
Joysticks[(int)joy].valid = false;
}
// returns true if joystick valid
bool joy_IsValid(tJoystick joy) {
if (Joysticks[(int)joy].valid)
return true;
else
return false;
}
// retreive information about joystick.
void joy_GetJoyInfo(tJoystick joy, tJoyInfo *info) {
ASSERT(Joy_initialized);
if (Joysticks[(int)joy].valid) {
memcpy(info, &Joysticks[(int)joy].caps, sizeof(tJoyInfo));
} else
Int3(); // This should never happen.
}
// retreive uncalibrated position of joystick
#define LNX_JOYAXIS_RANGE 65535
void joy_GetRawPos(tJoystick joy, tJoyPos *pos) {
joy_GetPos(joy, pos);
if (!Joysticks[joy].use_old_driver) {
pos->x = (pos->x + 32767);
pos->y = (pos->y + 32767);
pos->z = (pos->z + 32767);
pos->r = (pos->r + 32767);
pos->u = (pos->u + 32767);
pos->v = (pos->v + 32767);
}
}
// returns the state of a stick, remote or otherwise
void joy_GetPos(tJoystick stick, tJoyPos *pos) {
int i;
for (i = 0; i < JOYPOV_NUM; i++) {
pos->pov[i] = 0;
}
pos->x = 0;
pos->y = 0;
pos->z = 0;
pos->r = 0;
pos->u = 0;
pos->v = 0;
pos->buttons = 0;
pos->btn = 0;
if (!Joy_initialized)
return;
if (!Joysticks[(int)stick].valid)
return;
// retrieve joystick info from the net, or locally.
if (Joysticks[(int)stick].remote) {
joy_GetRemoteState(stick, pos);
} else {
memcpy(pos, &Joysticks[(int)stick].pos, sizeof(tJoyPos));
}
}
// returns the position of a remote stick.
void joy_GetRemoteState(tJoystick stick, tJoyPos *pos) {}
int joyGetNumDevs(void) {
int found = 0;
int count = 0, fd;
char joy_dev[80];
// rcg06182000 add support for specific joydev.
int rc = FindArgChar("-joystick", 'j');
if ((rc > 0) && (GameArgs[rc + 1] != NULL)) {
fd = open(GameArgs[rc + 1], O_RDONLY);
if (fd != -1) {
specificJoy = 1;
close(fd);
return (1);
} // if
} // if
// rcg end addition
for (count = 0; count < MAX_JOYSTICKS; count++) {
sprintf(joy_dev, "%s%d", JOY_DEV, count);
fd = open(joy_dev, O_RDONLY);
if (fd != -1) {
found++;
close(fd);
}
}
mprintf((0, "Joystick: Found %d joysticks.", found));
return found;
}
void ddio_InternalJoyFrame(void) {
int joy;
for (joy = 0; joy < MAX_JOYSTICKS; joy++) {
if (!Joysticks[joy].valid)
continue;
int count = 0;
struct js_event js;
struct JS_DATA_TYPE old_js;
fd_set watchset;
tJoyPos *pos;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
int new_pov = 0x0000;
#define PV_UP 0x01
#define PV_DOWN 0x02
#define PV_LEFT 0x04
#define PV_RIGHT 0x08
pos = &Joysticks[joy].pos;
switch (pos->pov[0]) {
case 0x00: // up
new_pov = PV_UP;
break;
case 0x20: // up-right;
new_pov = PV_UP | PV_RIGHT;
break;
case 0x40: // right
new_pov = PV_RIGHT;
break;
case 0x60: // down-right
new_pov = PV_DOWN | PV_RIGHT;
break;
case 0x80: // down
new_pov = PV_DOWN;
break;
case 0xA0: // down-left
new_pov = PV_DOWN | PV_LEFT;
break;
case 0xC0: // left
new_pov = PV_LEFT;
break;
case 0xE0: // up-left
new_pov = PV_UP | PV_LEFT;
break;
}
FD_ZERO(&watchset);
FD_SET(Joysticks[joy].id.joyid, &watchset);
while (1 && count < 50) {
if (select(Joysticks[joy].id.joyid + 1, &watchset, NULL, NULL, &tv) < 0) {
perror("Error reading joystick file descriptor \n");
break;
}
if (!FD_ISSET(Joysticks[joy].id.joyid, &watchset))
break; // done reading, nothing waiting
if (Joysticks[joy].use_old_driver) {
if (read(Joysticks[joy].id.joyid, &old_js, JS_RETURN) != JS_RETURN) {
break;
}
pos->x = old_js.x;
pos->y = old_js.y;
pos->buttons = 0;
pos->buttons |= (old_js.buttons & 1) ? 0x01 : 0;
pos->buttons |= (old_js.buttons & 2) ? 0x02 : 0;
break;
} else {
// read the joystick state
read(Joysticks[joy].id.joyid, &js, sizeof(struct js_event));
// see what to do with the event
switch (js.type & ~JS_EVENT_INIT) {
case JS_EVENT_AXIS:
switch (js.number) {
case 0: // X Axis
pos->x = js.value;
break;
case 1: // Y Axis
pos->y = js.value;
break;
case 2: // Z Axis
pos->z = js.value;
break;
case 3: // R Axis
pos->r = js.value;
break;
case 4: // POV U Axis
// rcg 06152000 set pos->u. Wasn't here. !?
pos->u = js.value;
new_pov &= ~(PV_LEFT | PV_RIGHT);
if (js.value > 0) {
// mprintf((0,"POV RIGHT\n"));
new_pov |= PV_RIGHT;
} else if (js.value < 0) {
// mprintf((0,"POV LEFT\n"));
new_pov |= PV_LEFT;
}
break;
case 5: // POV V Axis
// rcg 06152000 set pos->v. Wasn't here. !?
pos->v = js.value;
new_pov &= ~(PV_UP | PV_DOWN);
if (js.value > 0) {
// mprintf((0,"POV DOWN\n"));
new_pov |= PV_DOWN;
} else if (js.value < 0) {
// mprintf((0,"POV UP\n"));
new_pov |= PV_UP;
}
break;
}
break;
case JS_EVENT_BUTTON:
int bit;
bit = 0x01;
bit = bit << js.number;
if (js.value) {
// button push
pos->buttons |= bit;
} else {
// button release
pos->buttons &= ~bit;
}
break;
}
}
count++;
}
if (count == 50) {
// mprintf((0,"JOYSTICK BREAK!\n"));
}
// recalc pov
switch (new_pov) {
case 0: // center
pos->pov[0] = JOYPOV_CENTER;
break;
case PV_UP:
pos->pov[0] = 0x00;
break;
case PV_UP | PV_RIGHT:
pos->pov[0] = 0x20;
break;
case PV_RIGHT:
pos->pov[0] = 0x40;
break;
case PV_DOWN | PV_RIGHT:
pos->pov[0] = 0x60;
break;
case PV_DOWN:
pos->pov[0] = 0x80;
break;
case PV_DOWN | PV_LEFT:
pos->pov[0] = 0xA0;
break;
case PV_LEFT:
pos->pov[0] = 0xC0;
break;
case PV_UP | PV_LEFT:
pos->pov[0] = 0xE0;
break;
}
}
}