让Windows控制台应用程序支持VT100---原理篇
微軟的操作系統(tǒng)在歷史上對(duì)VT的支持可追溯到 DOS 年代,那時(shí)候有一個(gè)設(shè)備驅(qū)動(dòng)程序名字叫 ANSI.SYS(泄露的dos6.0代碼里面有,位于 ms_dos_6_0_source_code\dos-6.0\dev\ansi,是匯編語言實(shí)現(xiàn)的),加載后就可以讓終端支持VT控制符,后來進(jìn)入桌面時(shí)代后就沒有類似的支持了。直到Windows 10的Anniversary Update(1607),微軟追加了對(duì)VT的支持,這可能是得益于微軟在內(nèi)核層面支持Linux kernel的努力(WSL)。下面是詳細(xì)的介紹和示例內(nèi)容
https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
測(cè)試代碼
// // Copyright (C) Microsoft. All rights reserved. // //https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#define DEFINE_CONSOLEV2_PROPERTIES// System headers #include <windows.h>// Standard library C-style #include <wchar.h> #include <stdlib.h> #include <stdio.h>#define ESC "\x1b" #define CSI "\x1b["#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endifbool EnableVTMode() {// Set output mode to handle virtual terminal sequencesHANDLE 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 modeprintf(CSI "104;93m"); // bright yellow on bright blueprintf("x"); // in line drawing mode, \x78 -> \u2502 "Vertical Bar"printf(CSI "0m"); // restore colorprintf(ESC "(B"); // exit line drawing mode }void PrintHorizontalBorder(COORD const Size, bool fIsTop) {printf(ESC "(0"); // Enter Line drawing modeprintf(CSI "104;93m"); // Make the border bright yellow on bright blueprintf(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 cornerprintf(CSI "0m");printf(ESC "(B"); // exit line drawing mode }void PrintStatusLine(char* const pszMessage, COORD const Size) {printf(CSI "%d;1H", Size.Y);printf(CSI "K"); // clear the lineprintf(pszMessage); }int __cdecl wmain(int argc, WCHAR* argv[]) { argc; // unusedargv; // unused//First, enable VT modebool 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 bufferprintf(CSI "?1049h");// Clear screen, tab stops, set, stop at columns 16, 32printf(CSI "1;1H");printf(CSI "2J"); // Clear screenint iNumTabStops = 4; // (0, 20, 40, width)printf(CSI "3g"); // clear all tab stopsprintf(CSI "1;20H"); // Move to column 20printf(ESC "H"); // set a tab stopprintf(CSI "1;40H"); // Move to column 40printf(ESC "H"); // set a tab stop// Set scrolling margins to 3, h-2printf(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 - Yellowprintf(CSI "2;1H");PrintHorizontalBorder(Size, true);// // Print a bottom borderprintf(CSI "%d;1H", Size.Y-1);PrintHorizontalBorder(Size, false);wchar_t wch;// draw columnsprintf(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 lineprintf("\t"); // advance to next tab stop}PrintStatusLine("Press any key to see text printed between tab stops.", Size);wch = _getwch();// Fill columns with outputprintf(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 sideif (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 lineint 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 sideif (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 bufferprintf(CSI "?1049l");}那如果windows版本低于win10 1607怎么辦呢?我感覺可以實(shí)現(xiàn)一個(gè)兼容層,例如微軟的telnet客戶端,他就是支持VT的,查看前一段時(shí)間nt5泄露代碼,確實(shí)找到相關(guān)的代碼。
位于?F:\nt5src\Source\Win2K3\NT\net\tcpip\services\telnet\client\trmio.c
代碼非常多,簡(jiǎn)單摘一些里面代碼聲明吧。
static UCHAR pchNBBuffer[ READ_BUF_SZ ]; static void NewLineUp(WI *, TRM *); static void NewLine(WI *pwi, TRM *); static void SetBufferStart(TRM *); static BOOL FAddTabToBuffer( TRM *, DWORD ); static BOOL FAddCharToBuffer(TRM *, UCHAR); static void FlushBuffer(WI *pwi, TRM *); static void CursorUp(TRM *); static void CursorDown(TRM *); static void CursorRight(TRM *); static void CursorLeft(TRM *); static void ClearLine(WI *pwi, TRM *, DWORD); static void SetMargins(TRM *, DWORD, DWORD);另外微軟win10 的cmd和conhost是開源的,在
https://github.com/microsoft/terminal
搜索?ENABLE_VIRTUAL_TERMINAL_PROCESSING 可找到相關(guān)的代碼
總結(jié)
以上是生活随笔為你收集整理的让Windows控制台应用程序支持VT100---原理篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows环境下IOCP和SELEC
- 下一篇: Ookla speedtest网速测试算