/****************************************************************************** File: Console.cpp Project: Console library Copyright: (c) 2002 Joost Ronkes Agerbeek Author: Joost Ronkes Agerbeek Date: November 15, 2002 ******************************************************************************/ #include "Console.h" /** * Clears the console. */ void ClearScreen() { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_OUTPUT_HANDLE); // set coordinate to upperleft corner COORD myCoord; myCoord.X = 0; myCoord.Y = 0; // get console buffer size CONSOLE_SCREEN_BUFFER_INFO myInfo; GetConsoleScreenBufferInfo(myHandle, &myInfo); int mySize = myInfo.dwSize.X * myInfo.dwSize.Y; // write null characters to screen DWORD myNumberOfChars; ::FillConsoleOutputCharacter(myHandle, 0, mySize, myCoord, &myNumberOfChars); // write standard color to screen ::FillConsoleOutputAttribute(myHandle, 0x07, mySize, myCoord, &myNumberOfChars); // position cursor at upperleft corner ::SetConsoleCursorPosition(myHandle, myCoord); } /** * Waits for a key to be pressed and returns the key's ASCII code. * * @returns the ASCII code of the pressed key */ char GetKey() { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_INPUT_HANDLE); // read input until a key has been pressed INPUT_RECORD myEvent[1]; DWORD myNumberOfEvents; do { // read input ::ReadConsoleInput(myHandle, myEvent, 1, &myNumberOfEvents); } while ((myEvent[0].EventType != KEY_EVENT) || (myEvent[0].Event.KeyEvent.bKeyDown != TRUE)); // return ASCII code return myEvent[0].Event.KeyEvent.uChar.AsciiChar; } /** * Waits for a key to be pressed and returns the key's virtual key code. * * @returns the virtual key code of the pressed key */ WORD GetVirtualKey() { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_INPUT_HANDLE); // read input until a key has been pressed INPUT_RECORD myEvent[1]; DWORD myNumberOfEvents; do { // read input ::ReadConsoleInput(myHandle, myEvent, 1, &myNumberOfEvents); } while ((myEvent[0].EventType != KEY_EVENT) || (myEvent[0].Event.KeyEvent.bKeyDown != TRUE)); // return ASCII code return myEvent[0].Event.KeyEvent.wVirtualKeyCode; } /** * Hides the text cursor. * * @see ShowCursor() */ void HideCursor() { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_OUTPUT_HANDLE); // get current cursor information CONSOLE_CURSOR_INFO myCursorInfo; ::GetConsoleCursorInfo(myHandle, &myCursorInfo); // hide cursor myCursorInfo.bVisible = false; ::SetConsoleCursorInfo(myHandle, &myCursorInfo); } /** * Moves the text cursor to the specified location in the console. * * @param x the column in which to position the cursor * @param y the row in which to position the cursor */ void MoveCursor(unsigned short x, unsigned short y) { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_OUTPUT_HANDLE); // set coordinate cursor will be moved to COORD myCoord; myCoord.X = x; myCoord.Y = y; // position cursor ::SetConsoleCursorPosition(myHandle, myCoord); } /** * Returns the ASCII code of the first key that is present in the input buffer, * without removing the key from the buffer. * * @param absent indicates the ASCII code that should be returned when there * is no key present in the input buffer; default is 0 */ char PeekKey(char absent) { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_INPUT_HANDLE); // get number of console input events in buffer DWORD myNumberOfEvents; ::GetNumberOfConsoleInputEvents(myHandle, &myNumberOfEvents); // create buffer to hold events INPUT_RECORD* myEvents; myEvents = new INPUT_RECORD[myNumberOfEvents]; // peek input buffer PeekConsoleInput(myHandle, myEvents, myNumberOfEvents, &myNumberOfEvents); // loop through buffer in search for a key down event int i; for (i = 0; i < myNumberOfEvents; i++) { // is this a key down event? if ((myEvents[i].EventType == KEY_EVENT) && (myEvents[i].Event.KeyEvent.bKeyDown == TRUE)) { // yes, break out of loop break; } } // was a key event found? if (i == myNumberOfEvents) { // no, return failure return absent; } // return ASCII code of found key return myEvents[i].Event.KeyEvent.uChar.AsciiChar; } /** * Returns the virtual key code of the first key that is present in the input * buffer, without removing the key from the buffer. * * @returns the virtual key code of the first key in the input buffer or 0 if * there is no key present */ WORD PeekVirtualKey() { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_INPUT_HANDLE); // get number of console input events in buffer DWORD myNumberOfEvents; ::GetNumberOfConsoleInputEvents(myHandle, &myNumberOfEvents); // create buffer to hold events INPUT_RECORD* myEvents; myEvents = new INPUT_RECORD[myNumberOfEvents]; // peek input buffer PeekConsoleInput(myHandle, myEvents, myNumberOfEvents, &myNumberOfEvents); // loop through buffer in search for a key down event int i; for (i = 0; i < myNumberOfEvents; i++) { // is this a key down event? if ((myEvents[i].EventType == KEY_EVENT) && (myEvents[i].Event.KeyEvent.bKeyDown == TRUE)) { // yes, break out of loop break; } } // was a key event found? if (i == myNumberOfEvents) { // no, return failure return 0; } // return virtual key code of found key return myEvents[i].Event.KeyEvent.wVirtualKeyCode; } /** * Sets the size of the cursor. * * @param size the percentage (1-100) of the character cell that is filled * by the cursor. */ void SetCursorSize(unsigned short size) { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_OUTPUT_HANDLE); // get current cursor information CONSOLE_CURSOR_INFO myCursorInfo; ::GetConsoleCursorInfo(myHandle, &myCursorInfo); // hide cursor myCursorInfo.dwSize = size; ::SetConsoleCursorInfo(myHandle, &myCursorInfo); } /** * Sets the title of the console window. * * @param title the title of the console window */ void SetTitle(std::string title) { ::SetConsoleTitle(title.c_str()); } /** * Shows the text cursor. * * @see HideCursor() */ void ShowCursor() { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_OUTPUT_HANDLE); // get current cursor information CONSOLE_CURSOR_INFO myCursorInfo; ::GetConsoleCursorInfo(myHandle, &myCursorInfo); // hide cursor myCursorInfo.bVisible = true; ::SetConsoleCursorInfo(myHandle, &myCursorInfo); } /** * Change the color of the specified block without changing the text inside the * block. * * @param left the left-most column of the block * @param top the top row of the block * @param right the right-most column of the block * @param bottom the bottom row of the block * @param foreColor the foreground color of the block * @param backColor the background color of the block */ void WriteColorBlock(unsigned short left, unsigned short top, unsigned short right, unsigned short bottom, unsigned short foreColor, unsigned short backColor) { // is box valid? if ((left > right) || (top > bottom)) { // no, exit return; } // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_OUTPUT_HANDLE); // set coordinate to start writing COORD myCoord; myCoord.X = left; myCoord.Y = top; // calculate line length int myLineLength = right - left + 1; // create color buffer LPWORD myColorBuffer; myColorBuffer = new WORD[myLineLength]; memset(myColorBuffer, (backColor << 4) + foreColor, sizeof(WORD) * myLineLength); // loop over lines for (myCoord.Y = top; myCoord.Y <= bottom; myCoord.Y++) { // set color DWORD myNumberOfColorsWritten; ::WriteConsoleOutputAttribute(myHandle, myColorBuffer, myLineLength, myCoord, &myNumberOfColorsWritten); } } /** * Writes text to the console at the specified position and in the specified * color. If you don't specify the color of the text, it defaults to white on * black. WriteText does not update the position of the cursor. * * @param text the text to write to the screen * @param x the column in which to start writing the text * @param y the row in which to start writing the text * @param foreColor the foreground color of the text * @param backColor the background color of the text */ void WriteText(std::string text, unsigned short x, unsigned short y, unsigned short foreColor, unsigned short backColor) { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_OUTPUT_HANDLE); // set coordinate to start writing COORD myCoord; myCoord.X = x; myCoord.Y = y; // create color buffer LPWORD myColorBuffer; myColorBuffer = new WORD[text.length()]; memset(myColorBuffer, (backColor << 4) + foreColor, sizeof(WORD) * text.length()); // write text to screen DWORD myNumberOfCharsWritten; ::WriteConsoleOutputCharacter(myHandle, text.c_str(), text.length(), myCoord, &myNumberOfCharsWritten); // set color ::WriteConsoleOutputAttribute(myHandle, myColorBuffer, text.length(), myCoord, &myNumberOfCharsWritten); } /** * Writes the specified character to the console at the specified position and * in the specified color. If you don't specify the color of the text, it * defaults to white on black. WriteText does not update the position of the * cursor. * * @param character the character to write to the screen * @param x the column in which to start writing the text * @param y the row in which to start writing the text * @param foreColor the foreground color of the text * @param backColor the background color of the text */ void WriteText(char character, unsigned short x, unsigned short y, unsigned short foreColor, unsigned short backColor) { // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_OUTPUT_HANDLE); // set coordinate to start writing COORD myCoord; myCoord.X = x; myCoord.Y = y; // create color buffer WORD myColorBuffer = (backColor << 4) + foreColor; // write text to screen DWORD myNumberOfCharsWritten; ::WriteConsoleOutputCharacter(myHandle, &character, 1, myCoord, &myNumberOfCharsWritten); // set color ::WriteConsoleOutputAttribute(myHandle, &myColorBuffer, 1, myCoord, &myNumberOfCharsWritten); } /** * Writes text to the console within the specified block and in the specified * color. Text is word-wrapped at the right edge of the text block and clipped * at the text block's bottom. If you don't specify the color of the text, it * defaults to white on black. WriteText does not update the position of the * cursor. * * @param text the text to write to the screen * @param left the left-most column of the text block * @param top the top row of the text block * @param right the right-most column of the text block * @param bottom the bottom row of the text block * @param foreColor the foreground color of the text block * @param backColor the background color of the text block */ void WriteTextBlock(std::string text, unsigned short left, unsigned short top, unsigned short right, unsigned short bottom, unsigned short foreColor, unsigned short backColor) { // is text box valid? if ((left > right) || (top > bottom)) { // no, exit return; } // get standard console handle HANDLE myHandle = ::GetStdHandle(STD_OUTPUT_HANDLE); COORD myCoord; myCoord.X = left; myCoord.Y = top; // clear text box (also sets color) int i, j; for (i = top; i < bottom + 1; i++) { for (j = left; j < right + 1; j++) { WriteText(' ', j, i, foreColor, backColor); } } // calculate maximum number of characters in a single line int myLineLength = right - left + 1; // write text line for line std::string myLine; for (i = 0; i < (bottom - top + 1); i++) { // does line fit? if (text.length() <= myLineLength) { // yes, line is entire text myLine = text; // this is the last line i = bottom - top + 1; } else { // no, get maximum sized line myLine = text.substr(0, myLineLength); // find right-most space int myIndex = myLine.rfind(" ", myLineLength); // was a space found? if (myIndex != std::string::npos) { // yes, get word-wrapped line myLine = text.substr(0, myIndex + 1); } // erase line from text text.erase(0, myLine.length()); } // write text to screen DWORD myNumberOfCharsWritten; ::WriteConsoleOutputCharacter(myHandle, myLine.c_str(), myLine.length(), myCoord, &myNumberOfCharsWritten); // advance to next line myCoord.Y++; } }