mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-11 07:11:36 +00:00
e75c19b45d
Functionality is still quite limited (no tab completion, history, etc.), but at least with this console you can scroll without locking up your server.
264 lines
6.5 KiB
C
264 lines
6.5 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
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "../qcommon/q_shared.h"
|
|
#include "../qcommon/qcommon.h"
|
|
#include "windows.h"
|
|
|
|
#define QCONSOLE_WIDTH 80
|
|
#define QCONSOLE_HEIGHT 30
|
|
|
|
#define QCONSOLE_THEME FOREGROUND_RED | \
|
|
BACKGROUND_RED | \
|
|
BACKGROUND_GREEN | \
|
|
BACKGROUND_BLUE
|
|
|
|
#define QCONSOLE_INPUT_RECORDS 1024
|
|
|
|
static int qconsole_chars = 0;
|
|
|
|
/*
|
|
==================
|
|
CON_Hide
|
|
==================
|
|
*/
|
|
void CON_Hide( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
==================
|
|
CON_Show
|
|
==================
|
|
*/
|
|
void CON_Show( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
==================
|
|
CON_Shutdown
|
|
==================
|
|
*/
|
|
void CON_Shutdown( void )
|
|
{
|
|
}
|
|
|
|
/*
|
|
==================
|
|
CON_Init
|
|
==================
|
|
*/
|
|
void CON_Init( void )
|
|
{
|
|
SMALL_RECT win = { 0, 0, QCONSOLE_WIDTH-1, QCONSOLE_HEIGHT-1 };
|
|
HANDLE hout;
|
|
COORD screen = { 0, 0 };
|
|
DWORD written;
|
|
CONSOLE_SCREEN_BUFFER_INFO binfo;
|
|
SMALL_RECT rect;
|
|
|
|
SetConsoleTitle("ioquake3 Dedicated Server Console");
|
|
|
|
hout = GetStdHandle( STD_OUTPUT_HANDLE );
|
|
|
|
SetConsoleWindowInfo( hout, TRUE, &win );
|
|
SetConsoleTextAttribute( hout, QCONSOLE_THEME );
|
|
FillConsoleOutputAttribute( hout, QCONSOLE_THEME, 63999, screen, &written );
|
|
|
|
// adjust console scroll to match up with cursor position
|
|
GetConsoleScreenBufferInfo( hout, &binfo );
|
|
rect.Top = binfo.srWindow.Top;
|
|
rect.Left = binfo.srWindow.Left;
|
|
rect.Bottom = binfo.srWindow.Bottom;
|
|
rect.Right = binfo.srWindow.Right;
|
|
rect.Top += ( binfo.dwCursorPosition.Y - binfo.srWindow.Bottom );
|
|
rect.Bottom = binfo.dwCursorPosition.Y;
|
|
SetConsoleWindowInfo( hout, TRUE, &rect );
|
|
|
|
}
|
|
|
|
/*
|
|
==================
|
|
CON_ConsoleInput
|
|
==================
|
|
*/
|
|
char *CON_ConsoleInput( void )
|
|
{
|
|
HANDLE hin, hout;
|
|
INPUT_RECORD buff[ QCONSOLE_INPUT_RECORDS ];
|
|
DWORD count = 0;
|
|
int i;
|
|
static char input[ 1024 ] = { "" };
|
|
int inputlen;
|
|
int newlinepos = -1;
|
|
CHAR_INFO line[ QCONSOLE_WIDTH ];
|
|
int linelen = 0;
|
|
|
|
inputlen = 0;
|
|
input[ 0 ] = '\0';
|
|
|
|
hin = GetStdHandle( STD_INPUT_HANDLE );
|
|
if( hin == INVALID_HANDLE_VALUE )
|
|
return NULL;
|
|
hout = GetStdHandle( STD_OUTPUT_HANDLE );
|
|
if( hout == INVALID_HANDLE_VALUE )
|
|
return NULL;
|
|
|
|
if( !PeekConsoleInput( hin, buff, QCONSOLE_INPUT_RECORDS, &count ) )
|
|
return NULL;
|
|
|
|
// if we have overflowed, start dropping oldest input events
|
|
if( count == QCONSOLE_INPUT_RECORDS )
|
|
{
|
|
ReadConsoleInput( hin, buff, 1, &count );
|
|
return NULL;
|
|
}
|
|
|
|
for( i = 0; i < count; i++ )
|
|
{
|
|
if( buff[ i ].EventType == KEY_EVENT &&
|
|
buff[ i ].Event.KeyEvent.bKeyDown )
|
|
{
|
|
if( buff[ i ].Event.KeyEvent.wVirtualKeyCode == VK_RETURN )
|
|
{
|
|
newlinepos = i;
|
|
break;
|
|
}
|
|
|
|
if( linelen < QCONSOLE_WIDTH &&
|
|
buff[ i ].Event.KeyEvent.uChar.AsciiChar )
|
|
{
|
|
if( buff[ i ].Event.KeyEvent.wVirtualKeyCode == VK_BACK )
|
|
{
|
|
if( linelen > 0 )
|
|
linelen--;
|
|
|
|
}
|
|
else
|
|
{
|
|
line[ linelen ].Attributes = QCONSOLE_THEME;
|
|
line[ linelen++ ].Char.AsciiChar =
|
|
buff[ i ].Event.KeyEvent.uChar.AsciiChar;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// provide visual feedback for incomplete commands
|
|
if( linelen != qconsole_chars )
|
|
{
|
|
CONSOLE_SCREEN_BUFFER_INFO binfo;
|
|
COORD writeSize = { QCONSOLE_WIDTH, 1 };
|
|
COORD writePos = { 0, 0 };
|
|
SMALL_RECT writeArea = { 0, 0, 0, 0 };
|
|
int i;
|
|
|
|
// keep track of this so we don't need to re-write to console every frame
|
|
qconsole_chars = linelen;
|
|
|
|
GetConsoleScreenBufferInfo( hout, &binfo );
|
|
|
|
// adjust scrolling to cursor when typing
|
|
if( binfo.dwCursorPosition.Y > binfo.srWindow.Bottom )
|
|
{
|
|
SMALL_RECT rect;
|
|
|
|
rect.Top = binfo.srWindow.Top;
|
|
rect.Left = binfo.srWindow.Left;
|
|
rect.Bottom = binfo.srWindow.Bottom;
|
|
rect.Right = binfo.srWindow.Right;
|
|
|
|
rect.Top += ( binfo.dwCursorPosition.Y - binfo.srWindow.Bottom );
|
|
rect.Bottom = binfo.dwCursorPosition.Y;
|
|
|
|
SetConsoleWindowInfo( hout, TRUE, &rect );
|
|
GetConsoleScreenBufferInfo( hout, &binfo );
|
|
}
|
|
|
|
writeArea.Left = 0;
|
|
writeArea.Top = binfo.srWindow.Bottom;
|
|
writeArea.Bottom = binfo.srWindow.Bottom;
|
|
writeArea.Right = QCONSOLE_WIDTH;
|
|
|
|
// pad line with ' ' to handle VK_BACK
|
|
for( i = linelen; i < QCONSOLE_WIDTH; i++ )
|
|
{
|
|
line[ i ].Char.AsciiChar = ' ';
|
|
line[ i ].Attributes = QCONSOLE_THEME;
|
|
}
|
|
|
|
WriteConsoleOutput( hout, line, writeSize, writePos, &writeArea );
|
|
|
|
if( binfo.dwCursorPosition.X != linelen )
|
|
{
|
|
COORD cursorPos = { 0, 0 };
|
|
|
|
cursorPos.X = linelen;
|
|
cursorPos.Y = binfo.srWindow.Bottom;
|
|
SetConsoleCursorPosition( hout, cursorPos );
|
|
}
|
|
}
|
|
|
|
// don't touch the input buffer if this is an incomplete command
|
|
if( newlinepos < 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
// add a newline
|
|
COORD cursorPos = { 0, 0 };
|
|
CONSOLE_SCREEN_BUFFER_INFO binfo;
|
|
|
|
GetConsoleScreenBufferInfo( hout, &binfo );
|
|
cursorPos.Y = binfo.srWindow.Bottom + 1;
|
|
SetConsoleCursorPosition( hout, cursorPos );
|
|
}
|
|
|
|
|
|
if( !ReadConsoleInput( hin, buff, newlinepos+1, &count ) )
|
|
return NULL;
|
|
|
|
for( i = 0; i < count; i++ )
|
|
{
|
|
if( buff[ i ].EventType == KEY_EVENT &&
|
|
buff[ i ].Event.KeyEvent.bKeyDown )
|
|
{
|
|
if( buff[ i ].Event.KeyEvent.wVirtualKeyCode == VK_BACK )
|
|
{
|
|
if( inputlen > 0 )
|
|
input[ --inputlen ] = '\0';
|
|
continue;
|
|
}
|
|
if( inputlen < ( sizeof( input ) - 1 ) &&
|
|
buff[ i ].Event.KeyEvent.uChar.AsciiChar )
|
|
{
|
|
input[ inputlen++ ] = buff[ i ].Event.KeyEvent.uChar.AsciiChar;
|
|
input[ inputlen ] = '\0';
|
|
}
|
|
}
|
|
}
|
|
if( !inputlen )
|
|
return NULL;
|
|
return input;
|
|
}
|