1455 lines
29 KiB
C
1455 lines
29 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
Quake III Arena source code 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 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
#ifndef DEDICATED
|
|
#ifdef USE_LOCAL_HEADERS
|
|
# include "SDL.h"
|
|
#else
|
|
# include <SDL.h>
|
|
#endif
|
|
#endif
|
|
|
|
#include "../qcommon/q_shared.h"
|
|
#include "../qcommon/qcommon.h"
|
|
#include "sys_local.h"
|
|
|
|
#include <windows.h>
|
|
#include <lmerr.h>
|
|
#include <lmcons.h>
|
|
#include <lmwksta.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <direct.h>
|
|
#include <io.h>
|
|
#include <conio.h>
|
|
#include <wincrypt.h>
|
|
#include <shlobj.h>
|
|
#include <psapi.h>
|
|
#include <float.h>
|
|
|
|
|
|
#ifdef USE_CONSOLE_WINDOW
|
|
// windowstuff
|
|
void Sys_ShowConsole( int visLevel, qboolean quitOnClose );
|
|
void Conbuf_AppendText( const char *pMsg );
|
|
void Sys_DestroyConsole( void );
|
|
|
|
#endif
|
|
// Used to determine where to store user-specific files
|
|
static char homePath[ MAX_OSPATH ] = { 0 };
|
|
|
|
#ifndef DEDICATED
|
|
static UINT timerResolution = 0;
|
|
#endif
|
|
|
|
/*
|
|
================
|
|
Sys_SetFPUCW
|
|
Set FPU control word to default value
|
|
================
|
|
*/
|
|
|
|
#ifndef _RC_CHOP
|
|
// mingw doesn't seem to have these defined :(
|
|
|
|
#define _MCW_EM 0x0008001fU
|
|
#define _MCW_RC 0x00000300U
|
|
#define _MCW_PC 0x00030000U
|
|
#define _RC_NEAR 0x00000000U
|
|
#define _PC_53 0x00010000U
|
|
|
|
unsigned int _controlfp(unsigned int new, unsigned int mask);
|
|
#endif
|
|
|
|
#define FPUCWMASK1 (_MCW_RC | _MCW_EM)
|
|
#define FPUCW (_RC_NEAR | _MCW_EM | _PC_53)
|
|
|
|
#if idx64
|
|
#define FPUCWMASK (FPUCWMASK1)
|
|
#else
|
|
#define FPUCWMASK (FPUCWMASK1 | _MCW_PC)
|
|
#endif
|
|
|
|
void Sys_SetFloatEnv(void)
|
|
{
|
|
_controlfp(FPUCW, FPUCWMASK);
|
|
}
|
|
|
|
/*
|
|
================
|
|
Sys_DefaultHomePath
|
|
================
|
|
*/
|
|
const char *Sys_DefaultHomePath( void )
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
FARPROC qSHGetFolderPath;
|
|
HMODULE shfolder = LoadLibrary("shfolder.dll");
|
|
|
|
if(shfolder == NULL)
|
|
{
|
|
Com_Printf("Unable to load SHFolder.dll\n");
|
|
return NULL;
|
|
}
|
|
|
|
if(!*homePath && com_homepath)
|
|
{
|
|
qSHGetFolderPath = GetProcAddress(shfolder, "SHGetFolderPathA");
|
|
if(qSHGetFolderPath == NULL)
|
|
{
|
|
Com_Printf("Unable to find SHGetFolderPath in SHFolder.dll\n");
|
|
FreeLibrary(shfolder);
|
|
return NULL;
|
|
}
|
|
|
|
if( !SUCCEEDED( qSHGetFolderPath( NULL, CSIDL_APPDATA,
|
|
NULL, 0, szPath ) ) )
|
|
{
|
|
Com_Printf("Unable to detect CSIDL_APPDATA\n");
|
|
FreeLibrary(shfolder);
|
|
return NULL;
|
|
}
|
|
|
|
Com_sprintf(homePath, sizeof(homePath), "%s%c", szPath, PATH_SEP);
|
|
|
|
if(com_homepath->string[0])
|
|
Q_strcat(homePath, sizeof(homePath), com_homepath->string);
|
|
else
|
|
Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_WIN);
|
|
}
|
|
|
|
FreeLibrary(shfolder);
|
|
return homePath;
|
|
}
|
|
|
|
/*
|
|
================
|
|
Sys_Milliseconds
|
|
================
|
|
*/
|
|
int sys_timeBase;
|
|
int Sys_Milliseconds (void)
|
|
{
|
|
int sys_curtime;
|
|
static qboolean initialized = qfalse;
|
|
|
|
if (!initialized) {
|
|
sys_timeBase = timeGetTime();
|
|
initialized = qtrue;
|
|
}
|
|
sys_curtime = timeGetTime() - sys_timeBase;
|
|
|
|
return sys_curtime;
|
|
}
|
|
|
|
/*
|
|
================
|
|
Sys_RandomBytes
|
|
================
|
|
*/
|
|
qboolean Sys_RandomBytes( byte *string, int len )
|
|
{
|
|
HCRYPTPROV prov;
|
|
|
|
if( !CryptAcquireContext( &prov, NULL, NULL,
|
|
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) ) {
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
if( !CryptGenRandom( prov, len, (BYTE *)string ) ) {
|
|
CryptReleaseContext( prov, 0 );
|
|
return qfalse;
|
|
}
|
|
CryptReleaseContext( prov, 0 );
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
================
|
|
Sys_GetCurrentUser
|
|
================
|
|
*/
|
|
char *Sys_GetCurrentUser( void )
|
|
{
|
|
static char s_userName[1024];
|
|
unsigned long size = sizeof( s_userName );
|
|
|
|
if( !GetUserName( s_userName, &size ) )
|
|
strcpy( s_userName, "player" );
|
|
|
|
if( !s_userName[0] )
|
|
{
|
|
strcpy( s_userName, "player" );
|
|
}
|
|
|
|
return s_userName;
|
|
}
|
|
|
|
/*
|
|
================
|
|
Sys_GetClipboardData
|
|
================
|
|
*/
|
|
char *Sys_GetClipboardData( void )
|
|
{
|
|
char *data = NULL;
|
|
char *cliptext;
|
|
|
|
if ( OpenClipboard( NULL ) != 0 ) {
|
|
HANDLE hClipboardData;
|
|
|
|
if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) {
|
|
if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 ) {
|
|
data = Z_Malloc( GlobalSize( hClipboardData ) + 1 );
|
|
Q_strncpyz( data, cliptext, GlobalSize( hClipboardData ) );
|
|
GlobalUnlock( hClipboardData );
|
|
|
|
strtok( data, "\n\r\b" );
|
|
}
|
|
}
|
|
CloseClipboard();
|
|
}
|
|
return data;
|
|
}
|
|
|
|
#define MEM_THRESHOLD 96*1024*1024
|
|
|
|
/*
|
|
==================
|
|
Sys_LowPhysicalMemory
|
|
==================
|
|
*/
|
|
qboolean Sys_LowPhysicalMemory( void )
|
|
{
|
|
MEMORYSTATUS stat;
|
|
GlobalMemoryStatus (&stat);
|
|
return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_Basename
|
|
==============
|
|
*/
|
|
const char *Sys_Basename( char *path )
|
|
{
|
|
static char base[ MAX_OSPATH ] = { 0 };
|
|
int length;
|
|
|
|
length = strlen( path ) - 1;
|
|
|
|
// Skip trailing slashes
|
|
while( length > 0 && path[ length ] == '\\' )
|
|
length--;
|
|
|
|
while( length > 0 && path[ length - 1 ] != '\\' )
|
|
length--;
|
|
|
|
Q_strncpyz( base, &path[ length ], sizeof( base ) );
|
|
|
|
length = strlen( base ) - 1;
|
|
|
|
// Strip trailing slashes
|
|
while( length > 0 && base[ length ] == '\\' )
|
|
base[ length-- ] = '\0';
|
|
|
|
return base;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_Dirname
|
|
==============
|
|
*/
|
|
const char *Sys_Dirname( char *path )
|
|
{
|
|
static char dir[ MAX_OSPATH ] = { 0 };
|
|
int length;
|
|
|
|
Q_strncpyz( dir, path, sizeof( dir ) );
|
|
length = strlen( dir ) - 1;
|
|
|
|
while( length > 0 && dir[ length ] != '\\' )
|
|
length--;
|
|
|
|
dir[ length ] = '\0';
|
|
|
|
return dir;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_FOpen
|
|
==============
|
|
*/
|
|
FILE *Sys_FOpen( const char *ospath, const char *mode ) {
|
|
return fopen( ospath, mode );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_Mkdir
|
|
==============
|
|
*/
|
|
qboolean Sys_Mkdir( const char *path )
|
|
{
|
|
if( !CreateDirectory( path, NULL ) )
|
|
{
|
|
if( GetLastError( ) != ERROR_ALREADY_EXISTS )
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Sys_Mkfifo
|
|
Noop on windows because named pipes do not function the same way
|
|
==================
|
|
*/
|
|
FILE *Sys_Mkfifo( const char *ospath )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_Cwd
|
|
==============
|
|
*/
|
|
char *Sys_Cwd( void ) {
|
|
static char cwd[MAX_OSPATH];
|
|
|
|
_getcwd( cwd, sizeof( cwd ) - 1 );
|
|
cwd[MAX_OSPATH-1] = 0;
|
|
|
|
return cwd;
|
|
}
|
|
|
|
/*
|
|
==============================================================
|
|
|
|
DIRECTORY SCANNING
|
|
|
|
==============================================================
|
|
*/
|
|
|
|
#define MAX_FOUND_FILES 0x1000
|
|
|
|
/*
|
|
==============
|
|
Sys_ListFilteredFiles
|
|
==============
|
|
*/
|
|
void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles )
|
|
{
|
|
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
|
|
char filename[MAX_OSPATH];
|
|
intptr_t findhandle;
|
|
struct _finddata_t findinfo;
|
|
|
|
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
|
|
return;
|
|
}
|
|
|
|
if (strlen(subdirs)) {
|
|
Com_sprintf( search, sizeof(search), "%s\\%s\\*", basedir, subdirs );
|
|
}
|
|
else {
|
|
Com_sprintf( search, sizeof(search), "%s\\*", basedir );
|
|
}
|
|
|
|
findhandle = _findfirst (search, &findinfo);
|
|
if (findhandle == -1) {
|
|
return;
|
|
}
|
|
|
|
do {
|
|
if (findinfo.attrib & _A_SUBDIR) {
|
|
if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) {
|
|
if (strlen(subdirs)) {
|
|
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name);
|
|
}
|
|
else {
|
|
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name);
|
|
}
|
|
Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
|
|
}
|
|
}
|
|
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
|
|
break;
|
|
}
|
|
Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name );
|
|
if (!Com_FilterPath( filter, filename, qfalse ))
|
|
continue;
|
|
list[ *numfiles ] = CopyString( filename );
|
|
(*numfiles)++;
|
|
} while ( _findnext (findhandle, &findinfo) != -1 );
|
|
|
|
_findclose (findhandle);
|
|
}
|
|
|
|
/*
|
|
==============
|
|
strgtr
|
|
==============
|
|
*/
|
|
static qboolean strgtr(const char *s0, const char *s1)
|
|
{
|
|
int l0, l1, i;
|
|
|
|
l0 = strlen(s0);
|
|
l1 = strlen(s1);
|
|
|
|
if (l1<l0) {
|
|
l0 = l1;
|
|
}
|
|
|
|
for(i=0;i<l0;i++) {
|
|
if (s1[i] > s0[i]) {
|
|
return qtrue;
|
|
}
|
|
if (s1[i] < s0[i]) {
|
|
return qfalse;
|
|
}
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_ListFiles
|
|
==============
|
|
*/
|
|
char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs )
|
|
{
|
|
char search[MAX_OSPATH];
|
|
int nfiles;
|
|
char **listCopy;
|
|
char *list[MAX_FOUND_FILES];
|
|
struct _finddata_t findinfo;
|
|
intptr_t findhandle;
|
|
int flag;
|
|
int i;
|
|
|
|
if (filter) {
|
|
|
|
nfiles = 0;
|
|
Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
|
|
|
|
list[ nfiles ] = 0;
|
|
*numfiles = nfiles;
|
|
|
|
if (!nfiles)
|
|
return NULL;
|
|
|
|
listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
|
|
for ( i = 0 ; i < nfiles ; i++ ) {
|
|
listCopy[i] = list[i];
|
|
}
|
|
listCopy[i] = NULL;
|
|
|
|
return listCopy;
|
|
}
|
|
|
|
if ( !extension) {
|
|
extension = "";
|
|
}
|
|
|
|
// passing a slash as extension will find directories
|
|
if ( extension[0] == '/' && extension[1] == 0 ) {
|
|
extension = "";
|
|
flag = 0;
|
|
} else {
|
|
flag = _A_SUBDIR;
|
|
}
|
|
|
|
Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
|
|
|
|
// search
|
|
nfiles = 0;
|
|
|
|
findhandle = _findfirst (search, &findinfo);
|
|
if (findhandle == -1) {
|
|
*numfiles = 0;
|
|
return NULL;
|
|
}
|
|
|
|
do {
|
|
if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
|
|
if ( nfiles == MAX_FOUND_FILES - 1 ) {
|
|
break;
|
|
}
|
|
list[ nfiles ] = CopyString( findinfo.name );
|
|
nfiles++;
|
|
}
|
|
} while ( _findnext (findhandle, &findinfo) != -1 );
|
|
|
|
list[ nfiles ] = 0;
|
|
|
|
_findclose (findhandle);
|
|
|
|
// return a copy of the list
|
|
*numfiles = nfiles;
|
|
|
|
if ( !nfiles ) {
|
|
return NULL;
|
|
}
|
|
|
|
listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
|
|
for ( i = 0 ; i < nfiles ; i++ ) {
|
|
listCopy[i] = list[i];
|
|
}
|
|
listCopy[i] = NULL;
|
|
|
|
do {
|
|
flag = 0;
|
|
for(i=1; i<nfiles; i++) {
|
|
if (strgtr(listCopy[i-1], listCopy[i])) {
|
|
char *temp = listCopy[i];
|
|
listCopy[i] = listCopy[i-1];
|
|
listCopy[i-1] = temp;
|
|
flag = 1;
|
|
}
|
|
}
|
|
} while(flag);
|
|
|
|
return listCopy;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_FreeFileList
|
|
==============
|
|
*/
|
|
void Sys_FreeFileList( char **list )
|
|
{
|
|
int i;
|
|
|
|
if ( !list ) {
|
|
return;
|
|
}
|
|
|
|
for ( i = 0 ; list[i] ; i++ ) {
|
|
Z_Free( list[i] );
|
|
}
|
|
|
|
Z_Free( list );
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
Sys_Sleep
|
|
|
|
Block execution for msec or until input is received.
|
|
==============
|
|
*/
|
|
void Sys_Sleep( int msec )
|
|
{
|
|
if( msec == 0 )
|
|
return;
|
|
|
|
#ifdef DEDICATED
|
|
if( msec < 0 )
|
|
WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), INFINITE );
|
|
else
|
|
WaitForSingleObject( GetStdHandle( STD_INPUT_HANDLE ), msec );
|
|
#else
|
|
// Client Sys_Sleep doesn't support waiting on stdin
|
|
if( msec < 0 )
|
|
return;
|
|
|
|
Sleep( msec );
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_ErrorDialog
|
|
|
|
Display an error message
|
|
==============
|
|
*/
|
|
void Sys_ErrorDialog( const char *error )
|
|
{
|
|
#ifdef USE_CONSOLE_WINDOW
|
|
// leilei - console restoration
|
|
//va_list argptr;
|
|
//char text[4096];
|
|
MSG msg;
|
|
|
|
Conbuf_AppendText( error );
|
|
Conbuf_AppendText( "\n" );
|
|
|
|
Sys_SetErrorText( error );
|
|
Sys_ShowConsole( 1, qtrue );
|
|
|
|
timeEndPeriod( 1 );
|
|
|
|
IN_Shutdown();
|
|
|
|
// wait for the user to quit
|
|
while ( 1 ) {
|
|
if (!GetMessage (&msg, NULL, 0, 0))
|
|
Com_Quit_f ();
|
|
TranslateMessage (&msg);
|
|
DispatchMessage (&msg);
|
|
}
|
|
Sys_DestroyConsole();
|
|
|
|
|
|
exit (1);
|
|
|
|
#else
|
|
if( Sys_Dialog( DT_YES_NO, va( "%s. Copy console log to clipboard?", error ),
|
|
"Error" ) == DR_YES )
|
|
{
|
|
HGLOBAL memoryHandle;
|
|
char *clipMemory;
|
|
|
|
memoryHandle = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, CON_LogSize( ) + 1 );
|
|
clipMemory = (char *)GlobalLock( memoryHandle );
|
|
|
|
if( clipMemory )
|
|
{
|
|
char *p = clipMemory;
|
|
char buffer[ 1024 ];
|
|
unsigned int size;
|
|
|
|
while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 )
|
|
{
|
|
Com_Memcpy( p, buffer, size );
|
|
p += size;
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
if( OpenClipboard( NULL ) && EmptyClipboard( ) )
|
|
SetClipboardData( CF_TEXT, memoryHandle );
|
|
|
|
GlobalUnlock( clipMemory );
|
|
CloseClipboard( );
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_Dialog
|
|
|
|
Display a win32 dialog box
|
|
==============
|
|
*/
|
|
dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title )
|
|
{
|
|
UINT uType;
|
|
|
|
switch( type )
|
|
{
|
|
default:
|
|
case DT_INFO: uType = MB_ICONINFORMATION|MB_OK; break;
|
|
case DT_WARNING: uType = MB_ICONWARNING|MB_OK; break;
|
|
case DT_ERROR: uType = MB_ICONERROR|MB_OK; break;
|
|
case DT_YES_NO: uType = MB_ICONQUESTION|MB_YESNO; break;
|
|
case DT_OK_CANCEL: uType = MB_ICONWARNING|MB_OKCANCEL; break;
|
|
}
|
|
|
|
switch( MessageBox( NULL, message, title, uType ) )
|
|
{
|
|
default:
|
|
case IDOK: return DR_OK;
|
|
case IDCANCEL: return DR_CANCEL;
|
|
case IDYES: return DR_YES;
|
|
case IDNO: return DR_NO;
|
|
}
|
|
}
|
|
|
|
#ifndef DEDICATED
|
|
#if SDL_MAJOR_VERSION != 2
|
|
static qboolean SDL_VIDEODRIVER_externallySet = qfalse;
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
==============
|
|
Sys_GLimpSafeInit
|
|
|
|
Windows specific "safe" GL implementation initialisation
|
|
==============
|
|
*/
|
|
void Sys_GLimpSafeInit( void )
|
|
{
|
|
#ifndef DEDICATED
|
|
#if SDL_MAJOR_VERSION != 2
|
|
if( !SDL_VIDEODRIVER_externallySet )
|
|
{
|
|
// Here, we want to let SDL decide what do to unless
|
|
// explicitly requested otherwise
|
|
_putenv( "SDL_VIDEODRIVER=" );
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_GLimpInit
|
|
|
|
Windows specific GL implementation initialisation
|
|
==============
|
|
*/
|
|
void Sys_GLimpInit( void )
|
|
{
|
|
#ifndef DEDICATED
|
|
#if SDL_MAJOR_VERSION != 2
|
|
if( !SDL_VIDEODRIVER_externallySet )
|
|
{
|
|
// It's a little bit weird having in_mouse control the
|
|
// video driver, but from ioq3's point of view they're
|
|
// virtually the same except for the mouse input anyway
|
|
if( Cvar_VariableIntegerValue( "in_mouse" ) == -1 )
|
|
{
|
|
// Use the windib SDL backend, which is closest to
|
|
// the behaviour of idq3 with in_mouse set to -1
|
|
_putenv( "SDL_VIDEODRIVER=windib" );
|
|
}
|
|
else
|
|
{
|
|
// Use the DirectX SDL backend
|
|
_putenv( "SDL_VIDEODRIVER=directx" );
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
#ifndef DEDICATED
|
|
#ifdef USE_CONSOLE_WINDOW
|
|
void Sys_CreateConsole( void );
|
|
#endif
|
|
#endif
|
|
/*
|
|
==============
|
|
Sys_PlatformInit
|
|
|
|
Windows specific initialisation
|
|
==============
|
|
*/
|
|
void Sys_PlatformInit( void )
|
|
{
|
|
#ifndef DEDICATED
|
|
TIMECAPS ptc;
|
|
const char *SDL_VIDEODRIVER = getenv( "SDL_VIDEODRIVER" );
|
|
#endif
|
|
|
|
Sys_SetFloatEnv();
|
|
|
|
#ifndef DEDICATED
|
|
|
|
|
|
#ifdef USE_CONSOLE_WINDOW
|
|
|
|
// leilei - console restoration
|
|
// done before Com/Sys_Init since we need this for error output
|
|
Sys_CreateConsole();
|
|
|
|
#endif
|
|
|
|
#if SDL_MAJOR_VERSION != 2
|
|
if( SDL_VIDEODRIVER )
|
|
{
|
|
Com_Printf( "SDL_VIDEODRIVER is externally set to \"%s\", "
|
|
"in_mouse -1 will have no effect\n", SDL_VIDEODRIVER );
|
|
SDL_VIDEODRIVER_externallySet = qtrue;
|
|
}
|
|
else
|
|
SDL_VIDEODRIVER_externallySet = qfalse;
|
|
#endif
|
|
|
|
// leilei - no 3dfx splashes please
|
|
_putenv("FX_GLIDE_NO_SPLASH=1");
|
|
|
|
if(timeGetDevCaps(&ptc, sizeof(ptc)) == MMSYSERR_NOERROR)
|
|
{
|
|
timerResolution = ptc.wPeriodMin;
|
|
|
|
if(timerResolution > 1)
|
|
{
|
|
Com_Printf("Warning: Minimum supported timer resolution is %ums "
|
|
"on this system, recommended resolution 1ms\n", timerResolution);
|
|
}
|
|
|
|
timeBeginPeriod(timerResolution);
|
|
}
|
|
else
|
|
timerResolution = 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_PlatformExit
|
|
|
|
Windows specific initialisation
|
|
==============
|
|
*/
|
|
void Sys_PlatformExit( void )
|
|
{
|
|
#ifndef DEDICATED
|
|
if(timerResolution)
|
|
timeEndPeriod(timerResolution);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_SetEnv
|
|
|
|
set/unset environment variables (empty value removes it)
|
|
==============
|
|
*/
|
|
void Sys_SetEnv(const char *name, const char *value)
|
|
{
|
|
if(value)
|
|
_putenv(va("%s=%s", name, value));
|
|
else
|
|
_putenv(va("%s=", name));
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_PID
|
|
==============
|
|
*/
|
|
int Sys_PID( void )
|
|
{
|
|
return GetCurrentProcessId( );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Sys_PIDIsRunning
|
|
==============
|
|
*/
|
|
qboolean Sys_PIDIsRunning( int pid )
|
|
{
|
|
DWORD processes[ 1024 ];
|
|
DWORD numBytes, numProcesses;
|
|
int i;
|
|
|
|
// leilei - load PSAPI.DLL here, check for EnumProcesses.
|
|
// Fixes Windows 95 support.
|
|
HMODULE psapi = LoadLibrary("psapi.dll");
|
|
FARPROC qEnumProcesses;
|
|
|
|
if(psapi == NULL)
|
|
{
|
|
Com_Printf("Unable to load PSAPI.dll\n");
|
|
FreeLibrary(psapi);
|
|
return qfalse;
|
|
}
|
|
|
|
qEnumProcesses = GetProcAddress(psapi, "EnumProcesses");
|
|
if(qEnumProcesses == NULL)
|
|
{
|
|
Com_Printf("Unable to find EnumProcesses in psapi.dll\n");
|
|
FreeLibrary(psapi);
|
|
return qfalse;
|
|
}
|
|
|
|
|
|
if( !qEnumProcesses( processes, sizeof( processes ), &numBytes ) ){
|
|
FreeLibrary(psapi);
|
|
return qfalse; // Assume it's not running
|
|
}
|
|
|
|
FreeLibrary(psapi); // we're still done
|
|
|
|
numProcesses = numBytes / sizeof( DWORD );
|
|
|
|
// Search for the pid
|
|
for( i = 0; i < numProcesses; i++ )
|
|
{
|
|
if( processes[ i ] == pid )
|
|
return qtrue;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
|
|
|
|
// leilei - win32 console restoration
|
|
|
|
|
|
#ifdef USE_CONSOLE_WINDOW
|
|
|
|
#include "../sys/win_resource.h"
|
|
#include "../qcommon/q_shared.h"
|
|
#include "../qcommon/qcommon.h"
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <windows.h>
|
|
#include <olectl.h>
|
|
#include <wingdi.h>
|
|
#include <math.h>
|
|
|
|
#include "../renderercommon/tr_common.h"
|
|
#include "../sys/sys_local.h"
|
|
|
|
typedef struct
|
|
{
|
|
|
|
HINSTANCE reflib_library; // Handle to refresh DLL
|
|
qboolean reflib_active;
|
|
|
|
HWND hWnd;
|
|
HINSTANCE hInstance;
|
|
qboolean activeApp;
|
|
qboolean isMinimized;
|
|
OSVERSIONINFO osversion;
|
|
|
|
// when we get a windows message, we store the time off so keyboard processing
|
|
// can know the exact time of an event
|
|
unsigned sysMsgTime;
|
|
} WinVars_t;
|
|
|
|
WinVars_t g_wv;
|
|
|
|
|
|
|
|
#define CONSOLE_WINDOW_TITLE "OpenArena3 Console"
|
|
#define CONSOLE_WINDOW_ICON CLIENT_WINDOW_ICON
|
|
|
|
|
|
#define COPY_ID 1
|
|
#define QUIT_ID 2
|
|
#define CLEAR_ID 3
|
|
|
|
#define ERRORBOX_ID 10
|
|
#define ERRORTEXT_ID 11
|
|
|
|
#define EDIT_ID 100
|
|
#define INPUT_ID 101
|
|
|
|
typedef struct
|
|
{
|
|
HWND hWnd;
|
|
HWND hwndBuffer;
|
|
|
|
HWND hwndButtonClear;
|
|
HWND hwndButtonCopy;
|
|
HWND hwndButtonQuit;
|
|
|
|
HWND hwndErrorBox;
|
|
HWND hwndErrorText;
|
|
|
|
HBITMAP hbmLogo;
|
|
HBITMAP hbmClearBitmap;
|
|
|
|
HBRUSH hbrEditBackground;
|
|
HBRUSH hbrErrorBackground;
|
|
|
|
HFONT hfBufferFont;
|
|
HFONT hfButtonFont;
|
|
|
|
HWND hwndInputLine;
|
|
|
|
char errorString[80];
|
|
|
|
char consoleText[512], returnedText[512];
|
|
int visLevel;
|
|
qboolean quitOnClose;
|
|
int windowWidth, windowHeight;
|
|
|
|
WNDPROC SysInputLineWndProc;
|
|
|
|
} WinConData;
|
|
|
|
static WinConData s_wcd;
|
|
|
|
|
|
|
|
static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
//char *cmdString; // TODO: Reimplement Quit
|
|
static qboolean s_timePolarity;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_ACTIVATE:
|
|
if ( LOWORD( wParam ) != WA_INACTIVE )
|
|
{
|
|
SetFocus( s_wcd.hwndInputLine );
|
|
}
|
|
|
|
/* if ( com_viewlog && ( com_dedicated && !com_dedicated->integer ) )
|
|
{
|
|
// if the viewlog is open, check to see if it's being minimized
|
|
if ( com_viewlog->integer == 1 )
|
|
{
|
|
if ( HIWORD( wParam ) ) // minimized flag
|
|
{
|
|
// ri.Cvar_Set( "viewlog", "2" );
|
|
}
|
|
}
|
|
else if ( com_viewlog->integer == 2 )
|
|
{
|
|
if ( !HIWORD( wParam ) ) // minimized flag
|
|
{
|
|
// ri.Cvar_Set( "viewlog", "1" );
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
// if ( ( com_dedicated && com_dedicated->integer ) )
|
|
// {
|
|
// cmdString = CopyString( "quit" );
|
|
// Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString );
|
|
// }
|
|
// else if ( s_wcd.quitOnClose )
|
|
// {
|
|
// PostQuitMessage( 0 );
|
|
// }
|
|
// else
|
|
{
|
|
// Sys_ShowConsole( 0, qfalse );
|
|
// ri.Cvar_Set( "viewlog", "0" );
|
|
}
|
|
return 0;
|
|
case WM_CTLCOLORSTATIC:
|
|
if ( ( HWND ) lParam == s_wcd.hwndBuffer )
|
|
{
|
|
// SetBkColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0xB0 ) ); // old colors
|
|
// SetTextColor( ( HDC ) wParam, RGB( 0xff, 0xff, 0x00 ) );
|
|
|
|
SetBkColor( ( HDC ) wParam, RGB( 0x09, 0x29, 0x35 ) );
|
|
SetTextColor( ( HDC ) wParam, RGB( 0xC3, 0xDA, 0xF3 ) );
|
|
|
|
return ( long ) s_wcd.hbrEditBackground;
|
|
}
|
|
else if ( ( HWND ) lParam == s_wcd.hwndErrorBox )
|
|
{
|
|
if ( s_timePolarity & 1 )
|
|
{
|
|
SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
|
|
SetTextColor( ( HDC ) wParam, RGB( 0xff, 0x0, 0x00 ) );
|
|
}
|
|
else
|
|
{
|
|
SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
|
|
SetTextColor( ( HDC ) wParam, RGB( 0x00, 0x0, 0x00 ) );
|
|
}
|
|
return ( long ) s_wcd.hbrErrorBackground;
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
if ( wParam == COPY_ID )
|
|
{
|
|
SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
|
|
SendMessage( s_wcd.hwndBuffer, WM_COPY, 0, 0 );
|
|
}
|
|
else if ( wParam == QUIT_ID )
|
|
{
|
|
if ( s_wcd.quitOnClose )
|
|
{
|
|
PostQuitMessage( 0 );
|
|
}
|
|
else
|
|
{
|
|
//cmdString = CopyString( "quit" ); // TODO: Reimplement quit
|
|
// Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString );
|
|
}
|
|
}
|
|
else if ( wParam == CLEAR_ID )
|
|
{
|
|
SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
|
|
SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, FALSE, ( LPARAM ) "" );
|
|
UpdateWindow( s_wcd.hwndBuffer );
|
|
}
|
|
break;
|
|
case WM_CREATE:
|
|
// s_wcd.hbmLogo = LoadBitmap( g_wv.hInstance, MAKEINTRESOURCE( IDB_BITMAP1 ) );
|
|
// s_wcd.hbmClearBitmap = LoadBitmap( g_wv.hInstance, MAKEINTRESOURCE( IDB_BITMAP2 ) ); // could use one later for test throwbacks
|
|
// s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0xB0 ) );
|
|
s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x09, 0x29, 0x35 ) );
|
|
|
|
s_wcd.hbrErrorBackground = CreateSolidBrush( RGB( 0x80, 0x80, 0x80 ) );
|
|
SetTimer( hWnd, 1, 1000, NULL );
|
|
break;
|
|
case WM_ERASEBKGND:
|
|
return DefWindowProc( hWnd, uMsg, wParam, lParam );
|
|
case WM_TIMER:
|
|
if ( wParam == 1 )
|
|
{
|
|
s_timePolarity = !s_timePolarity;
|
|
if ( s_wcd.hwndErrorBox )
|
|
{
|
|
InvalidateRect( s_wcd.hwndErrorBox, NULL, FALSE );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return DefWindowProc( hWnd, uMsg, wParam, lParam );
|
|
}
|
|
|
|
|
|
LONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
char inputBuffer[1024];
|
|
|
|
switch ( uMsg )
|
|
{
|
|
case WM_KILLFOCUS:
|
|
if ( ( HWND ) wParam == s_wcd.hWnd ||
|
|
( HWND ) wParam == s_wcd.hwndErrorBox )
|
|
{
|
|
SetFocus( hWnd );
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_CHAR:
|
|
if ( wParam == 13 )
|
|
{
|
|
GetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer ) );
|
|
strncat( s_wcd.consoleText, inputBuffer, sizeof( s_wcd.consoleText ) - strlen( s_wcd.consoleText ) - 5 );
|
|
strcat( s_wcd.consoleText, "\n" );
|
|
SetWindowText( s_wcd.hwndInputLine, "" );
|
|
|
|
Sys_Print( va( "]%s\n", inputBuffer ) );
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return CallWindowProc( s_wcd.SysInputLineWndProc, hWnd, uMsg, wParam, lParam );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** Sys_CreateConsole
|
|
*/
|
|
void Sys_CreateConsole( void )
|
|
{
|
|
HDC hDC;
|
|
WNDCLASS wc;
|
|
RECT rect;
|
|
const char *DEDCLASS = "Q3 WinConsole";
|
|
int nHeight;
|
|
int swidth, sheight;
|
|
int DEDSTYLE = WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX;
|
|
|
|
memset( &wc, 0, sizeof( wc ) );
|
|
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = (WNDPROC) ConWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = g_wv.hInstance;
|
|
wc.hIcon = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1));
|
|
wc.hCursor = LoadCursor (NULL,IDC_ARROW);
|
|
wc.hbrBackground = (void *)COLOR_WINDOW;
|
|
wc.lpszMenuName = 0;
|
|
wc.lpszClassName = DEDCLASS;
|
|
|
|
if ( !RegisterClass (&wc) )
|
|
return;
|
|
|
|
rect.left = 0;
|
|
rect.right = 540;
|
|
rect.top = 0;
|
|
rect.bottom = 450;
|
|
AdjustWindowRect( &rect, DEDSTYLE, FALSE );
|
|
|
|
hDC = GetDC( GetDesktopWindow() );
|
|
swidth = GetDeviceCaps( hDC, HORZRES );
|
|
sheight = GetDeviceCaps( hDC, VERTRES );
|
|
ReleaseDC( GetDesktopWindow(), hDC );
|
|
|
|
s_wcd.windowWidth = rect.right - rect.left + 1;
|
|
s_wcd.windowHeight = rect.bottom - rect.top + 1;
|
|
|
|
s_wcd.hWnd = CreateWindowEx( 0,
|
|
DEDCLASS,
|
|
CONSOLE_WINDOW_TITLE,
|
|
DEDSTYLE,
|
|
( swidth - 600 ) / 2, ( sheight - 450 ) / 2 , rect.right - rect.left + 1, rect.bottom - rect.top + 1,
|
|
NULL,
|
|
NULL,
|
|
g_wv.hInstance,
|
|
NULL );
|
|
|
|
if ( s_wcd.hWnd == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// create fonts
|
|
//
|
|
hDC = GetDC( s_wcd.hWnd );
|
|
nHeight = -MulDiv( 8, GetDeviceCaps( hDC, LOGPIXELSY), 72);
|
|
|
|
s_wcd.hfBufferFont = CreateFont( nHeight,
|
|
0,
|
|
0,
|
|
0,
|
|
FW_LIGHT,
|
|
0,
|
|
0,
|
|
0,
|
|
DEFAULT_CHARSET,
|
|
OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,
|
|
DEFAULT_QUALITY,
|
|
FF_MODERN | FIXED_PITCH,
|
|
"Courier New" );
|
|
|
|
ReleaseDC( s_wcd.hWnd, hDC );
|
|
|
|
//
|
|
// create the input line
|
|
//
|
|
s_wcd.hwndInputLine = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER |
|
|
ES_LEFT | ES_AUTOHSCROLL,
|
|
6, 400, 528, 20,
|
|
s_wcd.hWnd,
|
|
( HMENU ) INPUT_ID, // child window ID
|
|
g_wv.hInstance, NULL );
|
|
|
|
//
|
|
// create the buttons
|
|
//
|
|
s_wcd.hwndButtonCopy = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
|
|
5, 425, 72, 24,
|
|
s_wcd.hWnd,
|
|
( HMENU ) COPY_ID, // child window ID
|
|
g_wv.hInstance, NULL );
|
|
SendMessage( s_wcd.hwndButtonCopy, WM_SETTEXT, 0, ( LPARAM ) "copy" );
|
|
|
|
s_wcd.hwndButtonClear = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
|
|
82, 425, 72, 24,
|
|
s_wcd.hWnd,
|
|
( HMENU ) CLEAR_ID, // child window ID
|
|
g_wv.hInstance, NULL );
|
|
SendMessage( s_wcd.hwndButtonClear, WM_SETTEXT, 0, ( LPARAM ) "clear" );
|
|
|
|
s_wcd.hwndButtonQuit = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
|
|
462, 425, 72, 24,
|
|
s_wcd.hWnd,
|
|
( HMENU ) QUIT_ID, // child window ID
|
|
g_wv.hInstance, NULL );
|
|
SendMessage( s_wcd.hwndButtonQuit, WM_SETTEXT, 0, ( LPARAM ) "quit" );
|
|
|
|
|
|
//
|
|
// create the scrollbuffer
|
|
//
|
|
s_wcd.hwndBuffer = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER |
|
|
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
|
|
6, 40, 526, 354,
|
|
s_wcd.hWnd,
|
|
( HMENU ) EDIT_ID, // child window ID
|
|
g_wv.hInstance, NULL );
|
|
SendMessage( s_wcd.hwndBuffer, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
|
|
|
|
s_wcd.SysInputLineWndProc = ( WNDPROC ) SetWindowLong( s_wcd.hwndInputLine, GWL_WNDPROC, ( long ) InputLineWndProc );
|
|
SendMessage( s_wcd.hwndInputLine, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
|
|
|
|
ShowWindow( s_wcd.hWnd, SW_SHOWDEFAULT);
|
|
UpdateWindow( s_wcd.hWnd );
|
|
SetForegroundWindow( s_wcd.hWnd );
|
|
SetFocus( s_wcd.hwndInputLine );
|
|
|
|
s_wcd.visLevel = 1;
|
|
}
|
|
|
|
/*
|
|
** Sys_DestroyConsole
|
|
*/
|
|
void Sys_DestroyConsole( void ) {
|
|
if ( s_wcd.hWnd ) {
|
|
ShowWindow( s_wcd.hWnd, SW_HIDE );
|
|
CloseWindow( s_wcd.hWnd );
|
|
DestroyWindow( s_wcd.hWnd );
|
|
s_wcd.hWnd = 0;
|
|
}
|
|
}
|
|
void Conbuf_AppendText( const char *pMsg );
|
|
|
|
/*
|
|
** Sys_ShowConsole
|
|
*/
|
|
void Sys_ShowConsole( int visLevel, qboolean quitOnClose )
|
|
{
|
|
s_wcd.quitOnClose = quitOnClose;
|
|
|
|
if ( visLevel == s_wcd.visLevel )
|
|
{
|
|
return;
|
|
}
|
|
|
|
s_wcd.visLevel = visLevel;
|
|
|
|
if ( !s_wcd.hWnd )
|
|
return;
|
|
|
|
switch ( visLevel )
|
|
{
|
|
case 0:
|
|
ShowWindow( s_wcd.hWnd, SW_HIDE );
|
|
break;
|
|
case 1:
|
|
ShowWindow( s_wcd.hWnd, SW_SHOWNORMAL );
|
|
SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
|
|
break;
|
|
case 2:
|
|
ShowWindow( s_wcd.hWnd, SW_MINIMIZE );
|
|
break;
|
|
default:
|
|
Sys_Error( "Invalid visLevel %d sent to Sys_ShowConsole\n", visLevel );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** Conbuf_AppendText
|
|
*/
|
|
void Conbuf_AppendText( const char *pMsg )
|
|
{
|
|
#define CONSOLE_BUFFER_SIZE 16384
|
|
|
|
char buffer[CONSOLE_BUFFER_SIZE*2];
|
|
char *b = buffer;
|
|
const char *msg;
|
|
int bufLen;
|
|
int i = 0;
|
|
static unsigned long s_totalChars;
|
|
|
|
//
|
|
// if the message is REALLY long, use just the last portion of it
|
|
//
|
|
if ( strlen( pMsg ) > CONSOLE_BUFFER_SIZE - 1 )
|
|
{
|
|
msg = pMsg + strlen( pMsg ) - CONSOLE_BUFFER_SIZE + 1;
|
|
}
|
|
else
|
|
{
|
|
msg = pMsg;
|
|
}
|
|
|
|
//
|
|
// copy into an intermediate buffer
|
|
//
|
|
while ( msg[i] && ( ( b - buffer ) < sizeof( buffer ) - 1 ) )
|
|
{
|
|
if ( msg[i] == '\n' && msg[i+1] == '\r' )
|
|
{
|
|
b[0] = '\r';
|
|
b[1] = '\n';
|
|
b += 2;
|
|
i++;
|
|
}
|
|
else if ( msg[i] == '\r' )
|
|
{
|
|
b[0] = '\r';
|
|
b[1] = '\n';
|
|
b += 2;
|
|
}
|
|
else if ( msg[i] == '\n' )
|
|
{
|
|
b[0] = '\r';
|
|
b[1] = '\n';
|
|
b += 2;
|
|
}
|
|
else if ( Q_IsColorString( &msg[i] ) )
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
*b= msg[i];
|
|
b++;
|
|
}
|
|
i++;
|
|
}
|
|
*b = 0;
|
|
bufLen = b - buffer;
|
|
|
|
s_totalChars += bufLen;
|
|
|
|
//
|
|
// replace selection instead of appending if we're overflowing
|
|
//
|
|
if ( s_totalChars > 0x7fff )
|
|
{
|
|
SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
|
|
s_totalChars = bufLen;
|
|
}
|
|
|
|
//
|
|
// put this text into the windows console
|
|
//
|
|
SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
|
|
SendMessage( s_wcd.hwndBuffer, EM_SCROLLCARET, 0, 0 );
|
|
SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, 0, (LPARAM) buffer );
|
|
}
|
|
|
|
|
|
/*
|
|
** Sys_SetErrorText
|
|
*/
|
|
void Sys_SetErrorText( const char *buf )
|
|
{
|
|
Q_strncpyz( s_wcd.errorString, buf, sizeof( s_wcd.errorString ) );
|
|
|
|
if ( !s_wcd.hwndErrorBox )
|
|
{
|
|
s_wcd.hwndErrorBox = CreateWindow( "static", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN,
|
|
6, 5, 526, 30,
|
|
s_wcd.hWnd,
|
|
( HMENU ) ERRORBOX_ID, // child window ID
|
|
g_wv.hInstance, NULL );
|
|
SendMessage( s_wcd.hwndErrorBox, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
|
|
SetWindowText( s_wcd.hwndErrorBox, s_wcd.errorString );
|
|
|
|
DestroyWindow( s_wcd.hwndInputLine );
|
|
s_wcd.hwndInputLine = NULL;
|
|
}
|
|
}
|
|
|
|
#endif
|