2024-04-20 15:57:49 +00:00
|
|
|
/*
|
|
|
|
* Descent 3
|
|
|
|
* Copyright (C) 2024 Parallax Software
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
/*
|
|
|
|
* joystick header
|
|
|
|
*
|
|
|
|
* $NoKeywords: $
|
|
|
|
*/
|
|
|
|
#include "joystick.h"
|
|
|
|
#include "pserror.h"
|
|
|
|
#include "pstypes.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2024-04-16 18:56:40 +00:00
|
|
|
typedef struct tJoystickRecord {
|
|
|
|
bool valid; // is this a valid device.
|
|
|
|
bool remote; // is this device on another computer
|
|
|
|
tJoystick joy; // joystick
|
|
|
|
union {
|
2024-04-16 03:43:29 +00:00
|
|
|
int joyid;
|
2024-04-16 18:56:40 +00:00
|
|
|
// SOCKET joysock;
|
|
|
|
} id; // information on accessing the device
|
|
|
|
tJoyInfo caps; // controller capabilities
|
|
|
|
tJoyPos pos; // current position
|
|
|
|
} tJoystickRecord;
|
2024-04-16 03:43:29 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// globals
|
|
|
|
static tJoystickRecord Joysticks[MAX_JOYSTICKS];
|
2024-04-16 18:56:40 +00:00
|
|
|
int Joy_initialized = 0; // is our joystick system initialized?
|
2024-04-16 03:43:29 +00:00
|
|
|
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);
|
2024-04-16 18:56:40 +00:00
|
|
|
int joyGetNumDevs(void);
|
2024-04-16 03:43:29 +00:00
|
|
|
// closes a stick
|
|
|
|
// closes connection with controller.
|
|
|
|
void joy_CloseStick(tJoystick joy);
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// functions
|
|
|
|
// joystick system initialization
|
2024-04-16 18:56:40 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize joystick list
|
|
|
|
for (i = 0; i < MAX_JOYSTICKS; i++)
|
|
|
|
Joysticks[i].valid = false;
|
|
|
|
|
|
|
|
Joy_initialized = 1;
|
|
|
|
|
|
|
|
return true;
|
2024-04-16 03:43:29 +00:00
|
|
|
}
|
2024-04-16 18:56:40 +00:00
|
|
|
void joy_Close() {
|
2024-04-16 03:43:29 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_JOYSTICKS; i++)
|
|
|
|
if (Joysticks[i].valid)
|
2024-04-16 18:56:40 +00:00
|
|
|
joy_CloseStick((i == 0) ? JOYSTICK_1 : (i == 1) ? JOYSTICK_2 : JOYSTICK_1);
|
2024-04-16 03:43:29 +00:00
|
|
|
}
|
|
|
|
// initializes a joystick
|
|
|
|
// if server_adr is valid, a link is opened to another machine with a controller.
|
2024-04-16 18:56:40 +00:00
|
|
|
bool joy_InitStick(tJoystick joy, char *server_adr) {
|
2024-04-16 03:43:29 +00:00
|
|
|
ASSERT(Joy_initialized);
|
|
|
|
// close down already open joystick.
|
2024-04-16 18:56:40 +00:00
|
|
|
if (Joysticks[(int)joy].valid)
|
2024-04-16 03:43:29 +00:00
|
|
|
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]);
|
2024-04-16 18:56:40 +00:00
|
|
|
} else if (joyGetNumDevs() == 0) {
|
2024-04-16 03:43:29 +00:00
|
|
|
return false;
|
2024-04-16 18:56:40 +00:00
|
|
|
} else {
|
|
|
|
// OPEN JOYSTICK HERE!
|
|
|
|
// Setup struct
|
2024-04-16 03:43:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
return false;
|
|
|
|
}
|
2024-04-16 18:56:40 +00:00
|
|
|
// 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) {
|
2024-04-16 03:43:29 +00:00
|
|
|
/*
|
|
|
|
sockaddr_in servaddr;
|
|
|
|
int adr[4];
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
ASSERT(server_adr);
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
Joysticks[(int)joy].id.joysock = socket(AF_INET, SOCK_STREAM, 0);
|
2024-04-16 18:56:40 +00:00
|
|
|
if (Joysticks[(int)joy].id.joysock == INVALID_SOCKET)
|
2024-04-16 03:43:29 +00:00
|
|
|
return false;
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
sscanf(server_adr, "%d.%d.%d.%d", &adr[0], &adr[1], &adr[2], &adr[3]);
|
|
|
|
mprintf((0, "Connecting to remote control on %d.%d.%d.%d...\n", adr[0],adr[1],adr[2],adr[3]));
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
servaddr.sin_family = AF_INET;
|
|
|
|
servaddr.sin_port = JOY_PORT;
|
|
|
|
servaddr.sin_addr.S_un.S_un_b.s_b1 = (ubyte)adr[0];
|
|
|
|
servaddr.sin_addr.S_un.S_un_b.s_b2 = (ubyte)adr[1];
|
|
|
|
servaddr.sin_addr.S_un.S_un_b.s_b3 = (ubyte)adr[2];
|
|
|
|
servaddr.sin_addr.S_un.S_un_b.s_b4 = (ubyte)adr[3];
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
if (connect(Joysticks[(int)joy].id.joysock, (struct sockaddr *)&servaddr, sizeof(servaddr)) == SOCKET_ERROR) {
|
|
|
|
shutdown(Joysticks[(int)joy].id.joysock, 1);
|
|
|
|
closesocket(Joysticks[(int)joy].id.joysock);
|
|
|
|
Joysticks[(int)joy].valid = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tJoyPacket packet;
|
|
|
|
LINGER linger;
|
|
|
|
int res;
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
linger.l_onoff = 1;
|
|
|
|
linger.l_linger = 2;
|
|
|
|
setsockopt(Joysticks[(int)joy].id.joysock, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(linger));
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
Joysticks[(int)joy].valid = true;
|
|
|
|
Joysticks[(int)joy].remote = true;
|
|
|
|
Joysticks[(int)joy].joy = joy;
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
// now wait to receive acknowledgement packet (joystick info will be stored here in a tJoyInfo format) "INFO"
|
|
|
|
res = recv(Joysticks[(int)joy].id.joysock, (char *)&packet, sizeof(tJoyInfo) + strlen(JOY_INFO),0);
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
if ( res == SOCKET_ERROR || !res) {
|
|
|
|
shutdown(Joysticks[(int)joy].id.joysock, 1);
|
|
|
|
closesocket(Joysticks[(int)joy].id.joysock);
|
|
|
|
Joysticks[(int)joy].valid = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
mprintf((0, "RECV %c%c%c%c \n", packet.coda[0], packet.coda[1], packet.coda[2], packet.coda[3]));
|
|
|
|
if (memcmp(packet.coda, JOY_INFO, strlen(JOY_INFO)) != 0) {
|
|
|
|
mprintf((0, "Received non information packet from control server.\n"));
|
|
|
|
shutdown(Joysticks[(int)joy].id.joysock, 1);
|
|
|
|
closesocket(Joysticks[(int)joy].id.joysock);
|
|
|
|
Joysticks[(int)joy].valid = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
memcpy(&Joysticks[(int)joy].caps, packet.buf, sizeof(tJoyInfo));
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
// start polling. send "POLL"
|
|
|
|
memcpy(packet.coda, JOY_POLL, strlen(JOY_POLL));
|
|
|
|
send(Joysticks[(int)joy].id.joysock, (char *)&packet, strlen(JOY_POLL), 0);
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
// start packet read thread.
|
|
|
|
//@@ Thread_running[(int)joy] = false;
|
|
|
|
//@@ unsigned thread_id;
|
2024-04-16 20:59:11 +00:00
|
|
|
//@@ unsigned long thread_handle = _beginthreadex(NULL, 0, joy_ReadRemotePacket,
|
|
|
|
&Joysticks[(int)joy], 1, &thread_id);
|
2024-04-16 03:43:29 +00:00
|
|
|
//@@ if (thread_handle == 0) {
|
|
|
|
//@@ Error("Remote joystick thread creation failed.");
|
|
|
|
//@@ }
|
|
|
|
//@@
|
2024-04-16 18:56:40 +00:00
|
|
|
//@@ if (SetThreadPriority((HANDLE)thread_handle, THREAD_PRIORITY_NORMAL) == FALSE)
|
2024-04-16 03:43:29 +00:00
|
|
|
//@@ Error("Remote joystick thread prioritization failed.");
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// closes a stick
|
|
|
|
// closes connection with controller.
|
2024-04-16 18:56:40 +00:00
|
|
|
void joy_CloseStick(tJoystick joy) {
|
2024-04-16 03:43:29 +00:00
|
|
|
ASSERT(Joysticks[(int)joy].valid);
|
|
|
|
if (Joysticks[(int)joy].remote) {
|
|
|
|
//@@ u_long arg = 1;
|
|
|
|
//@@ ioctlsocket(Joysticks[(int)joy].id.joysock, FIONBIO, &arg);
|
|
|
|
//@@ Thread_running[(int)joy] = false;
|
|
|
|
//@@ Sleep(200);
|
2024-04-16 18:56:40 +00:00
|
|
|
// shutdown(Joysticks[(int)joy].id.joysock, 1);
|
|
|
|
// closesocket(Joysticks[(int)joy].id.joysock);
|
2024-04-16 03:43:29 +00:00
|
|
|
}
|
2024-04-16 18:56:40 +00:00
|
|
|
// CLOSE joystick here
|
2024-04-16 03:43:29 +00:00
|
|
|
Joysticks[(int)joy].valid = false;
|
|
|
|
}
|
|
|
|
// returns true if joystick valid
|
2024-04-16 18:56:40 +00:00
|
|
|
bool joy_IsValid(tJoystick joy) {
|
|
|
|
if (Joysticks[(int)joy].valid)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
2024-04-16 03:43:29 +00:00
|
|
|
}
|
|
|
|
// retreive information about joystick.
|
2024-04-16 18:56:40 +00:00
|
|
|
void joy_GetJoyInfo(tJoystick joy, tJoyInfo *info) {
|
2024-04-16 03:43:29 +00:00
|
|
|
ASSERT(Joy_initialized);
|
|
|
|
if (Joysticks[(int)joy].valid) {
|
|
|
|
memcpy(info, &Joysticks[(int)joy].caps, sizeof(tJoyInfo));
|
2024-04-16 18:56:40 +00:00
|
|
|
} else
|
|
|
|
Int3(); // This should never happen.
|
2024-04-16 03:43:29 +00:00
|
|
|
}
|
|
|
|
// retreive uncalibrated position of joystick
|
2024-04-16 18:56:40 +00:00
|
|
|
void joy_GetRawPos(tJoystick joy, tJoyPos *pos) {
|
2024-04-16 03:43:29 +00:00
|
|
|
joy_GetPos(joy, pos);
|
2024-04-16 18:56:40 +00:00
|
|
|
pos->x = (pos->x + 128) * JOYAXIS_RANGE;
|
|
|
|
pos->y = (pos->y + 128) * JOYAXIS_RANGE;
|
|
|
|
pos->z = (pos->z + 128) * JOYAXIS_RANGE;
|
|
|
|
pos->r = (pos->r + 128) * JOYAXIS_RANGE;
|
|
|
|
pos->u = (pos->u + 128) * JOYAXIS_RANGE;
|
|
|
|
pos->v = (pos->v + 128) * JOYAXIS_RANGE;
|
2024-04-16 03:43:29 +00:00
|
|
|
}
|
|
|
|
// returns the state of a stick, remote or otherwise
|
2024-04-16 18:56:40 +00:00
|
|
|
void joy_GetPos(tJoystick stick, tJoyPos *pos) {
|
|
|
|
// ASSERT(Joy_initialized);
|
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
pos->x = 0;
|
|
|
|
pos->y = 0;
|
|
|
|
pos->z = 0;
|
|
|
|
pos->r = 0;
|
|
|
|
pos->u = 0;
|
|
|
|
pos->v = 0;
|
|
|
|
pos->pov[0] = 0;
|
|
|
|
pos->pov[1] = 0;
|
|
|
|
pos->pov[2] = 0;
|
|
|
|
pos->pov[3] = 0;
|
|
|
|
pos->buttons = 0;
|
|
|
|
pos->btn = 0;
|
2024-04-16 18:56:40 +00:00
|
|
|
|
|
|
|
if (!Joysticks[(int)stick].valid)
|
2024-04-16 03:43:29 +00:00
|
|
|
return;
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
// retrieve joystick info from the net, or locally.
|
|
|
|
if (Joysticks[(int)stick].remote) {
|
|
|
|
joy_GetRemoteState(stick, pos);
|
2024-04-16 18:56:40 +00:00
|
|
|
} else {
|
|
|
|
// READ JOYSTICK HERE!!!!!!!!!!!
|
2024-04-16 03:43:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// returns the position of a remote stick.
|
2024-04-16 18:56:40 +00:00
|
|
|
void joy_GetRemoteState(tJoystick stick, tJoyPos *pos) {
|
2024-04-16 03:43:29 +00:00
|
|
|
/*
|
|
|
|
ASSERT(Joysticks[(int)stick].remote);
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
tJoyPacket packet;
|
|
|
|
// get next POSI packet
|
|
|
|
recv(Joysticks[(int)stick].id.joysock, (char *)packet.coda, strlen(JOY_POS),0);
|
|
|
|
if (memcmp(packet.coda, JOY_POS, strlen(JOY_POS)) == 0) {
|
|
|
|
recv(Joysticks[(int)stick].id.joysock, (char *)packet.buf, sizeof(tJoyPos),0);
|
|
|
|
memcpy(&Joysticks[(int)stick].pos, packet.buf, sizeof(tJoyPos));
|
|
|
|
}
|
2024-04-16 18:56:40 +00:00
|
|
|
pos->x = (int)((Joysticks[(int)stick].pos.x<<8)/(Joysticks[(int)stick].caps.maxx - Joysticks[(int)stick].caps.minx)) -
|
|
|
|
128; pos->y = (int)((Joysticks[(int)stick].pos.y<<8)/(Joysticks[(int)stick].caps.maxy -
|
|
|
|
Joysticks[(int)stick].caps.miny)) - 128; if (Joysticks[(int)stick].caps.axes_mask & JOYFLAG_ZVALID) pos->z =
|
|
|
|
(int)((Joysticks[(int)stick].pos.z<<8)/(Joysticks[(int)stick].caps.maxz - Joysticks[(int)stick].caps.minz)) - 128;
|
|
|
|
else
|
2024-04-16 03:43:29 +00:00
|
|
|
pos->z = 0;
|
2024-04-16 18:56:40 +00:00
|
|
|
if (Joysticks[(int)stick].caps.axes_mask & JOYFLAG_RVALID)
|
|
|
|
pos->r = (int)((Joysticks[(int)stick].pos.r<<8)/(Joysticks[(int)stick].caps.maxr - Joysticks[(int)stick].caps.minr))
|
|
|
|
- 128; else pos->r = 0; if (Joysticks[(int)stick].caps.axes_mask & JOYFLAG_UVALID) pos->u =
|
|
|
|
(int)((Joysticks[(int)stick].pos.u<<8)/(Joysticks[(int)stick].caps.maxu - Joysticks[(int)stick].caps.minu)) - 128;
|
|
|
|
else
|
2024-04-16 03:43:29 +00:00
|
|
|
pos->u = 0;
|
2024-04-16 18:56:40 +00:00
|
|
|
if (Joysticks[(int)stick].caps.axes_mask & JOYFLAG_VVALID)
|
|
|
|
pos->v = (int)((Joysticks[(int)stick].pos.v<<8)/(Joysticks[(int)stick].caps.maxv - Joysticks[(int)stick].caps.minv))
|
|
|
|
- 128; else pos->v = 0; if (Joysticks[(int)stick].caps.axes_mask & JOYFLAG_POVVALID) { pos->pov =
|
|
|
|
(Joysticks[(int)stick].pos.pov == JOY_POVBACKWARD) ? JOYPOV_DOWN : (Joysticks[(int)stick].pos.pov == JOY_POVFORWARD) ?
|
|
|
|
JOYPOV_UP : (Joysticks[(int)stick].pos.pov == JOY_POVLEFT) ? JOYPOV_LEFT : (Joysticks[(int)stick].pos.pov ==
|
|
|
|
JOY_POVRIGHT) ? JOYPOV_RIGHT : JOYPOV_CENTER;
|
2024-04-16 03:43:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
pos->pov = JOYPOV_CENTER;
|
|
|
|
pos->buttons = (unsigned)Joysticks[(int)stick].pos.buttons;
|
|
|
|
pos->btn = (unsigned)Joysticks[(int)stick].pos.btn;
|
2024-04-16 18:56:40 +00:00
|
|
|
|
2024-04-16 03:43:29 +00:00
|
|
|
// request poll for next packet POLL
|
|
|
|
memcpy(packet.coda, JOY_POLL, strlen(JOY_POLL));
|
|
|
|
send(Joysticks[(int)stick].id.joysock, (char *)&packet, strlen(JOY_POLL), 0);
|
|
|
|
*/
|
|
|
|
}
|
2024-04-16 18:56:40 +00:00
|
|
|
void ddio_InternalJoySuspend(void) {}
|
|
|
|
void ddio_InternalJoyResume(void) {}
|
|
|
|
int joyGetNumDevs(void) { return 0; }
|
|
|
|
void ddio_InternalJoyFrame(void) {}
|