在 Windows 中处理控制台的经典方法是通过Console API。要获取控制台大小,您可以使用GetConsoleScreenBufferInfo()。这是一个非常简单的例子,在屏幕中心绘制一个字符串
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdint>
#include <windows.h>
int main(void)
{
auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
std::string str;
CONSOLE_SCREEN_BUFFER_INFO oldcsbi{};
COORD coord{};
while (1)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(stdout_handle, &csbi);
if (csbi.srWindow.Bottom != oldcsbi.srWindow.Bottom || csbi.srWindow.Right != oldcsbi.srWindow.Right)
{
std::fill(str.begin(), str.end(), ' ');
SetConsoleCursorPosition(stdout_handle, coord);
std::cout << str; // clear the old text
oldcsbi = csbi;
std::ostringstream s;
s << "Console size: " << csbi.srWindow.Right << 'x' << csbi.srWindow.Bottom;
str = s.str();
coord.X = (short)((csbi.srWindow.Right - str.size()) / 2);
coord.Y = (short)(csbi.srWindow.Bottom/2);
SetConsoleCursorPosition(stdout_handle, coord);
std::cout << str; // draw the new text
}
Sleep(1000);
}
}
上面的代码会定期获取控制台大小,如果大小发生变化,则重新绘制屏幕。它会无限循环,直到您按下 Ctrl+C 或关闭程序
有关控制台 API 的更多信息,请参阅Using the Console
当然polling 这样的大小不是很好,因为它使输出不是很平滑并且还占用了 CPU 周期。真正的解决方案是监听调整大小事件并在回调函数中做必要的事情
有一种称为ENABLE_WINDOW_INPUT 的模式将调整大小事件传递到控制台,您可以在控制台中通过阻塞ReadConsoleInput() 或PeekConsoleInput() API 读取。您可以在Reading Input Buffer Events 中查看示例。只需运行它并调整窗口大小,调整大小事件将被打印出来
不幸的是,在该模式下,只有 console buffer size change event 通过 WINDOW_BUFFER_SIZE_RECORD 触发,并且没有 控制台屏幕大小更改 事件,因此如果您更改行数,那么大多数时候没有事件被生成。这意味着您需要进入较低级别并收听名为 EVENT_CONSOLE_LAYOUT 的 Console Winevent:
HWINEVENTHOOK eventHook = SetWinEventHook(EVENT_CONSOLE_LAYOUT, EVENT_CONSOLE_LAYOUT,
NULL, EventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
...
MSG msg;
while (GetMessage(&msg, g_hWindow, EVENT_CONSOLE_LAYOUT, EVENT_CONSOLE_LAYOUT)) {
DispatchMessage(&msg);
您可以在
中找到更多详细信息
更简单甚至更好的方法是使用ncurses 并处理类似于SIGWINCH 的内容。过去有很多 ncurses 的 Windows 端口,给定 Windows 10 控制台supportsANSI sequences,编写 ncurses 端口更加容易。事实上,现在是 recommended 到 use ANSI sequences 用于终端交互,而不是用于可移植性的 ole Console API