Created
January 22, 2023 03:04
-
-
Save uemuraj/eef7b30eb1cc7419e0356b074f0e88bf to your computer and use it in GitHub Desktop.
コンソールの仮想ターミナル シーケンス
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// https://learn.microsoft.com/ja-jp/windows/console/console-virtual-terminal-sequences | |
// | |
#if 1 | |
#include <stdio.h> | |
#include <wchar.h> | |
#include <windows.h> | |
#include <system_error> | |
#include <locale> | |
#include <iostream> | |
#define ESC "\x1b" | |
#define CSI "\x1b[" | |
class VirtualTerminalMode | |
{ | |
HANDLE m_cout; | |
DWORD m_mode; | |
public: | |
VirtualTerminalMode() : m_cout(INVALID_HANDLE_VALUE), m_mode(0) | |
{ | |
m_cout = ::GetStdHandle(STD_OUTPUT_HANDLE); | |
if (m_cout == INVALID_HANDLE_VALUE) | |
{ | |
throw std::system_error(::GetLastError(), std::system_category(), "GetStdHandle()"); | |
} | |
if (!::GetConsoleMode(m_cout, &m_mode)) | |
{ | |
throw std::system_error(::GetLastError(), std::system_category(), "GetConsoleMode()"); | |
} | |
if (!::SetConsoleMode(m_cout, m_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) | |
{ | |
throw std::system_error(::GetLastError(), std::system_category(), "SetConsoleMode()"); | |
} | |
} | |
~VirtualTerminalMode() noexcept | |
{ | |
std::cout << CSI "!p"; | |
::SetConsoleMode(m_cout, m_mode); | |
} | |
}; | |
int main() | |
{ | |
std::locale::global(std::locale("")); | |
VirtualTerminalMode vt; | |
std::cout << CSI "4m" "Hello World!"; | |
} | |
#elif 0 | |
int main() | |
{ | |
// Set output mode to handle virtual terminal sequences | |
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); | |
if (hOut == INVALID_HANDLE_VALUE) | |
{ | |
return false; | |
} | |
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); | |
if (hIn == INVALID_HANDLE_VALUE) | |
{ | |
return false; | |
} | |
DWORD dwOriginalOutMode = 0; | |
DWORD dwOriginalInMode = 0; | |
if (!GetConsoleMode(hOut, &dwOriginalOutMode)) | |
{ | |
return false; | |
} | |
if (!GetConsoleMode(hIn, &dwOriginalInMode)) | |
{ | |
return false; | |
} | |
DWORD dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN; | |
DWORD dwRequestedInModes = ENABLE_VIRTUAL_TERMINAL_INPUT; | |
DWORD dwOutMode = dwOriginalOutMode | dwRequestedOutModes; | |
if (!SetConsoleMode(hOut, dwOutMode)) | |
{ | |
// we failed to set both modes, try to step down mode gracefully. | |
dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING; | |
dwOutMode = dwOriginalOutMode | dwRequestedOutModes; | |
if (!SetConsoleMode(hOut, dwOutMode)) | |
{ | |
// Failed to set any VT mode, can't do anything here. | |
return -1; | |
} | |
} | |
DWORD dwInMode = dwOriginalInMode | dwRequestedInModes; | |
if (!SetConsoleMode(hIn, dwInMode)) | |
{ | |
// Failed to set VT input mode, can't do anything here. | |
return -1; | |
} | |
printf("Hello World!"); | |
return 0; | |
} | |
#else | |
// System headers | |
#include <windows.h> | |
// Standard library C-style | |
#include <wchar.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#define ESC "\x1b" | |
#define CSI "\x1b[" | |
bool EnableVTMode() | |
{ | |
// Set output mode to handle virtual terminal sequences | |
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); | |
if (hOut == INVALID_HANDLE_VALUE) | |
{ | |
return false; | |
} | |
DWORD dwMode = 0; | |
if (!GetConsoleMode(hOut, &dwMode)) | |
{ | |
return false; | |
} | |
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; | |
if (!SetConsoleMode(hOut, dwMode)) | |
{ | |
return false; | |
} | |
return true; | |
} | |
void PrintVerticalBorder() | |
{ | |
printf(ESC "(0"); // Enter Line drawing mode | |
printf(CSI "104;93m"); // bright yellow on bright blue | |
printf("x"); // in line drawing mode, \x78 -> \u2502 "Vertical Bar" | |
printf(CSI "0m"); // restore color | |
printf(ESC "(B"); // exit line drawing mode | |
} | |
void PrintHorizontalBorder(COORD const Size, bool fIsTop) | |
{ | |
printf(ESC "(0"); // Enter Line drawing mode | |
printf(CSI "104;93m"); // Make the border bright yellow on bright blue | |
printf(fIsTop ? "l" : "m"); // print left corner | |
for (int i = 1; i < Size.X - 1; i++) | |
printf("q"); // in line drawing mode, \x71 -> \u2500 "HORIZONTAL SCAN LINE-5" | |
printf(fIsTop ? "k" : "j"); // print right corner | |
printf(CSI "0m"); | |
printf(ESC "(B"); // exit line drawing mode | |
} | |
void PrintStatusLine(const char * const pszMessage, COORD const Size) | |
{ | |
printf(CSI "%d;1H", Size.Y); | |
printf(CSI "K"); // clear the line | |
printf(pszMessage); | |
} | |
int __cdecl wmain(int argc, WCHAR * argv[]) | |
{ | |
argc; // unused | |
argv; // unused | |
//First, enable VT mode | |
bool fSuccess = EnableVTMode(); | |
if (!fSuccess) | |
{ | |
printf("Unable to enter VT processing mode. Quitting.\n"); | |
return -1; | |
} | |
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); | |
if (hOut == INVALID_HANDLE_VALUE) | |
{ | |
printf("Couldn't get the console handle. Quitting.\n"); | |
return -1; | |
} | |
CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo; | |
GetConsoleScreenBufferInfo(hOut, &ScreenBufferInfo); | |
COORD Size; | |
Size.X = ScreenBufferInfo.srWindow.Right - ScreenBufferInfo.srWindow.Left + 1; | |
Size.Y = ScreenBufferInfo.srWindow.Bottom - ScreenBufferInfo.srWindow.Top + 1; | |
// Enter the alternate buffer | |
printf(CSI "?1049h"); | |
// Clear screen, tab stops, set, stop at columns 16, 32 | |
printf(CSI "1;1H"); | |
printf(CSI "2J"); // Clear screen | |
int iNumTabStops = 4; // (0, 20, 40, width) | |
printf(CSI "3g"); // clear all tab stops | |
printf(CSI "1;20H"); // Move to column 20 | |
printf(ESC "H"); // set a tab stop | |
printf(CSI "1;40H"); // Move to column 40 | |
printf(ESC "H"); // set a tab stop | |
// Set scrolling margins to 3, h-2 | |
printf(CSI "3;%dr", Size.Y - 2); | |
int iNumLines = Size.Y - 4; | |
printf(CSI "1;1H"); | |
printf(CSI "102;30m"); | |
printf("Windows 10 Anniversary Update - VT Example"); | |
printf(CSI "0m"); | |
// Print a top border - Yellow | |
printf(CSI "2;1H"); | |
PrintHorizontalBorder(Size, true); | |
// // Print a bottom border | |
printf(CSI "%d;1H", Size.Y - 1); | |
PrintHorizontalBorder(Size, false); | |
wchar_t wch; | |
// draw columns | |
printf(CSI "3;1H"); | |
int line = 0; | |
for (line = 0; line < iNumLines * iNumTabStops; line++) | |
{ | |
PrintVerticalBorder(); | |
if (line + 1 != iNumLines * iNumTabStops) // don't advance to next line if this is the last line | |
printf("\t"); // advance to next tab stop | |
} | |
PrintStatusLine("Press any key to see text printed between tab stops.", Size); | |
wch = _getwch(); | |
// Fill columns with output | |
printf(CSI "3;1H"); | |
for (line = 0; line < iNumLines; line++) | |
{ | |
int tab = 0; | |
for (tab = 0; tab < iNumTabStops - 1; tab++) | |
{ | |
PrintVerticalBorder(); | |
printf("line=%d", line); | |
printf("\t"); // advance to next tab stop | |
} | |
PrintVerticalBorder();// print border at right side | |
if (line + 1 != iNumLines) | |
printf("\t"); // advance to next tab stop, (on the next line) | |
} | |
PrintStatusLine("Press any key to demonstrate scroll margins", Size); | |
wch = _getwch(); | |
printf(CSI "3;1H"); | |
for (line = 0; line < iNumLines * 2; line++) | |
{ | |
printf(CSI "K"); // clear the line | |
int tab = 0; | |
for (tab = 0; tab < iNumTabStops - 1; tab++) | |
{ | |
PrintVerticalBorder(); | |
printf("line=%d", line); | |
printf("\t"); // advance to next tab stop | |
} | |
PrintVerticalBorder(); // print border at right side | |
if (line + 1 != iNumLines * 2) | |
{ | |
printf("\n"); //Advance to next line. If we're at the bottom of the margins, the text will scroll. | |
printf("\r"); //return to first col in buffer | |
} | |
} | |
PrintStatusLine("Press any key to exit", Size); | |
wch = _getwch(); | |
// Exit the alternate buffer | |
printf(CSI "?1049l"); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment