如何在换行后将 std::cout 输出带回顶部
How to bring std::cout output back to the top after a new line
我有以下菜单,它应该根据用户是否键入了键 F1 或 F2 来更新:
int main()
{
bool f1 = false;
bool f2 = false;
while (true)
{
std::cout << "[F1]: " << (f1 ? "ON" : "OFF") << std::endl;
std::cout << "[F2]: " << (f2 ? "ON" : "OFF") << std::endl;
std::cout << "[INS] to quit" << std::endl;
if (GetAsyncKeyState(VK_INSERT) & 0x1)
break;
if (GetAsyncKeyState(VK_F1) & 0x1)
f1 = !f1;
if (GetAsyncKeyState(VK_F2) & 0x1)
f2 = !f2;
Sleep(100);
cleanWindow();
}
return 0;
}
现在,我以前使用 system("cls")
并且工作“正常”,但我被告知我应该使用 Win32 API 来清理控制台,等等我按照 this MSVC article.
的描述创建了 cleanWindow()
DWORD cleanWindow()
{
HANDLE hStdOut;
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
// Fetch existing console mode so we correctly add a flag and not turn off others
DWORD mode = 0;
if (!GetConsoleMode(hStdOut, &mode))
{
return ::GetLastError();
}
// Hold original mode to restore on exit to be cooperative with other command-line apps.
const DWORD originalMode = mode;
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
// Try to set the mode.
if (!SetConsoleMode(hStdOut, mode))
{
return ::GetLastError();
}
// Write the sequence for clearing the display.
// \x1b[2J is the code for clearing the screen and set cursor to home
DWORD written = 0;
PCWSTR sequence = L"\x1b[2J";
if (!WriteConsoleW(hStdOut, sequence, (DWORD)wcslen(sequence), &written, NULL))
{
// If we fail, try to restore the mode on the way out.
SetConsoleMode(hStdOut, originalMode);
return ::GetLastError();
}
// To also clear the scroll back, emit L"\x1b[3J" as well.
// 2J only clears the visible window and 3J only clears the scroll back.
// Restore the mode on the way out to be nice to other command-line applications.
SetConsoleMode(hStdOut, originalMode);
}
现在,问题是“菜单”位于命令提示符的末尾而不是开头,就像 system("cls")
:
我的问题是,我该如何解决这个问题?如何将输出返回到 shell 的顶部?
编辑:
我还编辑了 cleanWindow()
函数来编写序列:3[2J
和 L"3[H"
与 WriteConsoleW()
,这有效,但我仍然得到“闪烁”效果就像 system("cls")
一样,这是我试图避免的事情。
您可以在清除后使用SetConsoleCursorPosition
将光标位置设置回左上角。
还有 ANSI escape codes(类似于您用来清除屏幕的那个)可以让您重新定位光标。
"3[r;cH"
将 r
替换为要移动到的行和 c
列。它们从 1 开始,默认位于左上角,因此您可以使用 "3[1;1H"
或仅使用 "3[H"
我有以下菜单,它应该根据用户是否键入了键 F1 或 F2 来更新:
int main()
{
bool f1 = false;
bool f2 = false;
while (true)
{
std::cout << "[F1]: " << (f1 ? "ON" : "OFF") << std::endl;
std::cout << "[F2]: " << (f2 ? "ON" : "OFF") << std::endl;
std::cout << "[INS] to quit" << std::endl;
if (GetAsyncKeyState(VK_INSERT) & 0x1)
break;
if (GetAsyncKeyState(VK_F1) & 0x1)
f1 = !f1;
if (GetAsyncKeyState(VK_F2) & 0x1)
f2 = !f2;
Sleep(100);
cleanWindow();
}
return 0;
}
现在,我以前使用 system("cls")
并且工作“正常”,但我被告知我应该使用 Win32 API 来清理控制台,等等我按照 this MSVC article.
cleanWindow()
DWORD cleanWindow()
{
HANDLE hStdOut;
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
// Fetch existing console mode so we correctly add a flag and not turn off others
DWORD mode = 0;
if (!GetConsoleMode(hStdOut, &mode))
{
return ::GetLastError();
}
// Hold original mode to restore on exit to be cooperative with other command-line apps.
const DWORD originalMode = mode;
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
// Try to set the mode.
if (!SetConsoleMode(hStdOut, mode))
{
return ::GetLastError();
}
// Write the sequence for clearing the display.
// \x1b[2J is the code for clearing the screen and set cursor to home
DWORD written = 0;
PCWSTR sequence = L"\x1b[2J";
if (!WriteConsoleW(hStdOut, sequence, (DWORD)wcslen(sequence), &written, NULL))
{
// If we fail, try to restore the mode on the way out.
SetConsoleMode(hStdOut, originalMode);
return ::GetLastError();
}
// To also clear the scroll back, emit L"\x1b[3J" as well.
// 2J only clears the visible window and 3J only clears the scroll back.
// Restore the mode on the way out to be nice to other command-line applications.
SetConsoleMode(hStdOut, originalMode);
}
现在,问题是“菜单”位于命令提示符的末尾而不是开头,就像 system("cls")
:
我的问题是,我该如何解决这个问题?如何将输出返回到 shell 的顶部?
编辑:
我还编辑了 cleanWindow()
函数来编写序列:3[2J
和 L"3[H"
与 WriteConsoleW()
,这有效,但我仍然得到“闪烁”效果就像 system("cls")
一样,这是我试图避免的事情。
您可以在清除后使用SetConsoleCursorPosition
将光标位置设置回左上角。
还有 ANSI escape codes(类似于您用来清除屏幕的那个)可以让您重新定位光标。
"3[r;cH"
将 r
替换为要移动到的行和 c
列。它们从 1 开始,默认位于左上角,因此您可以使用 "3[1;1H"
或仅使用 "3[H"