The console is now awesome on Windows too.

develop
Petr Mrázek 2011-07-15 19:58:17 +02:00
parent 459d48d75a
commit b85f196dc4
2 changed files with 366 additions and 267 deletions

@ -1,30 +1,11 @@
/* /*
https://github.com/peterix/dfhack https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) Copyright (c) 2011 Petr Mrázek <peterix@gmail.com>
This software is provided 'as-is', without any express or implied A thread-safe logging console with a line editor.
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any Based on linenoise:
purpose, including commercial applications, and to alter it and linenoise -- guerrilla line editing library against the idea that a
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/*
Parts of this code are based on linenoise:
linenoise.c -- guerrilla line editing library against the idea that a
line editing lib needs to be 20,000 lines of C code. line editing lib needs to be 20,000 lines of C code.
You can find the latest source code at: You can find the latest source code at:
@ -144,11 +125,6 @@ namespace DFHack
class Private class Private
{ {
public: public:
enum console_state
{
con_unclaimed,
con_lineedit
};
Private() Private()
{ {
dfout_C = NULL; dfout_C = NULL;
@ -199,6 +175,7 @@ namespace DFHack
color(Console::COLOR_LIGHTRED); color(Console::COLOR_LIGHTRED);
int ret = vfprintf( dfout_C, format, vl ); int ret = vfprintf( dfout_C, format, vl );
reset_color(); reset_color();
return ret;
} }
} }
/// Print a formatted string, like printf, in red /// Print a formatted string, like printf, in red
@ -592,7 +569,12 @@ namespace DFHack
// state variables // state variables
bool rawmode; // is raw mode active? bool rawmode; // is raw mode active?
termios orig_termios; // saved/restored by raw mode termios orig_termios; // saved/restored by raw mode
int state; // current state // current state
enum console_state
{
con_unclaimed,
con_lineedit
} state;
std::string prompt; // current prompt string std::string prompt; // current prompt string
std::string raw_buffer; // current raw mode buffer std::string raw_buffer; // current raw mode buffer
int raw_cursor; // cursor position in the buffer int raw_cursor; // cursor position in the buffer
@ -698,12 +680,6 @@ void Console::cursor(bool enable)
SDL_mutexV(d->wlock); SDL_mutexV(d->wlock);
} }
void Console::msleep (unsigned int msec)
{
if (msec > 1000) sleep(msec/1000000);
usleep((msec % 1000000) * 1000);
}
// push to front, remove from back if we are above maximum. ignore immediate duplicates // push to front, remove from back if we are above maximum. ignore immediate duplicates
void Console::history_add(const std::string & command) void Console::history_add(const std::string & command)
{ {
@ -719,3 +695,9 @@ int Console::lineedit(const std::string & prompt, std::string & output)
SDL_mutexV(d->wlock); SDL_mutexV(d->wlock);
return ret; return ret;
} }
void Console::msleep (unsigned int msec)
{
if (msec > 1000) sleep(msec/1000000);
usleep((msec % 1000000) * 1000);
}

@ -1,33 +1,11 @@
/* /*
https://github.com/peterix/dfhack https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) Copyright (c) 2011 Petr Mrázek <peterix@gmail.com>
This software is provided 'as-is', without any express or implied A thread-safe logging console with a line editor for windows.
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any Based on linenoise win32 port,
purpose, including commercial applications, and to alter it and copyright 2010, Jon Griffiths <jon_p_griffiths at yahoo dot com>.
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/*
Some functions are based on the linenoise win32 port:
linenoise_win32.c -- Linenoise win32 port.
Modifications copyright 2010, Jon Griffiths <jon_p_griffiths at yahoo dot com>.
All rights reserved. All rights reserved.
Based on linenoise, copyright 2010, Salvatore Sanfilippo <antirez at gmail dot com>. Based on linenoise, copyright 2010, Salvatore Sanfilippo <antirez at gmail dot com>.
The original linenoise can be found at: http://github.com/antirez/linenoise The original linenoise can be found at: http://github.com/antirez/linenoise
@ -74,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <string> #include <string>
#include "dfhack/Console.h" #include "dfhack/Console.h"
#include "dfhack/FakeSDL.h"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
@ -97,139 +76,105 @@ namespace DFHack
console_out = 0; console_out = 0;
ConsoleWindow = 0; ConsoleWindow = 0;
default_attributes = 0; default_attributes = 0;
state = con_unclaimed;
raw_cursor = 0;
}; };
void output(const char* str, size_t len, int x, int y) /// Print a formatted string, like printf
int print(const char * format, ...)
{ {
COORD pos = { (SHORT)x, (SHORT)y }; va_list args;
DWORD count = 0; va_start( args, format );
WriteConsoleOutputCharacterA(console_out, str, len, pos, &count); int ret = vprint( format, args );
va_end( args );
return ret;
} }
int vprint(const char * format, va_list vl)
FILE * dfout_C; {
duthomhas::stdiobuf * stream_o; if(state == con_lineedit)
int rawmode; /* for atexit() function to check if restore is needed*/ {
std::deque <std::string> history; clearline();
int ret = vfprintf( dfout_C, format, vl );
HANDLE console_in; prompt_refresh();
HANDLE console_out; return ret;
HWND ConsoleWindow; }
WORD default_attributes; else return vfprintf( dfout_C, format, vl );
}; }
} int vprinterr(const char * format, va_list vl)
{
if(state == con_lineedit)
Console::Console():std::ostream(0), std::ios(0) {
{ color(Console::COLOR_LIGHTRED);
d = 0; clearline();
} int ret = vfprintf( dfout_C, format, vl );
reset_color();
Console::~Console() prompt_refresh();
{ return ret;
} }
else
bool Console::init(void) {
{ color(Console::COLOR_LIGHTRED);
d = new Private(); int ret = vfprintf( dfout_C, format, vl );
int hConHandle; reset_color();
long lStdHandle; return ret;
CONSOLE_SCREEN_BUFFER_INFO coninfo; }
FILE *fp; }
DWORD oldMode, newMode; /// Print a formatted string, like printf, in red
int printerr(const char * format, ...)
// Allocate a console! {
AllocConsole();
d->ConsoleWindow = GetConsoleWindow();
HMENU hm = GetSystemMenu(d->ConsoleWindow,false);
DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND);
// set the screen buffer to be big enough to let us scroll text
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
d->default_attributes = coninfo.wAttributes;
coninfo.dwSize.Y = MAX_CONSOLE_LINES; // How many lines do you want to have in the console buffer
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
// redirect unbuffered STDOUT to the console
d->console_out = GetStdHandle(STD_OUTPUT_HANDLE);
lStdHandle = (long)d->console_out;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
d->dfout_C = _fdopen( hConHandle, "w" );
setvbuf( d->dfout_C, NULL, _IONBF, 0 );
// redirect unbuffered STDIN to the console
d->console_in = GetStdHandle(STD_INPUT_HANDLE);
lStdHandle = (long)d->console_in;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "r" );
*stdin = *fp;
setvbuf( stdin, NULL, _IONBF, 0 );
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),&oldMode);
newMode = oldMode | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),newMode);
std::ios::sync_with_stdio();
// make our own weird streams so our IO isn't redirected
d->stream_o = new duthomhas::stdiobuf(d->dfout_C);
rdbuf(d->stream_o);
std::cin.tie(this);
clear();
return true;
}
bool Console::shutdown(void)
{
FreeConsole();
return true;
}
int Console::print( const char* format, ... )
{
va_list args; va_list args;
va_start( args, format ); va_start( args, format );
int ret = vfprintf( d->dfout_C, format, args ); int ret = vprinterr( format, args );
va_end( args ); va_end( args );
return ret; return ret;
} }
int get_columns(void)
int Console::get_columns(void) {
{
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 }; CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(d->console_out, &inf); GetConsoleScreenBufferInfo(console_out, &inf);
return (size_t)inf.dwSize.X; return (size_t)inf.dwSize.X;
} }
int get_rows(void)
int Console::get_rows(void) {
{
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 }; CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(d->console_out, &inf); GetConsoleScreenBufferInfo(console_out, &inf);
return (size_t)inf.dwSize.Y; return (size_t)inf.dwSize.Y;
} }
void clear()
void Console::clear() {
{
system("cls"); system("cls");
} }
void clearline()
void Console::gotoxy(int x, int y) {
{ CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(console_out, &inf);
// Blank to EOL
char* tmp = (char*)malloc(inf.dwSize.X);
memset(tmp, ' ', inf.dwSize.X);
output(tmp, inf.dwSize.X, 0, inf.dwCursorPosition.Y);
free(tmp);
COORD coord = {0, inf.dwCursorPosition.Y}; // Windows uses 0-based coordinates
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void gotoxy(int x, int y)
{
COORD coord = {x-1, y-1}; // Windows uses 0-based coordinates COORD coord = {x-1, y-1}; // Windows uses 0-based coordinates
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
} }
void Console::color(int index) void color(int index)
{ {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, index); SetConsoleTextAttribute(hConsole, index);
} }
void Console::reset_color( void ) void reset_color( void )
{ {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, d->default_attributes); SetConsoleTextAttribute(hConsole, default_attributes);
} }
void Console::cursor(bool enable) void cursor(bool enable)
{ {
if(enable) if(enable)
{ {
HANDLE hConsoleOutput; HANDLE hConsoleOutput;
@ -248,35 +193,27 @@ void Console::cursor(bool enable)
structCursorInfo.bVisible = FALSE; structCursorInfo.bVisible = FALSE;
SetConsoleCursorInfo( hConsoleOutput, &structCursorInfo ); SetConsoleCursorInfo( hConsoleOutput, &structCursorInfo );
} }
} }
void Console::msleep (unsigned int msec)
{
Sleep(msec);
}
int Console::enable_raw()
{
return 0;
}
void Console::disable_raw() void output(const char* str, size_t len, int x, int y)
{ {
/* Nothing to do yet */ COORD pos = { (SHORT)x, (SHORT)y };
} DWORD count = 0;
WriteConsoleOutputCharacterA(console_out, str, len, pos, &count);
}
void Console::prompt_refresh( const std::string& prompt, const std::string& buffer, size_t pos) void prompt_refresh()
{ {
size_t cols = get_columns(); size_t cols = get_columns();
size_t plen = prompt.size(); size_t plen = prompt.size();
const char * buf = buffer.c_str(); const char * buf = raw_buffer.c_str();
size_t len = buffer.size(); size_t len = raw_buffer.size();
while ((plen + pos) >= cols) while ((plen + raw_cursor) >= cols)
{ {
buf++; buf++;
len--; len--;
pos--; raw_cursor--;
} }
while (plen + len > cols) while (plen + len > cols)
{ {
@ -284,147 +221,327 @@ void Console::prompt_refresh( const std::string& prompt, const std::string& buff
} }
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 }; CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(d->console_out, &inf); GetConsoleScreenBufferInfo(console_out, &inf);
d->output(prompt.c_str(), plen, 0, inf.dwCursorPosition.Y); output(prompt.c_str(), plen, 0, inf.dwCursorPosition.Y);
d->output(buf, len, plen, inf.dwCursorPosition.Y); output(buf, len, plen, inf.dwCursorPosition.Y);
if (plen + len < (size_t)inf.dwSize.X) if (plen + len < (size_t)inf.dwSize.X)
{ {
/* Blank to EOL */ // Blank to EOL
char* tmp = (char*)malloc(inf.dwSize.X - (plen + len)); char* tmp = (char*)malloc(inf.dwSize.X - (plen + len));
memset(tmp, ' ', inf.dwSize.X - (plen + len)); memset(tmp, ' ', inf.dwSize.X - (plen + len));
d->output(tmp, inf.dwSize.X - (plen + len), len + plen, inf.dwCursorPosition.Y); output(tmp, inf.dwSize.X - (plen + len), len + plen, inf.dwCursorPosition.Y);
free(tmp); free(tmp);
} }
inf.dwCursorPosition.X = (SHORT)(pos + plen); inf.dwCursorPosition.X = (SHORT)(raw_cursor + plen);
SetConsoleCursorPosition(d->console_out, inf.dwCursorPosition); SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
} }
int Console::prompt_loop(const std::string & prompt, std::string & buffer) int prompt_loop()
{ {
buffer.clear(); // make sure the buffer is empty! raw_buffer.clear(); // make sure the buffer is empty!
size_t plen = prompt.size(); size_t plen = prompt.size();
size_t pos = 0; raw_cursor = 0;
int history_index = 0; int history_index = 0;
/* The latest history entry is always our current buffer, that // The latest history entry is always our current buffer, that
* initially is just an empty string. */ // initially is just an empty string.
const std::string empty; const std::string empty;
history_add(empty); history_add(empty);
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 }; CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(d->console_out, &inf); GetConsoleScreenBufferInfo(console_out, &inf);
size_t cols = inf.dwSize.X; size_t cols = inf.dwSize.X;
d->output(prompt.c_str(), plen, 0, inf.dwCursorPosition.Y); output(prompt.c_str(), plen, 0, inf.dwCursorPosition.Y);
inf.dwCursorPosition.X = (SHORT)plen; inf.dwCursorPosition.X = (SHORT)plen;
SetConsoleCursorPosition(d->console_out, inf.dwCursorPosition); SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
while (1) while (1)
{ {
INPUT_RECORD rec; INPUT_RECORD rec;
DWORD count; DWORD count;
ReadConsoleInputA(d->console_in, &rec, 1, &count); SDL_mutexV(wlock);
ReadConsoleInputA(console_in, &rec, 1, &count);
SDL_mutexP(wlock);
if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown) if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown)
continue; continue;
switch (rec.Event.KeyEvent.wVirtualKeyCode) switch (rec.Event.KeyEvent.wVirtualKeyCode)
{ {
case VK_RETURN: // enter case VK_RETURN: // enter
d->history.pop_front(); history.pop_front();
return buffer.size(); return raw_buffer.size();
case VK_BACK: // backspace case VK_BACK: // backspace
if (pos > 0 && buffer.size() > 0) if (raw_cursor > 0 && raw_buffer.size() > 0)
{ {
buffer.erase(pos-1,1); raw_buffer.erase(raw_cursor-1,1);
pos--; raw_cursor--;
prompt_refresh(prompt,buffer,pos); prompt_refresh();
} }
break; break;
case VK_LEFT: // left arrow case VK_LEFT: // left arrow
if (pos > 0) if (raw_cursor > 0)
{ {
pos--; raw_cursor--;
prompt_refresh(prompt,buffer,pos); prompt_refresh();
} }
break; break;
case VK_RIGHT: // right arrow case VK_RIGHT: // right arrow
if (pos != buffer.size()) if (raw_cursor != raw_buffer.size())
{ {
pos++; raw_cursor++;
prompt_refresh(prompt,buffer,pos); prompt_refresh();
} }
break; break;
case VK_UP: case VK_UP:
case VK_DOWN: case VK_DOWN:
/* up and down arrow: history */ // up and down arrow: history
if (d->history.size() > 1) if (history.size() > 1)
{ {
/* Update the current history entry before to // Update the current history entry before to
* overwrite it with tne next one. */ // overwrite it with tne next one.
d->history[history_index] = buffer; history[history_index] = raw_buffer;
/* Show the new entry */ // Show the new entry
history_index += (rec.Event.KeyEvent.wVirtualKeyCode == VK_UP) ? 1 : -1; history_index += (rec.Event.KeyEvent.wVirtualKeyCode == VK_UP) ? 1 : -1;
if (history_index < 0) if (history_index < 0)
{ {
history_index = 0; history_index = 0;
break; break;
} }
else if (history_index >= d->history.size()) else if (history_index >= history.size())
{ {
history_index = d->history.size()-1; history_index = history.size()-1;
break; break;
} }
buffer = d->history[history_index]; raw_buffer = history[history_index];
pos = buffer.size(); raw_cursor = raw_buffer.size();
prompt_refresh(prompt,buffer,pos); prompt_refresh();
} }
break; break;
case VK_DELETE: case VK_DELETE:
// delete // delete
if (buffer.size() > 0 && pos < buffer.size()) if (raw_buffer.size() > 0 && raw_cursor < raw_buffer.size())
{ {
buffer.erase(pos,1); raw_buffer.erase(raw_cursor,1);
prompt_refresh(prompt,buffer,pos); prompt_refresh();
} }
break; break;
case VK_HOME: case VK_HOME:
pos = 0; raw_cursor = 0;
prompt_refresh(prompt,buffer,pos); prompt_refresh();
break; break;
case VK_END: case VK_END:
pos = buffer.size(); raw_cursor = raw_buffer.size();
prompt_refresh(prompt,buffer,pos); prompt_refresh();
break; break;
default: default:
if (rec.Event.KeyEvent.uChar.AsciiChar < ' ' || if (rec.Event.KeyEvent.uChar.AsciiChar < ' ' ||
rec.Event.KeyEvent.uChar.AsciiChar > '~') rec.Event.KeyEvent.uChar.AsciiChar > '~')
continue; continue;
if (buffer.size() == pos) if (raw_buffer.size() == raw_cursor)
buffer.append(1,rec.Event.KeyEvent.uChar.AsciiChar); raw_buffer.append(1,rec.Event.KeyEvent.uChar.AsciiChar);
else else
buffer.insert(pos,1,rec.Event.KeyEvent.uChar.AsciiChar); raw_buffer.insert(raw_cursor,1,rec.Event.KeyEvent.uChar.AsciiChar);
pos++; raw_cursor++;
prompt_refresh(prompt,buffer,pos); prompt_refresh();
break; break;
} }
} }
}
int lineedit(const std::string & prompt, std::string & output)
{
output.clear();
int count;
state = con_lineedit;
this->prompt = prompt;
count = prompt_loop();
if(count != -1)
output = raw_buffer;
state = con_unclaimed;
print("\n");
return count;
}
// push to front, remove from back if we are above maximum. ignore immediate duplicates
void history_add(const std::string & command)
{
// if current command = last in history -> do not add. Always add if history is empty.
if(!history.empty() && history.front() == command)
return;
history.push_front(command);
if(history.size() > 100)
history.pop_back();
}
FILE * dfout_C;
duthomhas::stdiobuf * stream_o;
int rawmode; /* for atexit() function to check if restore is needed*/
std::deque <std::string> history;
HANDLE console_in;
HANDLE console_out;
HWND ConsoleWindow;
WORD default_attributes;
// current state
enum console_state
{
con_unclaimed,
con_lineedit
} state;
std::string prompt; // current prompt string
std::string raw_buffer; // current raw mode buffer
int raw_cursor; // cursor position in the buffer
// locks
SDL::Mutex *wlock;
};
}
Console::Console():std::ostream(0), std::ios(0)
{
d = 0;
}
Console::~Console()
{
}
bool Console::init(void)
{
d = new Private();
int hConHandle;
long lStdHandle;
CONSOLE_SCREEN_BUFFER_INFO coninfo;
FILE *fp;
DWORD oldMode, newMode;
// Allocate a console!
AllocConsole();
d->ConsoleWindow = GetConsoleWindow();
HMENU hm = GetSystemMenu(d->ConsoleWindow,false);
DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND);
// set the screen buffer to be big enough to let us scroll text
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
d->default_attributes = coninfo.wAttributes;
coninfo.dwSize.Y = MAX_CONSOLE_LINES; // How many lines do you want to have in the console buffer
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
// redirect unbuffered STDOUT to the console
d->console_out = GetStdHandle(STD_OUTPUT_HANDLE);
lStdHandle = (long)d->console_out;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
d->dfout_C = _fdopen( hConHandle, "w" );
setvbuf( d->dfout_C, NULL, _IONBF, 0 );
// redirect unbuffered STDIN to the console
d->console_in = GetStdHandle(STD_INPUT_HANDLE);
lStdHandle = (long)d->console_in;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "r" );
*stdin = *fp;
setvbuf( stdin, NULL, _IONBF, 0 );
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),&oldMode);
newMode = oldMode | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),newMode);
std::ios::sync_with_stdio();
// make our own weird streams so our IO isn't redirected
d->stream_o = new duthomhas::stdiobuf(d->dfout_C);
rdbuf(d->stream_o);
std::cin.tie(this);
d->wlock = SDL_CreateMutex();
clear();
return true;
}
// FIXME: looks awfully empty, doesn't it?
bool Console::shutdown(void)
{
FreeConsole();
return true;
}
int Console::print( const char* format, ... )
{
va_list args;
SDL_mutexP(d->wlock);
va_start( args, format );
int ret = d->vprint(format, args);
va_end(args);
SDL_mutexV(d->wlock);
return ret;
}
int Console::printerr( const char* format, ... )
{
va_list args;
SDL_mutexP(d->wlock);
va_start( args, format );
int ret = d->vprinterr(format, args);
va_end(args);
SDL_mutexV(d->wlock);
return ret;
}
int Console::get_columns(void)
{
return d->get_columns();
}
int Console::get_rows(void)
{
return d->get_rows();
}
void Console::clear()
{
SDL_mutexP(d->wlock);
d->clear();
SDL_mutexV(d->wlock);
}
void Console::gotoxy(int x, int y)
{
SDL_mutexP(d->wlock);
d->gotoxy(x,y);
SDL_mutexV(d->wlock);
}
void Console::color(color_value index)
{
SDL_mutexP(d->wlock);
d->color(index);
SDL_mutexV(d->wlock);
}
void Console::reset_color( void )
{
SDL_mutexP(d->wlock);
d->reset_color();
SDL_mutexV(d->wlock);
}
void Console::cursor(bool enable)
{
SDL_mutexP(d->wlock);
d->cursor(enable);
SDL_mutexV(d->wlock);
} }
// push to front, remove from back if we are above maximum. ignore immediate duplicates // push to front, remove from back if we are above maximum. ignore immediate duplicates
void Console::history_add(const std::string & command) void Console::history_add(const std::string & command)
{ {
if(d->history.front() == command) SDL_mutexP(d->wlock);
return; d->history_add(command);
d->history.push_front(command); SDL_mutexV(d->wlock);
if(d->history.size() > 100)
d->history.pop_back();
} }
int Console::lineedit(const std::string & prompt, std::string & output) int Console::lineedit(const std::string & prompt, std::string & output)
{ {
output.clear(); SDL_mutexP(d->wlock);
int count; int ret = d->lineedit(prompt,output);
if (enable_raw() == -1) SDL_mutexV(d->wlock);
return -1; return ret;
count = prompt_loop(prompt,output); }
disable_raw();
*this << std::endl; void Console::msleep (unsigned int msec)
return count; {
Sleep(msec);
} }