summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/cl_main.c2
-rw-r--r--src/client/cl_parse.c28
-rw-r--r--src/client/snd_codec.c15
-rw-r--r--src/client/snd_codec_ogg.c9
-rw-r--r--src/client/snd_openal.c1
-rw-r--r--src/qcommon/common.c5
-rw-r--r--src/qcommon/files.c52
-rw-r--r--src/qcommon/md4.c4
-rw-r--r--src/qcommon/msg.c9
-rw-r--r--src/qcommon/net_chan.c66
-rw-r--r--src/qcommon/qcommon.h5
-rw-r--r--src/qcommon/vm_ppc_new.c8
-rw-r--r--src/server/server.h1
-rw-r--r--src/server/sv_client.c6
-rw-r--r--src/server/sv_init.c1
-rw-r--r--src/server/sv_main.c1
-rw-r--r--src/server/sv_snapshot.c7
-rw-r--r--src/unix/sdl_glimp.c141
18 files changed, 306 insertions, 55 deletions
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index 6e0cdaff..3390ead5 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -1403,7 +1403,7 @@ void CL_NextDownload(void) {
*s++ = 0;
else
s = localName + strlen(localName); // point at the nul byte
-
+
CL_BeginDownload( localName, remoteName );
clc.downloadRestart = qtrue;
diff --git a/src/client/cl_parse.c b/src/client/cl_parse.c
index 7f219b32..dc14cd66 100644
--- a/src/client/cl_parse.c
+++ b/src/client/cl_parse.c
@@ -256,6 +256,13 @@ void CL_ParseSnapshot( msg_t *msg ) {
// read areamask
len = MSG_ReadByte( msg );
+
+ if(len > sizeof(newSnap.areamask))
+ {
+ Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask.", len);
+ return;
+ }
+
MSG_ReadData( msg, &newSnap.areamask, len);
// read playerinfo
@@ -476,6 +483,12 @@ void CL_ParseDownload ( msg_t *msg ) {
unsigned char data[MAX_MSGLEN];
int block;
+ if (!*clc.downloadTempName) {
+ Com_Printf("Server sending download, but no download was requested\n");
+ CL_AddReliableCommand( "stopdl" );
+ return;
+ }
+
// read the data
block = MSG_ReadShort ( msg );
@@ -494,8 +507,13 @@ void CL_ParseDownload ( msg_t *msg ) {
}
size = MSG_ReadShort ( msg );
- if (size > 0)
- MSG_ReadData( msg, data, size );
+ if (size < 0 || size > sizeof(data))
+ {
+ Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size);
+ return;
+ }
+
+ MSG_ReadData(msg, data, size);
if (clc.downloadBlock != block) {
Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block);
@@ -505,12 +523,6 @@ void CL_ParseDownload ( msg_t *msg ) {
// open the file if not opened yet
if (!clc.download)
{
- if (!*clc.downloadTempName) {
- Com_Printf("Server sending download, but no download was requested\n");
- CL_AddReliableCommand( "stopdl" );
- return;
- }
-
clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
if (!clc.download) {
diff --git a/src/client/snd_codec.c b/src/client/snd_codec.c
index 98fae65f..088236a4 100644
--- a/src/client/snd_codec.c
+++ b/src/client/snd_codec.c
@@ -34,13 +34,16 @@ S_FileExtension
*/
static char *S_FileExtension(const char *fni)
{
- char *fn = (char *)fni;
+ // we should search from the ending to the last '/'
+
+ char *fn = (char *) fni + strlen(fni) - 1;
char *eptr = NULL;
- while(*fn)
+
+ while(*fn != '/' && fn != fni)
{
if(*fn == '.')
eptr = fn;
- fn++;
+ fn--;
}
return eptr;
@@ -64,8 +67,10 @@ static snd_codec_t *S_FindCodecForFile(const char *filename)
while(codec)
{
char fn[MAX_QPATH];
- Q_strncpyz(fn, filename, sizeof(fn) - 4);
- COM_DefaultExtension(fn, sizeof(fn), codec->ext);
+
+ // there is no extension so we do not need to subtract 4 chars
+ Q_strncpyz(fn, filename, MAX_QPATH);
+ COM_DefaultExtension(fn, MAX_QPATH, codec->ext);
// Check it exists
if(FS_ReadFile(fn, NULL) != -1)
diff --git a/src/client/snd_codec_ogg.c b/src/client/snd_codec_ogg.c
index 9c17c0b9..72ece944 100644
--- a/src/client/snd_codec_ogg.c
+++ b/src/client/snd_codec_ogg.c
@@ -360,6 +360,13 @@ int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
// Bitstream for the decoder
int BS = 0;
+ // big endian machines want their samples in big endian order
+ int IsBigEndian = 0;
+
+# ifdef Q3_BIG_ENDIAN
+ IsBigEndian = 1;
+# endif // Q3_BIG_ENDIAN
+
// check if input is valid
if(!(stream && buffer))
{
@@ -379,7 +386,7 @@ int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
while(-1)
{
// read some bytes from the OGG codec
- c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, 0, OGG_SAMPLEWIDTH, 1, &BS);
+ c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, IsBigEndian, OGG_SAMPLEWIDTH, 1, &BS);
// no more bytes are left
if(c <= 0)
diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c
index c44f1e0a..c71a58ee 100644
--- a/src/client/snd_openal.c
+++ b/src/client/snd_openal.c
@@ -1539,6 +1539,7 @@ void S_AL_StopAllSounds( void )
{
S_AL_SrcShutup();
S_AL_StopBackgroundTrack();
+ S_AL_StreamDie();
}
/*
diff --git a/src/qcommon/common.c b/src/qcommon/common.c
index 44174ead..a33eb6fd 100644
--- a/src/qcommon/common.c
+++ b/src/qcommon/common.c
@@ -77,6 +77,8 @@ cvar_t *com_blood;
cvar_t *com_buildScript; // for automated data building scripts
cvar_t *cl_paused;
cvar_t *sv_paused;
+cvar_t *cl_packetdelay;
+cvar_t *sv_packetdelay;
cvar_t *com_cameraMode;
#if defined(_WIN32) && defined(_DEBUG)
cvar_t *com_noErrorInterrupt;
@@ -2085,6 +2087,7 @@ int Com_EventLoop( void ) {
MSG_Init( &buf, bufData, sizeof( bufData ) );
while ( 1 ) {
+ NET_FlushPacketQueue();
ev = Com_GetEvent();
// if no more events are available
@@ -2358,6 +2361,8 @@ void Com_Init( char *commandLine ) {
cl_paused = Cvar_Get ("cl_paused", "0", CVAR_ROM);
sv_paused = Cvar_Get ("sv_paused", "0", CVAR_ROM);
+ cl_packetdelay = Cvar_Get ("cl_packetdelay", "0", CVAR_CHEAT);
+ sv_packetdelay = Cvar_Get ("sv_packetdelay", "0", CVAR_CHEAT);
com_sv_running = Cvar_Get ("sv_running", "0", CVAR_ROM);
com_cl_running = Cvar_Get ("cl_running", "0", CVAR_ROM);
com_buildScript = Cvar_Get( "com_buildScript", "0", 0 );
diff --git a/src/qcommon/files.c b/src/qcommon/files.c
index c5b46607..9e9d21d0 100644
--- a/src/qcommon/files.c
+++ b/src/qcommon/files.c
@@ -2591,15 +2591,16 @@ we are not interested in a download string format, we want something human-reada
qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
searchpath_t *sp;
qboolean havepak, badchecksum;
+ char *origpos = neededpaks;
int i;
- if ( !fs_numServerReferencedPaks ) {
+ if (!fs_numServerReferencedPaks)
return qfalse; // Server didn't send any pack information along
- }
*neededpaks = 0;
- for ( i = 0 ; i < fs_numServerReferencedPaks ; i++ ) {
+ for ( i = 0 ; i < fs_numServerReferencedPaks ; i++ )
+ {
// Ok, see if we have this pak file
badchecksum = qfalse;
havepak = qfalse;
@@ -2609,6 +2610,13 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
continue;
}
+ // Make sure the server cannot make us write to non-quake3 directories.
+ if(strstr(fs_serverReferencedPakNames[i], "../") || strstr(fs_serverReferencedPakNames[i], "..\\"))
+ {
+ Com_Printf("WARNING: Invalid download name %s\n", fs_serverReferencedPakNames[i]);
+ continue;
+ }
+
for ( sp = fs_searchpaths ; sp ; sp = sp->next ) {
if ( sp->pack && sp->pack->checksum == fs_serverReferencedPaks[i] ) {
havepak = qtrue; // This is it!
@@ -2621,6 +2629,12 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
if (dlstring)
{
+ // We need this to make sure we won't hit the end of the buffer or the server could
+ // overwrite non-pk3 files on clients by writing so much crap into neededpaks that
+ // Q_strcat cuts off the .pk3 extension.
+
+ origpos += strlen(origpos);
+
// Remote name
Q_strcat( neededpaks, len, "@");
Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
@@ -2641,6 +2655,14 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
Q_strcat( neededpaks, len, ".pk3" );
}
+
+ // Find out whether it might have overflowed the buffer and don't add this file to the
+ // list if that is the case.
+ if(strlen(origpos) + (origpos - neededpaks) >= len - 1)
+ {
+ *origpos = '\0';
+ break;
+ }
}
else
{
@@ -3146,7 +3168,7 @@ checksums to see if any pk3 files need to be auto-downloaded.
=====================
*/
void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames ) {
- int i, c, d;
+ int i, c, d = 0;
Cmd_TokenizeString( pakSums );
@@ -3155,30 +3177,36 @@ void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames )
c = MAX_SEARCH_PATHS;
}
- fs_numServerReferencedPaks = c;
-
for ( i = 0 ; i < c ; i++ ) {
fs_serverReferencedPaks[i] = atoi( Cmd_Argv( i ) );
}
- for ( i = 0 ; i < c ; i++ ) {
- if (fs_serverReferencedPakNames[i]) {
+ for (i = 0 ; i < sizeof(fs_serverReferencedPakNames) / sizeof(*fs_serverReferencedPakNames); i++)
+ {
+ if(fs_serverReferencedPakNames[i])
Z_Free(fs_serverReferencedPakNames[i]);
- }
+
fs_serverReferencedPakNames[i] = NULL;
}
+
if ( pakNames && *pakNames ) {
Cmd_TokenizeString( pakNames );
d = Cmd_Argc();
- if ( d > MAX_SEARCH_PATHS ) {
- d = MAX_SEARCH_PATHS;
- }
+
+ if(d > c)
+ d = c;
for ( i = 0 ; i < d ; i++ ) {
fs_serverReferencedPakNames[i] = CopyString( Cmd_Argv( i ) );
}
}
+
+ // ensure that there are as many checksums as there are pak names.
+ if(d < c)
+ c = d;
+
+ fs_numServerReferencedPaks = c;
}
/*
diff --git a/src/qcommon/md4.c b/src/qcommon/md4.c
index 2501b2b6..838b062e 100644
--- a/src/qcommon/md4.c
+++ b/src/qcommon/md4.c
@@ -159,10 +159,10 @@ static void mdfour_update(struct mdfour *md, byte *in, int n)
{
uint32_t M[16];
- if (n == 0) mdfour_tail(in, n);
-
m = md;
+ if (n == 0) mdfour_tail(in, n);
+
while (n >= 64) {
copy64(M, in);
mdfour64(M);
diff --git a/src/qcommon/msg.c b/src/qcommon/msg.c
index da96dab9..e4db4d8e 100644
--- a/src/qcommon/msg.c
+++ b/src/qcommon/msg.c
@@ -469,6 +469,10 @@ char *MSG_ReadBigString( msg_t *msg ) {
if ( c == '%' ) {
c = '.';
}
+ // don't allow higher ascii values
+ if ( c > 127 ) {
+ c = '.';
+ }
string[l] = c;
l++;
@@ -493,6 +497,11 @@ char *MSG_ReadStringLine( msg_t *msg ) {
if ( c == '%' ) {
c = '.';
}
+ // don't allow higher ascii values
+ if ( c > 127 ) {
+ c = '.';
+ }
+
string[l] = c;
l++;
} while (l < sizeof(string)-1);
diff --git a/src/qcommon/net_chan.c b/src/qcommon/net_chan.c
index 4df95c46..9dd41589 100644
--- a/src/qcommon/net_chan.c
+++ b/src/qcommon/net_chan.c
@@ -614,6 +614,62 @@ void NET_SendLoopPacket (netsrc_t sock, int length, const void *data, netadr_t t
//=============================================================================
+typedef struct packetQueue_s {
+ struct packetQueue_s *next;
+ int length;
+ byte *data;
+ netadr_t to;
+ int release;
+} packetQueue_t;
+
+packetQueue_t *packetQueue = NULL;
+
+static void NET_QueuePacket( int length, const void *data, netadr_t to,
+ int offset )
+{
+ packetQueue_t *new, *next = packetQueue;
+
+ if(offset > 999)
+ offset = 999;
+
+ new = S_Malloc(sizeof(packetQueue_t));
+ new->data = S_Malloc(length);
+ Com_Memcpy(new->data, data, length);
+ new->length = length;
+ new->to = to;
+ new->release = Sys_Milliseconds() + offset;
+ new->next = NULL;
+
+ if(!packetQueue) {
+ packetQueue = new;
+ return;
+ }
+ while(next) {
+ if(!next->next) {
+ next->next = new;
+ return;
+ }
+ next = next->next;
+ }
+}
+
+void NET_FlushPacketQueue(void)
+{
+ packetQueue_t *last;
+ int now;
+
+ while(packetQueue) {
+ now = Sys_Milliseconds();
+ if(packetQueue->release >= now)
+ break;
+ Sys_SendPacket(packetQueue->length, packetQueue->data,
+ packetQueue->to);
+ last = packetQueue;
+ packetQueue = packetQueue->next;
+ Z_Free(last->data);
+ Z_Free(last);
+ }
+}
void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to ) {
@@ -630,7 +686,15 @@ void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to )
return;
}
- Sys_SendPacket( length, data, to );
+ if ( sock == NS_CLIENT && cl_packetdelay->integer > 0 ) {
+ NET_QueuePacket( length, data, to, cl_packetdelay->integer );
+ }
+ else if ( sock == NS_SERVER && sv_packetdelay->integer > 0 ) {
+ NET_QueuePacket( length, data, to, sv_packetdelay->integer );
+ }
+ else {
+ Sys_SendPacket( length, data, to );
+ }
}
/*
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index b21b5958..9cb03b6f 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -157,7 +157,7 @@ void NET_Init( void );
void NET_Shutdown( void );
void NET_Restart( void );
void NET_Config( qboolean enableNetworking );
-
+void NET_FlushPacketQueue(void);
void NET_SendPacket (netsrc_t sock, int length, const void *data, netadr_t to);
void QDECL NET_OutOfBandPrint( netsrc_t net_socket, netadr_t adr, const char *format, ...);
void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len );
@@ -750,6 +750,9 @@ extern cvar_t *com_altivec;
extern cvar_t *cl_paused;
extern cvar_t *sv_paused;
+extern cvar_t *cl_packetdelay;
+extern cvar_t *sv_packetdelay;
+
// com_speeds times
extern int time_game;
extern int time_frontend;
diff --git a/src/qcommon/vm_ppc_new.c b/src/qcommon/vm_ppc_new.c
index 42a03a50..a731d653 100644
--- a/src/qcommon/vm_ppc_new.c
+++ b/src/qcommon/vm_ppc_new.c
@@ -1107,7 +1107,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
#endif
assertInteger(opStackDepth-1);
assertInteger(opStackDepth-2);
- Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
+ Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
opStackRegType[opStackDepth-1] = 0;
opStackRegType[opStackDepth-2] = 0;
opStackLoadInstructionAddr[opStackDepth-1] = 0;
@@ -1131,7 +1131,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
#endif
assertInteger(opStackDepth-1);
assertInteger(opStackDepth-2);
- Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
+ Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
opStackRegType[opStackDepth-1] = 0;
opStackRegType[opStackDepth-2] = 0;
opStackLoadInstructionAddr[opStackDepth-1] = 0;
@@ -1155,7 +1155,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
#endif
assertInteger(opStackDepth-1);
assertInteger(opStackDepth-2);
- Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
+ Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
opStackRegType[opStackDepth-1] = 0;
opStackRegType[opStackDepth-2] = 0;
opStackLoadInstructionAddr[opStackDepth-1] = 0;
@@ -1179,7 +1179,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
#endif
assertInteger(opStackDepth-1);
assertInteger(opStackDepth-2);
- Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
+ Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
opStackRegType[opStackDepth-1] = 0;
opStackRegType[opStackDepth-2] = 0;
opStackLoadInstructionAddr[opStackDepth-1] = 0;
diff --git a/src/server/server.h b/src/server/server.h
index 091d7e7a..fd49da7b 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -239,6 +239,7 @@ extern cvar_t *sv_killserver;
extern cvar_t *sv_mapname;
extern cvar_t *sv_mapChecksum;
extern cvar_t *sv_serverid;
+extern cvar_t *sv_minRate;
extern cvar_t *sv_maxRate;
extern cvar_t *sv_minPing;
extern cvar_t *sv_maxPing;
diff --git a/src/server/sv_client.c b/src/server/sv_client.c
index 6cc9eecd..794f32a8 100644
--- a/src/server/sv_client.c
+++ b/src/server/sv_client.c
@@ -743,6 +743,12 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
rate = sv_maxRate->integer;
}
}
+ if ( sv_minRate->integer ) {
+ if ( sv_minRate->integer < 1000 )
+ Cvar_Set( "sv_minRate", "1000" );
+ if ( sv_minRate->integer > rate )
+ rate = sv_minRate->integer;
+ }
if (!rate) {
blockspersnap = 1;
diff --git a/src/server/sv_init.c b/src/server/sv_init.c
index 22f45729..0099e63f 100644
--- a/src/server/sv_init.c
+++ b/src/server/sv_init.c
@@ -539,6 +539,7 @@ void SV_Init (void) {
sv_hostname = Cvar_Get ("sv_hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE );
sv_maxclients = Cvar_Get ("sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
+ sv_minRate = Cvar_Get ("sv_minRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
sv_maxRate = Cvar_Get ("sv_maxRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
sv_minPing = Cvar_Get ("sv_minPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
sv_maxPing = Cvar_Get ("sv_maxPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
diff --git a/src/server/sv_main.c b/src/server/sv_main.c
index f4d960d9..c84e5ac3 100644
--- a/src/server/sv_main.c
+++ b/src/server/sv_main.c
@@ -45,6 +45,7 @@ cvar_t *sv_killserver; // menu system can set to 1 to shut server down
cvar_t *sv_mapname;
cvar_t *sv_mapChecksum;
cvar_t *sv_serverid;
+cvar_t *sv_minRate;
cvar_t *sv_maxRate;
cvar_t *sv_minPing;
cvar_t *sv_maxPing;
diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c
index cd295edf..dd483f17 100644
--- a/src/server/sv_snapshot.c
+++ b/src/server/sv_snapshot.c
@@ -552,6 +552,13 @@ static int SV_RateMsec( client_t *client, int messageSize ) {
rate = sv_maxRate->integer;
}
}
+ if ( sv_minRate->integer ) {
+ if ( sv_minRate->integer < 1000 )
+ Cvar_Set( "sv_minRate", "1000" );
+ if ( sv_minRate->integer > rate )
+ rate = sv_minRate->integer;
+ }
+
rateMsec = ( messageSize + HEADER_RATE_BYTES ) * 1000 / rate;
return rateMsec;
diff --git a/src/unix/sdl_glimp.c b/src/unix/sdl_glimp.c
index 4469f9e0..fcab7125 100644
--- a/src/unix/sdl_glimp.c
+++ b/src/unix/sdl_glimp.c
@@ -1357,17 +1357,32 @@ static int joy_keys[16] = {
K_JOY26, K_JOY27
};
+// translate hat events into keypresses
+// the 4 highest buttons are used for the first hat ...
+static int hat_keys[16] = {
+ K_JOY29, K_JOY30,
+ K_JOY31, K_JOY32,
+ K_JOY25, K_JOY26,
+ K_JOY27, K_JOY28,
+ K_JOY21, K_JOY22,
+ K_JOY23, K_JOY24,
+ K_JOY17, K_JOY18,
+ K_JOY19, K_JOY20
+};
+
// bk001130 - from linux_glimp.c
extern cvar_t * in_joystick;
extern cvar_t * in_joystickDebug;
extern cvar_t * joy_threshold;
+cvar_t *in_joystickNo;
#define ARRAYLEN(x) (sizeof (x) / sizeof (x[0]))
struct
{
qboolean buttons[16]; // !!! FIXME: these might be too many.
unsigned int oldaxes;
+ unsigned int oldhats;
} stick_state;
@@ -1407,36 +1422,35 @@ void IN_StartupJoystick( void )
for (i = 0; i < total; i++)
Com_Printf("[%d] %s\n", i, SDL_JoystickName(i));
- // !!! FIXME: someone should add a way to select a specific stick.
- for( i = 0; i < total; i++ ) {
- stick = SDL_JoystickOpen(i);
- if (stick == NULL)
- continue;
-
- Com_Printf( "Joystick %d opened\n", i );
- Com_Printf( "Name: %s\n", SDL_JoystickName(i) );
- Com_Printf( "Axes: %d\n", SDL_JoystickNumAxes(stick) );
- Com_Printf( "Hats: %d\n", SDL_JoystickNumHats(stick) );
- Com_Printf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) );
- Com_Printf( "Balls: %d\n", SDL_JoystickNumBalls(stick) );
-
- SDL_JoystickEventState(SDL_QUERY);
+ in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE );
+ if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total )
+ Cvar_Set( "in_joystickNo", "0" );
- /* Our work here is done. */
- return;
- }
+ stick = SDL_JoystickOpen( in_joystickNo->integer );
- /* No soup for you. */
- if( stick == NULL ) {
+ if (stick == NULL) {
Com_Printf( "No joystick opened.\n" );
return;
}
+
+ Com_Printf( "Joystick %d opened\n", in_joystickNo->integer );
+ Com_Printf( "Name: %s\n", SDL_JoystickName(in_joystickNo->integer) );
+ Com_Printf( "Axes: %d\n", SDL_JoystickNumAxes(stick) );
+ Com_Printf( "Hats: %d\n", SDL_JoystickNumHats(stick) );
+ Com_Printf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) );
+ Com_Printf( "Balls: %d\n", SDL_JoystickNumBalls(stick) );
+
+ SDL_JoystickEventState(SDL_QUERY);
+
+ /* Our work here is done. */
+ return;
}
void IN_JoyMove( void )
{
qboolean joy_pressed[ARRAYLEN(joy_keys)];
unsigned int axes = 0;
+ unsigned int hats = 0;
int total = 0;
int i = 0;
@@ -1490,7 +1504,94 @@ void IN_JoyMove( void )
}
}
- // !!! FIXME: look at the hats...
+ // look at the hats...
+ total = SDL_JoystickNumHats(stick);
+ if (total > 0)
+ {
+ if (total > 4) total = 4;
+ for (i = 0; i < total; i++)
+ {
+ ((Uint8 *)&hats)[i] = SDL_JoystickGetHat(stick, i);
+ }
+ }
+
+ // update hat state
+ if (hats != stick_state.oldhats)
+ {
+ for( i = 0; i < 4; i++ ) {
+ if( ((Uint8 *)&hats)[i] != ((Uint8 *)&stick_state.oldhats)[i] ) {
+ // release event
+ switch( ((Uint8 *)&stick_state.oldhats)[i] ) {
+ case SDL_HAT_UP:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
+ break;
+ case SDL_HAT_RIGHT:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
+ break;
+ case SDL_HAT_DOWN:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
+ break;
+ case SDL_HAT_LEFT:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
+ break;
+ case SDL_HAT_RIGHTUP:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
+ break;
+ case SDL_HAT_RIGHTDOWN:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
+ break;
+ case SDL_HAT_LEFTUP:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
+ break;
+ case SDL_HAT_LEFTDOWN:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
+ break;
+ default:
+ break;
+ }
+ // press event
+ switch( ((Uint8 *)&hats)[i] ) {
+ case SDL_HAT_UP:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
+ break;
+ case SDL_HAT_RIGHT:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
+ break;
+ case SDL_HAT_DOWN:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
+ break;
+ case SDL_HAT_LEFT:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
+ break;
+ case SDL_HAT_RIGHTUP:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
+ break;
+ case SDL_HAT_RIGHTDOWN:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
+ break;
+ case SDL_HAT_LEFTUP:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
+ break;
+ case SDL_HAT_LEFTDOWN:
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
+ Sys_QueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // save hat state
+ stick_state.oldhats = hats;
// finally, look at the axes...
total = SDL_JoystickNumAxes(stick);