From 579672760092292b7a9752899010ffa4ac6faf6f Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Sat, 17 Jun 2006 23:13:57 +0000 Subject: * Merged ioq3-r810 --- src/client/cl_main.c | 2 +- src/client/cl_parse.c | 28 ++++++--- src/client/snd_codec.c | 15 +++-- src/client/snd_codec_ogg.c | 9 ++- src/client/snd_openal.c | 1 + src/qcommon/common.c | 5 ++ src/qcommon/files.c | 52 +++++++++++++---- src/qcommon/md4.c | 4 +- src/qcommon/msg.c | 9 +++ src/qcommon/net_chan.c | 66 ++++++++++++++++++++- src/qcommon/qcommon.h | 5 +- src/qcommon/vm_ppc_new.c | 8 +-- src/server/server.h | 1 + src/server/sv_client.c | 6 ++ src/server/sv_init.c | 1 + src/server/sv_main.c | 1 + src/server/sv_snapshot.c | 7 +++ src/unix/sdl_glimp.c | 141 ++++++++++++++++++++++++++++++++++++++------- 18 files changed, 306 insertions(+), 55 deletions(-) (limited to 'src') 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); -- cgit