#include #include #include #include using std::string; class AsyncConsole { public: // Tworzy konsolę // Tworzyć tylko pojedynczy obiekt tej klasy. AsyncConsole(); // Zamyka konsolę ~AsyncConsole(); // Zmienia tytuł okna konsoli void SetTitle(const string &Title); // Zmienia bieżący kolor wyjścia // Podawać kombinację stałych FOREGROUND_ i BACKGROUND_ z WinAPI // udokumentowanych w opisie funkcji SetConsoleTextAttribute. void SetOutputColor(WORD Color); // Zmienia kolor używany do wejścia void SetInputColor(WORD Color); // Zapisuje podany tekst na wyjście konsoli void Write(const string &s); // Zapisuje linijkę tekstu na wyjście konsoli void Writeln(const string &s); // Zwraca true jeśli kolejka poleceń jest pusta bool InputQueueEmpty(); // Zwraca true i pierwsze polecenie z kolejki, jeśli nie jest pusta // Usuwa to polecenie. // Jesli kolejka jest pusta, zwraca false. bool GetInput(string *s); // Czeka na wejście zatrzumując wątek, który to wywoła void WaitForInput(); // Zwraca uchwyt do eventa, żeby można sobie urządzić czekanie na niego we // własnym zakresie HANDLE GetWaitEvent() { return m_Event; } private: static const DWORD BUFFER_SIZE = 1024; HANDLE m_HandleIn; HANDLE m_HandleOut; CRITICAL_SECTION m_CriticalSection; // Niesygnalizowany = kolejka pusta // Sygnalizowany = kolejka niepusta HANDLE m_Event; HANDLE m_ThreadHandle; WORD m_InputColor; WORD m_OutputColor; std::vector m_Buffer; std::queue m_Queue; static DWORD WINAPI ReadThreadProc_s(void *This); DWORD ReadThreadProc(); }; AsyncConsole::AsyncConsole() : m_HandleIn(0), m_HandleOut(0), m_ThreadHandle(0), m_Event(0) { m_Buffer.resize(BUFFER_SIZE+1); AllocConsole(); m_HandleIn = GetStdHandle(STD_INPUT_HANDLE); m_HandleOut = GetStdHandle(STD_OUTPUT_HANDLE); SetInputColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); SetOutputColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); InitializeCriticalSection(&m_CriticalSection); m_Event = CreateEvent(0, TRUE, FALSE, 0); m_ThreadHandle = CreateThread(0, 0, &ReadThreadProc_s, this, 0, 0); } AsyncConsole::~AsyncConsole() { TerminateThread(m_ThreadHandle, 0); CloseHandle(m_Event); DeleteCriticalSection(&m_CriticalSection); FreeConsole(); } void AsyncConsole::SetTitle(const string &Title) { SetConsoleTitle(Title.c_str()); } void AsyncConsole::SetOutputColor(WORD Color) { m_OutputColor = Color; } void AsyncConsole::SetInputColor(WORD Color) { m_InputColor = Color; SetConsoleTextAttribute(m_HandleOut, Color); } void AsyncConsole::Write(const string &s) { DWORD Foo; SetConsoleTextAttribute(m_HandleOut, m_OutputColor); WriteConsole(m_HandleOut, s.data(), (DWORD)s.length(), &Foo, 0); SetConsoleTextAttribute(m_HandleOut, m_InputColor); } void AsyncConsole::Writeln(const string &s) { Write(s); Write("\r\n"); } DWORD WINAPI AsyncConsole::ReadThreadProc_s(void *This) { return ((AsyncConsole*)This)->ReadThreadProc(); } DWORD AsyncConsole::ReadThreadProc() { DWORD CharactersRead; string s; while (true) { ReadConsole(m_HandleIn, &m_Buffer[0], BUFFER_SIZE, &CharactersRead, 0); EnterCriticalSection(&m_CriticalSection); s.assign(&m_Buffer[0], CharactersRead-2); // -2, bo bez końca wiersza m_Queue.push(s); s.clear(); SetEvent(m_Event); LeaveCriticalSection(&m_CriticalSection); } return 0; } bool AsyncConsole::InputQueueEmpty() { EnterCriticalSection(&m_CriticalSection); bool R = m_Queue.empty(); LeaveCriticalSection(&m_CriticalSection); return R; } bool AsyncConsole::GetInput(string *s) { EnterCriticalSection(&m_CriticalSection); bool R = m_Queue.empty(); if (!R) { *s = m_Queue.front(); m_Queue.pop(); if (m_Queue.empty()) ResetEvent(m_Event); } LeaveCriticalSection(&m_CriticalSection); return !R; } void AsyncConsole::WaitForInput() { WaitForSingleObject(m_Event, INFINITE); } int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, char *CmdLine, int CmdShow) { AsyncConsole con; con.SetTitle("My AsyncConsole Title"); con.SetOutputColor(FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_BLUE); while (true) { con.Writeln("Sth..."); Sleep(2000); string s; while (con.GetInput(&s)) { if (s == "exit") return 0; else if (s == "wait") { con.Writeln("Waiting..."); con.WaitForInput(); } else con.Writeln("You have entered: \""+s+"\""); } } } /* Działanie programu można w każdej chwili przerwać naciskając w konsoli CTRL+C lub CTRL+BREAK. */