好的,我将使用pdcurses进行翻译。如果有人想要做类似的事情,这里是我的解决方法。首先,我这样初始化控制台:
Console::Console(bool makeConsole)
{
if (makeConsole == false)
return;
if (self)
throw ("You only need one console - do not make another!\n");
self = this;
#ifdef WIN32
AllocConsole();
#endif
initscr();
inputLine = newwin(1, COLS, LINES - 1, 0);
outputLines = newwin(LINES - 1, COLS, 0, 0);
if (has_colors())
{
start_color();
for (int i = 1; i <= COLOR_WHITE; ++i)
{
init_pair(i, i, COLOR_BLACK);
}
}
else
wprintw(outputLines, "Terminal cannot print colors.\n");
scrollok(outputLines, TRUE);
scrollok(inputLine, TRUE);
leaveok(inputLine, TRUE);
nodelay(inputLine, TRUE);
cbreak();
noecho();
keypad(inputLine, TRUE);
initCommands();
hello("Starting %s.\n", APP_NAME);
hellomore("Version %i.%i.%i.\n\n", APP_MAJORVER, APP_MINORVER, APP_REVISION);
}
接下来,这个函数负责处理输出。实际上非常简单,我不需要做任何特殊的事情来保持它的线程安全。可能是因为我还没有遇到任何问题,但一个简单的解决方法是在它上面加一个互斥锁。
void Console::sendFormattedMsg(short prefixColor, const char* prefix, short color, const char* format, ...)
{
if (!self)
return;
va_list args;
va_start(args, format);
if (has_colors())
{
if (prefix)
{
wattron(outputLines, A_BOLD | COLOR_PAIR(prefixColor));
wprintw(outputLines, prefix);
}
if (color == COLOR_WHITE)
wattroff(outputLines, A_BOLD);
wattron(outputLines, COLOR_PAIR(color));
vwprintw(outputLines, format, args);
wattroff(outputLines, A_BOLD | COLOR_PAIR(color));
}
else
{
wprintw(outputLines, prefix);
vwprintw(outputLines, format, args);
}
wrefresh(outputLines);
va_end(args);
}
最后是输入。这需要进行相当多的微调。
void Console::inputLoop(void)
{
static string input;
wattron(inputLine, A_BOLD | COLOR_PAIR(COLOR_WHITE));
wprintw(inputLine, "\n> ");
wattroff(inputLine, A_BOLD | COLOR_PAIR(COLOR_WHITE));
wprintw(inputLine, input.c_str());
wrefresh(inputLine);
char c = wgetch(inputLine);
if (c == ERR)
return;
switch (c)
{
case '\n':
if (input.size() > 0)
{
sendFormattedMsg(COLOR_WHITE, "> ", COLOR_WHITE, input.c_str());
cprint("\n");
executeCommand(&input[0]);
input.clear();
}
break;
case 8:
case 127:
if (input.size() > 0) input.pop_back();
break;
default:
input += c;
break;
}
}
这段代码在处理窗口消息的同一线程中每一帧都会运行。我使用 nodelay()
禁用了 wgetch()
的阻塞行为,消除了需要在自己的线程中运行控制台输入的必要性。我还禁用了回显并手动回显输入内容。启用输入窗口的滚动功能使我可以使用简单的 "\n" 清除其内容,并在用户键入任何内容时替换为更新的内容。它支持一切你期望从一个简单的多线程终端中得到的能够输入和接收多个线程输出的功能。