This is based on a library called Consoledefender V 3.3.
I made a minimal class for personal usage based on this library by using C++11. It actually takes user input and prints it back on the console screen and acts like an echo. I would like this class reviewed.
Console.h
#include <windows.h>
#include <conio.h>
#include <sstream>
#include <vector>
class Console
{
public:
Console();
~Console();
template<typename T>
bool getinput(T& rNum, const short maxlen) const;
int wait(const std::string& rStrMessage = "Press any key to continue . . . ", const unsigned timeout = INFINITE) const;
bool setfontsize(short& rWidth, short& rHeight) const;
bool title(const std::string& rStrTitle) const;
bool resize(const short width, const short height) const;
bool move(const int left, const int top) const;
private:
static unsigned __stdcall key(void *ch);
DWORD getmode() const;
CONSOLE_SCREEN_BUFFER_INFO getscreenbufferinfo() const;
COORD getfontsize() const;
WINDOWPLACEMENT getplacement() const;
const HWND mHwndCon;
const HANDLE mOut, mIn;
const DWORD mMode;
const CONSOLE_SCREEN_BUFFER_INFO mConsoleSceenBufferInfo;
const COORD mFontsSize;
const WINDOWPLACEMENT mWindowPlacemet;
};
template<typename T>
inline
bool Console::getinput(T& rStr, const short maxlen) const
{
return false;
}
template <>
inline
bool Console::getinput(int& rNum, const short maxlen) const
{
short len = 0, i = 0;
int numtmp = 0;
int ch = 0;
std::string str;
CONSOLE_SCREEN_BUFFER_INFO csbi = { 0 };
COORD coordBufSize = { maxlen, 1 };
COORD coordBufCoord = { 0, 0 };
if (maxlen < 1 || !GetConsoleScreenBufferInfo(mOut, &csbi))
{
return false;
}
std::vector<CHAR_INFO> chiVec(maxlen);
SMALL_RECT srctRect = { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, static_cast<short>(csbi.dwCursorPosition.X + maxlen), csbi.dwCursorPosition.Y };
COORD crdCur = csbi.dwCursorPosition;
if (!ReadConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect))
{
return false;
}
for (auto& i : chiVec)
{
i.Char.AsciiChar = 0;
}
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect))
{
return false;
}
while (ch != 13)
{
ch = _getch();
if (ch == 0 || ch == 224)
{
ch = 256 + _getch();
}
if (len < maxlen)
{
if ((ch == static_cast<int>('-') && len == 0)
|| (ch == static_cast<int>('+') && len == 0)
|| (ch >= static_cast<int>('0') && ch <= static_cast<int>('9')))
{
str += static_cast<char>(ch);
chiVec.at(len).Char.AsciiChar = ch;
++len;
++crdCur.X;
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect)
|| !SetConsoleCursorPosition(mOut, crdCur))
{
return false;
}
}
}
if (ch == static_cast<int>('\b') && len > 0)
{
str = str.substr(0, str.size() - 1);
--len;
--crdCur.X;
chiVec.at(len).Char.AsciiChar = 0;
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect)
|| !SetConsoleCursorPosition(mOut, crdCur))
{
return false;
}
}
}
if (!(std::istringstream(str) >> numtmp).fail())
{
rNum = numtmp;
return true;
}
return false;
}
template <>
inline
bool Console::getinput(unsigned& rNum, const short maxlen) const
{
short len = 0, i = 0;
unsigned numtmp = 0;
int ch = 0;
std::string str;
CONSOLE_SCREEN_BUFFER_INFO csbi = { 0 };
COORD coordBufSize = { maxlen, 1 };
COORD coordBufCoord = { 0, 0 };
if (maxlen < 1 || !GetConsoleScreenBufferInfo(mOut, &csbi))
{
return false;
}
std::vector<CHAR_INFO> chiVec(maxlen);
SMALL_RECT srctRect = { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, static_cast<short>(csbi.dwCursorPosition.X + maxlen), csbi.dwCursorPosition.Y };
COORD crdCur = csbi.dwCursorPosition;
if (!ReadConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect))
{
return false;
}
for (auto& i : chiVec)
{
i.Char.AsciiChar = 0;
}
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect))
{
return false;
}
while (ch != 13)
{
ch = _getch();
if (ch == 0 || ch == 224)
{
ch = 256 + _getch();
}
if (len < maxlen)
{
if ((ch == static_cast<int>('+') && len == 0)
|| (ch >= static_cast<int>('0') && ch <= static_cast<int>('9')))
{
str += static_cast<char>(ch);
chiVec.at(len).Char.AsciiChar = ch;
++len;
++crdCur.X;
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect)
|| !SetConsoleCursorPosition(mOut, crdCur))
{
return false;
}
}
}
if (ch == static_cast<int>('\b') && len > 0)
{
str = str.substr(0, str.size() - 1);
--len;
--crdCur.X;
chiVec.at(len).Char.AsciiChar = 0;
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect)
|| !SetConsoleCursorPosition(mOut, crdCur))
{
return false;
}
}
}
if (!(std::istringstream(str) >> numtmp).fail())
{
rNum = numtmp;
return true;
}
return false;
}
template <>
inline
bool Console::getinput(float& rNum, const short maxlen) const
{
short len = 0, i = 0, sign = -1, fpoint = -1, exp = -1;
float numtmp = 0;
int ch = 0;
std::string str;
CONSOLE_SCREEN_BUFFER_INFO csbi = { 0 };
COORD coordBufSize = { maxlen, 1 };
COORD coordBufCoord = { 0, 0 };
if (maxlen < 1 || !GetConsoleScreenBufferInfo(mOut, &csbi))
{
return false;
}
std::vector<CHAR_INFO> chiVec(maxlen);
SMALL_RECT srctRect = { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, static_cast<short>(csbi.dwCursorPosition.X + maxlen), csbi.dwCursorPosition.Y };
COORD crdCur = csbi.dwCursorPosition;
if (!ReadConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect))
{
return false;
}
for (auto& i : chiVec)
{
i.Char.AsciiChar = 0;
}
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect))
{
return false;
}
while (ch != 13)
{
ch = _getch();
if (ch == 0 || ch == 224)
{
ch = 256 + _getch();
}
if (len < maxlen)
{
if ((ch == static_cast<int>('-') && len - 1 == exp)
|| (ch == static_cast<int>('+') && len - 1 == exp)
|| (ch >= static_cast<int>('0') && ch <= static_cast<int>('9'))
|| (ch == static_cast<int>('.') && fpoint == -1 && exp == -1)
|| ((ch == static_cast<int>('e') || ch == static_cast<int>('E')) && exp == -1 && len > 0 && !(len == 1 && !sign)))
{
str += static_cast<char>(ch);
chiVec.at(len).Char.AsciiChar = ch;
if (ch == static_cast<int>('-') && !len)
{
sign = 0;
}
else if (ch == static_cast<int>('+') && !len)
{
sign = 0;
}
else if (ch == static_cast<int>('.'))
{
fpoint = len;
}
else if (ch == static_cast<int>('e') || ch == static_cast<int>('E'))
{
exp = len;
}
++len;
++crdCur.X;
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect)
|| !SetConsoleCursorPosition(mOut, crdCur))
{
return false;
}
}
}
if (ch == static_cast<int>('\b') && len > 0)
{
str = str.substr(0, str.size() - 1);
--len;
--crdCur.X;
chiVec.at(len).Char.AsciiChar = 0;
if (len == sign)
{
sign = -1;
}
else if (len == fpoint)
{
fpoint = -1;
}
else if (len == exp)
{
exp = -1;
}
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect)
|| !SetConsoleCursorPosition(mOut, crdCur))
{
return false;
}
}
}
if (!(std::istringstream(str) >> numtmp).fail())
{
rNum = numtmp;
return true;
}
return false;
}
template <>
inline
bool Console::getinput(std::string& rStr, const short maxlen) const
{
short len = 0, i = 0;
std::string strtmp;
int ch = 0;
CONSOLE_SCREEN_BUFFER_INFO csbi = { 0 };
COORD coordBufSize = { maxlen, 1 };
COORD coordBufCoord = { 0, 0 };
if (maxlen < 1 || !GetConsoleScreenBufferInfo(mOut, &csbi))
{
return false;
}
std::vector<CHAR_INFO> chiVec(maxlen);
SMALL_RECT srctRect = { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, static_cast<short>(csbi.dwCursorPosition.X + maxlen), csbi.dwCursorPosition.Y };
COORD crdCur = csbi.dwCursorPosition;
if (!ReadConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect))
{
return false;
}
for (auto& i : chiVec)
{
i.Char.AsciiChar = 0;
}
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect))
{
return false;
}
while (ch != 13)
{
ch = _getch();
if (ch == 0 || ch == 224)
{
ch = 256 + _getch();
}
if (len < maxlen)
{
if (ch > 31 && ch < 256)
{
strtmp += static_cast<char>(ch);
chiVec.at(len).Char.AsciiChar = ch;
++len;
++crdCur.X;
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect)
|| !SetConsoleCursorPosition(mOut, crdCur))
{
return false;
}
}
}
if (ch == static_cast<int>('\b') && len > 0)
{
strtmp = strtmp.substr(0, strtmp.size() - 1);
--len;
--crdCur.X;
chiVec.at(len).Char.AsciiChar = 0;
if (!WriteConsoleOutputA(mOut, &chiVec.front(), coordBufSize, coordBufCoord, &srctRect)
|| !SetConsoleCursorPosition(mOut, crdCur))
{
return false;
}
}
}
if (!strtmp.empty())
{
rStr = strtmp;
return true;
}
return false;
}
Console.cpp
#include "Console.h"
#include <process.h>
#include <iostream>
#include <deque>
#include <array>
#include <stdexcept>
Console::Console()
: mHwndCon(GetConsoleWindow())
, mOut(GetStdHandle(STD_OUTPUT_HANDLE))
, mIn(GetStdHandle(STD_INPUT_HANDLE))
, mMode(getmode())
, mConsoleSceenBufferInfo(getscreenbufferinfo())
, mFontsSize(getfontsize())
, mWindowPlacemet(getplacement())
{
if (!mHwndCon
|| mOut == INVALID_HANDLE_VALUE
|| mIn == INVALID_HANDLE_VALUE)
throw std::runtime_error("Failed to construct winconshelper.");
}
Console::~Console()
{
CONSOLE_FONT_INFOEX cfix = { 0 };
cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX);
if (mMode != static_cast<DWORD>(-1)
&& mConsoleSceenBufferInfo.dwMaximumWindowSize.X
&& mFontsSize.X
&& mFontsSize.Y
&& mWindowPlacemet.length
&& GetCurrentConsoleFontEx(mOut, FALSE, &cfix))
{
SetConsoleMode(mIn, mMode);
MoveWindow(mHwndCon,
mWindowPlacemet.rcNormalPosition.left,
mWindowPlacemet.rcNormalPosition.top,
mWindowPlacemet.rcNormalPosition.left + 1,
mWindowPlacemet.rcNormalPosition.top + 1, TRUE);
cfix.dwFontSize = mFontsSize;
SetCurrentConsoleFontEx(mOut, FALSE, &cfix);
SetConsoleScreenBufferSize(mOut, mConsoleSceenBufferInfo.dwSize);
SetConsoleWindowInfo(mOut, FALSE, &mConsoleSceenBufferInfo.srWindow);
SetWindowPlacement(mHwndCon, &mWindowPlacemet);
}
}
int Console::wait(const std::string& rStrMessage, const unsigned timeout) const
{
int ch = 0;
HANDLE hThread = NULL;
std::cout << rStrMessage;
FlushConsoleInputBuffer(mIn);
if ((hThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, key, static_cast<void*>(&ch), 0, NULL))))
{
if (WaitForSingleObject(hThread, timeout) == WAIT_TIMEOUT)
{
TerminateThread(hThread, 0);
}
CloseHandle(hThread);
}
std::cout << '\n';
FlushConsoleInputBuffer(mIn);
return ch;
}
unsigned __stdcall Console::key(void *pch)
{
int ch = 0;
ch = _getch();
if (ch == 0 || ch == 224)
{
ch = 256 + _getch();
}
*(static_cast<int*>(pch)) = ch;
_endthreadex(0);
return 0;
}
DWORD Console::getmode() const
{
DWORD tmpmode = 0;
return (GetConsoleMode(mIn, &tmpmode)) ? tmpmode : -1;
}
CONSOLE_SCREEN_BUFFER_INFO Console::getscreenbufferinfo() const
{
CONSOLE_SCREEN_BUFFER_INFO temp = { 0 };
if (GetConsoleScreenBufferInfo(mOut, &temp))
{
return temp;
}
temp.dwMaximumWindowSize.X = 0;
return temp;
}
COORD Console::getfontsize() const
{
COORD tempfontsize = { 0, 0 };
CONSOLE_FONT_INFOEX cfix = { 0 };
cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX);
if (GetCurrentConsoleFontEx(mOut, FALSE, &cfix))
{
tempfontsize = GetConsoleFontSize(mOut, cfix.nFont);
}
return tempfontsize;
}
WINDOWPLACEMENT Console::getplacement() const
{
WINDOWPLACEMENT temp = { 0 };
temp.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(mHwndCon, &temp))
{
return temp;
}
temp.length = 0;
return temp;
}
bool Console::title(const std::string& rStrTitle) const
{
return (SetConsoleTitleA(rStrTitle.c_str())) ? true : false;
}
bool Console::resize(const short width, const short height) const
{
long lHeight = 0, lWidth = 0;
HMONITOR hMonitor = NULL;
MONITORINFO mi = { 0 };
CONSOLE_FONT_INFO cfi = { 0 };
COORD crdfontsize = { 0, 0 };
COORD coord = { 0, 0 };
COORD crdbuf = { width, height };
hMonitor = MonitorFromWindow(mHwndCon, MONITOR_DEFAULTTONEAREST);
mi.cbSize = sizeof(MONITORINFO);
if (!GetMonitorInfo(hMonitor, &mi)
|| !GetCurrentConsoleFont(mOut, FALSE, &cfi))
{
return false;
}
crdfontsize = GetConsoleFontSize(mOut, cfi.nFont);
lWidth = width * crdfontsize.X + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXBORDER));
lHeight = height * crdfontsize.Y + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYBORDER)) + GetSystemMetrics(SM_CYCAPTION);
if (crdfontsize.X == 0
|| crdfontsize.Y == 0
|| lWidth > (mi.rcWork.right - mi.rcWork.left)
|| lHeight > (mi.rcWork.bottom - mi.rcWork.top)
|| lWidth < GetSystemMetrics(SM_CXMIN)
|| lHeight < GetSystemMetrics(SM_CYMIN))
{
return false;
}
coord.X = static_cast<short>((mi.rcWork.right - mi.rcWork.left) / crdfontsize.X);
coord.Y = static_cast<short>((mi.rcWork.bottom - mi.rcWork.top) / crdfontsize.Y);
if (SetConsoleScreenBufferSize(mOut, coord)
&& SetWindowPos(mHwndCon, NULL, 0, 0, lWidth, lHeight, SWP_NOZORDER | SWP_NOMOVE)
&& SetConsoleScreenBufferSize(mOut, crdbuf))
{
SetWindowPos(mHwndCon, NULL, 0, 0, lWidth + 50, lHeight + 50, SWP_NOZORDER | SWP_NOMOVE);
return true;
}
return false;
}
bool Console::move(const int left, const int top) const
{
return SetWindowPos(mHwndCon, NULL, left, top, 0, 0, SWP_NOZORDER | SWP_NOSIZE) ? true : false;
}
test.cpp
#include <iostream>
#include <string>
#include <stdexcept>
#include "Console.h"
int main()
{
try
{
Console console;
// Put window in the upper left corner of the screen
console.move(0, 0);
// Window size to a width of 100 and a height of 30 character Cells
console.resize(100, 30);
// Change Window Title
console.title("Test");
// input test for float number
std::cout << "enter the number: ";
float f = 0.f;
console.getinput(f, 5);
std::cout << "\ninput was " << f << "\n\n";
// input test for int number
std::cout << "enter the int number: ";
int i = 0;
console.getinput(i, 7);
std::cout << "\ninput was " << i << "\n\n";
// input test for string
std::cout << "enter your full name: ";
std::string str;
console.getinput(str, 79);
std::cout << "\ninput was " << str << "\n\n";
console.wait();
return 0;
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
catch (...)
{
std::cerr << "An error occured." << std::endl;
}
return 1;
}