Я пишу консольное приложение с VS2022 на C++ и Windows API. После долгих поисков я увидел, что современные версии Windows Terminal допускают использование цветовых кодов ANSI.
В документации Windows говорится:
https://learn.microsoft.com/en-us/windows/console/writeconsole
Хотя приложение может использовать
WriteConsole
в режиме ANSI для записи символов ANSI, консоли не поддерживают escape-последовательности ANSI или последовательности «виртуального терминала», если они не включены. См. Последовательности виртуального терминала консоли для получения дополнительной информации и информации о применимости версии операционной системы.
https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
Вы можете использовать функции
GetConsoleMode
иSetConsoleMode
для настройки такого поведения. Пример предлагаемого способа включения поведения виртуального терминала приведен в конце этого документа.
Сокращенная версия примера программы:
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut, &dwMode)
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode)
Я создал минимальный пример, чтобы показать, что не работает.
HANDLE hConsole = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
0,
nullptr,
CONSOLE_TEXTMODE_BUFFER,
nullptr
);
SetConsoleActiveScreenBuffer(hConsole);
DWORD dwMode = 0;
GetConsoleMode(hConsole, &dwMode);
dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hConsole, dwMode);
DWORD charsWritten;
WriteConsoleA(hConsole, "\x1b[31mHello\x1b[0m", 13, &charsWritten, nullptr);
Результат: я не могу публиковать изображения, но в результате получается несколько символов Юникода с «отсутствующими символами».
Я могу изменить цвет с помощью escape-последовательностей ANSI ДО того, как создам буфер экрана консоли с помощью std::cout
. Использование std::cout
ПОСЛЕ того, как я создаю буфер экрана консоли, ничего не делает, а это мне не нужно.
Я знаю SetConsoleTextAttribute()
, и он работает, но мне хотелось бы работать с более чем 16 цветами теперь, когда VT100 Parser доступен для терминалов Windows. Раньше я также использовал WriteConsoleOutput()
и WriteConsoleOutputCharacter()
и знаю, что они не работают с ANSI. WriteConsole()
должен уметь работать с ANSI.
Отредактировано, но все равно без костей.
Длина передаваемой строки также превышает 13 символов. Вывод усекается.
ENABLE_VIRTUAL_TERMINAL_PROCESSING
работает нормально. Также проверьте документ Пример терминальных последовательностей SGR.
#include <stdio.h>
#include <wchar.h>
#include <windows.h>
int main()
{
// Set output mode to handle virtual terminal sequences
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
DWORD dwMode = 0;
if (!GetConsoleMode(hOut, &dwMode))
{
return GetLastError();
}
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(hOut, dwMode))
{
return GetLastError();
}
// Try some Set Graphics Rendition (SGR) terminal escape sequences
wprintf(L"\x1b[31mThis text has a red foreground using SGR.31.\r\n");
wprintf(L"\x1b[1mThis text has a bright (bold) red foreground using SGR.1 to affect the previous color setting.\r\n");
wprintf(L"\x1b[mThis text has returned to default colors using SGR.0 implicitly.\r\n");
wprintf(L"\x1b[34;46mThis text shows the foreground and background change at the same time.\r\n");
wprintf(L"\x1b[0mThis text has returned to default colors using SGR.0 explicitly.\r\n");
wprintf(L"\x1b[31;32;33;34;35;36;101;102;103;104;105;106;107mThis text attempts to apply many colors in the same command. Note the colors are applied from left to right so only the right-most option of foreground cyan (SGR.36) and background bright white (SGR.107) is effective.\r\n");
wprintf(L"\x1b[39mThis text has restored the foreground color only.\r\n");
wprintf(L"\x1b[49mThis text has restored the background color only.\r\n");
DWORD charsWritten;
BOOL b = WriteConsole(hOut, L"\x1b[31mThis text has a red foreground using SGR.31.\r\n", 52, &charsWritten,nullptr);
WriteConsoleA(hOut, "\x1b[31mHello\x1b[0m", 15, &charsWritten, nullptr);
return 0;
}
Также проверил ваш код.
Из документации : «
lpBuffer
: указатель на буфер, содержащий символы, которые будут записаны в буфер экрана консоли. Ожидается, что это будет массив либоchar
дляWriteConsoleA
, либоwchar_t
дляWriteConsoleW
». Код передаетchar
вWriteConsoleW()
.