主控台虛擬終端機序列

虛擬終端機序列是控制字元序列,可在寫入輸出數據流時控制游標移動、控制台色彩和其他作業。 只要設定適當模式,輸入資料流上也可以接收序列來回應輸出資料流的查詢資訊序列或作為使用者輸入的編碼。

您可以使用 GetConsoleModeSetConsoleMode 函式來設定此行為。 本文件最後會包含啟用虛擬終端機行為的建議方式範例。

下列序列的行為是以 VT100 和衍生的終端機模擬器技術為基礎,特別是 xterm 終端機模擬器。 如需有關終端機序列的詳細資訊,請參閱 http://vt100.nethttp://invisible-island.net/xterm/ctlseqs/ctlseqs.html

輸出序列

如果使用 SetConsoleMode 函式在畫面緩衝區句柄上設定了ENABLE_VIRTUAL_TERMINAL_PROCESSING旗標,控制台主機會在寫入輸出數據流時攔截下列終端機序列。 請注意,DISABLE_NEWLINE_AUTO_RETURN旗標在模擬其他終端模擬器的數據指標定位和捲動行為時可能也很有用,這些行為與寫入任何數據列中最後一個數據行的字元有關。

簡單的游標定位

在下列所有描述中,ESC 一律是十六進位值 0x1B。 終端機序列中不會包含任何空格。 個別的終端序列可以在任何字元或位元位置分割至 WriteFileWriteConsole 的多個循序呼叫,但最佳做法是將整個序列包含在一個呼叫中。 如需如何在實務中使用這些序列的範例,請參閱本主題結尾處的範例

下表描述直接在 ESC 字元之後使用單一動作命令的簡單逸出序列,並。 這些序列沒有參數,而且會立即生效。

此資料表中的所有命令通常等同於呼叫 SetConsoleCursorPosition 主控台 API 來放置游標。

游標移動會由目前的檢視區繫結至緩衝區中。 將不會發生捲動 (如果適用)。

序列 速記法 行為
ESC M RI 反向索引 – 執行 \n 的反向作業、將游標向上移動一行、維護水準位置、視需要捲動緩衝區*
ESC 7 DECSC 將游標位置儲存在記憶體中**
ESC 8 DECSR 從記憶體還原游標位置**

注意

* 如果已設定卷動邊界,邊界內的 RI 只會捲動邊界的內容,並將檢視區維持不變。 (請參閱捲動邊界)

**儲存命令的第一次使用之前,記憶體中不會儲存任何值。 存取儲存值的唯一方法是使用還原命令。

游標定位

下表包含控制序列引導器 (Control Sequence Introducer,CSI) 類型的序列。 所有 CSI 序列都是以 ESC (0x1B) 開頭,後面接著 [ (左括弧,0x5B),而且可能包含可變長度的參數,以指定每個作業的詳細資訊。 這會以速記法 <n> 表示。 下列每個資料表都會依功能分組,並在每個資料表下方說明群組的運作方式。

除非另有註明,否則所有參數皆適用下列規則:

  • <n> 代表要移動的距離,而且屬於選擇性參數
  • 如果 <n> 省略或等於 0,則會將其視為 1
  • <n> 不能大於 32,767 (最大 short 值)
  • <n> 不可以是負數

本節中的所有命令通常等同於呼叫 SetConsoleCursorPosition主控台 API。

游標移動會由目前的檢視區繫結至緩衝區中。 將不會發生捲動 (如果適用)。

序列 代碼 描述 行為
ESC [ <n> A CUU 游標向上移 游標向上移 <n> 個位置
ESC [ <n> B CUD 游標向下移 游標向下移 <n> 個位置
ESC [ <n> C CUF 游標向前移 游標向前 (右) 移 <n> 個位置
ESC [ <n> D CUB 游標向後移 游標向後 (左) 移 <n> 個位置
ESC [ <n> E CNL 游標移到下一行 游標從目前位置向下移動 <n> 行
ESC [ <n> F CPL 游標移到上一行 游標從目前位置向上移動 <n> 行
ESC [ <n> G CHA 游標水平移到絕對位置 游標水平移至目前這一行中的第 <n> 個位置
ESC [ <n> d VPA 游標垂直移動到行的絕對位置 游標垂直移至目前資料行中的第 <n> 個位置
ESC [ <y> ; <x> H CUP 游標位置 *游標移至 <x>; <檢視區內的 y> 座標,其中 <x> 是 y> 線的數據<行
ESC [ <y> ; <x> f HVP 水平垂直位置 *游標移至 <x>; <檢視區內的 y> 座標,其中 <x> 是 y> 線的數據<行
ESC [ s ANSISYSSC 儲存游標 – Ansi.sys 模擬 **如果沒有參數,請執行儲存數據指標作業,例如 DECSC
ESC [ u ANSISYSRC 還原游標 – Ansi.sys 模擬 **沒有參數,執行還原數據指標作業,例如 DECRC

注意

*<x> 和 <y> 參數的限制與上述 n> 相同<。 如果省略 <x> 和 <y>,則會設為 1;1。

**ANSI.sys歷史文件位於 https://msdn.microsoft.com/library/cc722862.aspx 並實作,以方便/相容性。

游標可見度

下列命令會控制游標的可見度和其閃爍狀態。 DECTCEM 序列通常等同於呼叫 SetConsoleCursorInfo 主控台 API 來切換游標可見度。

序列 代碼 描述 行為
ESC [ ? 12 h ATT160 文字游標啟用閃爍 啟動游標閃爍
ESC [ ? 12 l ATT160 文字游標停用閃爍 停止游標閃爍
ESC [ ? 25 h DECTCEM 文字游標啟用模式顯示 顯示游標
ESC [ ? 25 l DECTCEM 文字游標啟用模式隱藏 隱藏游標

提示

啟用序列的結尾是小寫 H 字元 (h),而停用序列的結尾則是小寫 L 字元 (l)。

游標圖形

下列命令會控制並允許自定義游標圖形。

序列 代碼 描述 行為
ESC [ 0 SP q DECSCUSR 用戶圖形 用戶設定的預設游標圖形
ESC [ 1 SP q DECSCUSR 閃爍區塊 閃爍區塊游標圖形
ESC [ 2 SP q DECSCUSR 穩定區塊 穩定區塊游標圖形
ESC [ 3 SP q DECSCUSR 閃爍底線 閃爍底線游標圖形
ESC [ 4 SP q DECSCUSR 穩定底線 穩定底線游標圖形
ESC [ 5 SP q DECSCUSR 閃爍列 閃爍列游標圖形
ESC [ 6 SP q DECSCUSR 穩定條 穩定條游標圖形

注意

SP 是中繼位置中的常值空格字元 (0x20),後面接著 q 最後一個位置的 (0x71)。

檢視區定位

本節中的所有命令通常等同於呼叫 ScrollConsoleScreenBuffer 主控台 API 來移動主控台緩衝區的內容。

注意 命令名稱會造成誤導。 捲動 (Scroll) 是指文字在作業期間移動的方向,而不是檢視區要移動的方式。

序列 代碼 描述 行為
ESC [ <n> S SU 向上捲動 文字向上捲動 <n> 個位置。 也稱為「向下平移」,新行會從畫面底部填入
ESC [ <n> T SD 向下捲動 向下捲動 <n> 個位置。 也稱為「向上平移」,新行會從畫面頂端填入

文字會從游標所在的那一行開始移動。 如果游標位於檢視區的中間資料列上,則向上捲動會移動此檢視區的下半部,並在底部插入空白行。 向下捲動會移動檢視區資料列的上半部,並在頂端插入新行。

另外,要注意的是,向上和向下捲動也會受到捲動邊界的影響。 向上和向下捲動不會影響捲動邊界以外的任何行。

<n> 的預設值是 1,而且可以選擇性地省略此值。

文字修改

本節中的所有命令通常等同於呼叫 FillConsoleOutputCharacterFillConsoleOutputAttributeScrollConsoleScreenBuffer 主控台 API 來修改文字緩衝區內容。

序列 代碼 描述 行為
ESC [ <n> @ ICH 插入字元 在目前的游標位置上插入 <n> 個空格,並將所有現有的文字移至右方。 移至畫面右側的現有文字會移除。
ESC [ <n> P DCH 刪除字元 刪除目前游標位置上的 <n> 個字元,從畫面右側邊緣移入空白字元。
ESC [ <n> X ECH 清除字元 藉由以空白字元覆寫的方式,從目前的游標位置清除 <n> 個字元。
ESC [ <n> L 伊利諾州 插入線條 將 <n> 行插入游標位置上的緩衝區。 游標所在的行和其下方的行將會向下移動。
ESC [ <n> M DL 刪除行 從緩衝區中刪除 <n> 行,從游標所在的資料列開始。

注意

針對 IL 和 DL,只有捲動邊界 (請參閱捲動邊界) 中的行會受到影響。 如果未設定邊界,則預設的邊界框線為目前的檢視區。 如果行會在邊界下方移動,則會遭到捨棄。 刪除行時,邊界底部會插入空白行,而檢視區外的行則不會受到影響。

針對每個序列,如果省略 <n>,則預設值為0。

在下列命令中,參數 <n> 具有 3 個有效值:

  • 0 會從目前的游標位置 (包含該位置) 清除到行/顯示畫面的結尾
  • 1 會從行/顯示畫面的開頭清除到目前的游標位置 (包含該位置)
  • 2 清除整行/整個顯示畫面
序列 代碼 描述 行為
ESC [ <n> J ED 清除顯示畫面 以空白字元取代 <n> 所指定的目前檢視區/畫面中的所有文字
ESC [ <n> K EL 清除行 以空白字元取代 <n> 所指定游標所在行上的所有文字

文字格式

本節中的所有命令通常等同於呼叫 SetConsoleTextAttribute 主控台 API,用於調整未來所有主控台輸出文字緩衝區的寫入格式。

此命令是特別的,因為下面的 <n> 位置可以接受 0 到 16 的參數 (以分號分隔)。

若未指定任何參數,則會將其視為等同於一個參數 0。

序列 代碼 描述 行為
ESC [ <n> m SGR 設定圖形轉譯 依據 <n> 所指定的內容設定畫面的格式和文字

下表的值可以在 <n> 中用來代表不同的格式化模式。

格式化模式會從左至右套用。 套用競爭格式化選項會使最右邊的選項具有優先權。

針對指定色彩的選項,這些色彩會依照主控台色彩表中的定義使用,您可以使用 SetConsoleScreenBufferInfoEx API 加以修改。 如果將資料表修改為讓資料表中的「藍色」位置顯示 RGB 色度的紅色,則對前景藍色發出的所有呼叫都會顯示該紅色色彩,直到另有變更為止。

Description 行為
0 預設 在修改前將所有屬性都設回為預設狀態
1 濃厚/明亮 將亮度/飽和度旗標套用至前景色彩
22 沒有粗體/明亮 從前景色彩移除亮度/強度旗標
4 底線 加底線
24 沒有底線 移除底線
7 負值 交換前景和背景色彩
27 正面 (非負面) 讓前景/背景回到一般狀態
30 前景黑色 將非濃厚/明亮的黑色套用至前景
31 前景紅色 將非濃厚/明亮的紅色套用至前景
32 前景綠色 將非濃厚/明亮的綠色套用至前景
33 前景黃色 將非濃厚/明亮的黃色套用至前景
34 前景藍色 將非濃厚/明亮的藍色套用至前景
35 前景洋紅色 將非濃厚/明亮的洋紅色套用至前景
36 前景青色 將非濃厚/明亮的青色套用至前景
37 前景白色 將非濃厚/明亮的白色套用至前景
38 前景擴充 將擴充的色彩值套用至前景 (請參閱下列詳細資料)
39 前景預設值 僅套用預設的前景部分 (請參閱 0)
40 背景黑色 將非濃厚/明亮的黑色套用至背景
41 背景紅色 將非濃厚/明亮的紅色套用至背景
42 背景綠色 將非濃厚/明亮的綠色套用至背景
43 背景黃色 將非濃厚/明亮的黃色套用至背景
44 背景藍色 將非濃厚/明亮的藍色套用至背景
45 背景洋紅色 將非濃厚/明亮的洋紅色套用至背景
46 背景青色 將非濃厚/明亮的青色套用至背景
47 背景白色 將非濃厚/明亮的白色套用至背景
48 背景擴充 將擴充的色彩值套用至背景 (請參閱下列詳細資料)
49 背景預設值 僅套用預設的背景部分 (請參閱0)
90 明亮前景黑色 將濃厚/明亮的亮黑色套用至前景
91 明亮前景紅色 將濃厚/明亮的紅色套用至前景
92 明亮前景綠色 將濃厚/明亮的綠色套用至前景
93 明亮前景黃色 將濃厚/明亮的黃色套用至前景
94 明亮前景藍色 將濃厚/明亮的藍色套用至前景
95 明亮前景洋紅色 將濃厚/明亮的洋紅色套用至前景
96 明亮前景青色 將濃厚/明亮的青色套用至前景
97 明亮前景白色 將濃厚/明亮的白色套用至前景
100 明亮的背景黑色 將濃厚/明亮的黑色套用至背景
101 明亮背景紅色 將濃厚/明亮的紅色套用至背景
102 明亮背景綠色 將濃厚/明亮的綠色套用至背景
103 明亮的背景黃色 將濃厚/明亮的黃色套用至背景
104 明亮背景藍色 將濃厚/明亮的藍色套用至背景
105 明亮背景洋紅色 將濃厚/明亮的洋紅色套用至背景
106 明亮背景青色 將濃厚/明亮的青色套用至背景
107 明亮背景白色 將濃厚/明亮的白色套用至背景

擴充的色彩

某些虛擬終端機模擬器支援的色彩調色板多於 Windows 主控台所提供的 16 種色彩。 針對這些擴充的色彩,Windows 主控台會從現有的 16 色表格中選擇最接近的色彩來顯示。 不同於上述的一般 SGR 值,擴充的值會根據下表,在使用最初的指示器之後取用額外的參數。

SGR 子序列 描述
38 ; 2 ; <r> ; <g> ; <b> 將前景色彩設定為 r>、g>、<<b> 參數中指定的 <RGB 值*
48 ; 2 ; <r> ; <g> ; <b> 將背景色彩設定為 r>、 g>、 <<b> 參數中指定的 <RGB 值*
38 ; 5 ; <s> 將前景色彩設定為 <> 88或256色彩表格中的索引*
48 ; 5 ; <s> 將背景色彩設定為 <> 88 或 256 色彩表格中的索引*

*在內部維護的88和256調色盤會以 xterm 終端機模擬器為基礎。 目前無法修改比較/進位表。

畫面色彩

下列命令可讓應用程式將畫面色彩調色盤值設定為任何 RGB 值。

RGB 值應該是 0ff 之間的十六進位值,並以正斜線字元 (例如 rgb:1/24/86) 分隔。

請注意,此序列是 OSC「操作系統命令」序列,而不是 CSI,就像列出的許多其他序列一樣,例如從 “\x1b]”開始,而不是 “\x1b[”。 當 OSC 序列時,它們會以表示為 <ST> 的字串終止符結束,並以 ESC \0x1B 0x5C) 傳輸。 BEL0x7) 可以改用為終止符,但偏好較長的格式。

序列 描述 行為
ESC ] 4 ;<i> ;rgb : <r> / g> / <<b><ST> 修改畫面色彩 將畫面色彩調色盤索引 <i> 設定為 <r>、<g>、<b> 中指定的 RGB 值

模式變更

這些是控制輸入模式的序列。 有兩組不同的輸入模式:游標按鍵模式和鍵盤按鍵模式。 游標按鍵模式會控制由方向鍵及 Home 與 End 所發出的序列,而鍵盤按鍵模式會控制主要由 Numpad 上按鍵及功能鍵所發出的序列。

這些模式中的每一個都是簡單的布林值設定 – 游標按鍵模式是標準 (預設) 或應用程式,而鍵盤按鍵模式則是數字 (預設值) 或應用程式。

請參閱 [游標按鍵] 和 [Numpad 與功能鍵] 區段,以了解在這些模式中發出的序列。

序列 代碼 描述 行為
ESC = DECKPAM 啟用鍵盤應用程式模式 鍵盤按鍵會發出其應用程式模式序列。
ESC > DECKPNM 啟用鍵盤數字模式 鍵盤按鍵會發出其數字模式序列。
ESC [ ? 1 小時 DECCKM 啟用游標按鍵應用程式模式 鍵盤按鍵會發出其應用程式模式序列。
ESC [ ? 1 l DECCKM 停用游標按鍵應用程式模式 (使用標準模式) 鍵盤按鍵會發出其數字模式序列。

查詢狀態

本節中的所有命令通常相當於呼叫 Get* 控制台 API,以擷取目前控制台緩衝區狀態的狀態資訊。

注意

這些查詢會在設定ENABLE_VIRTUAL_TERMINAL_PROCESSING時,立即在輸出數據流上辨識之後,將其回應發出至主控台輸入數據流。 ENABLE_VIRTUAL_TERMINAL_INPUT 旗標不適用於查詢命令,因為假設發出查詢的應用程式一律會想要接收回復。

序列 代碼 描述 行為
ESC [ 6 n DECXCPR 回報游標位置 將游標位置發出為:ESC [ <r> ; <c> R Where <r> = cursor row and <c> = cursor column
ESC [ 0 c DA 裝置屬性 回報終端機身分識別。 會發出 「\x1b[?1;0c“,表示”VT101 沒有選項“。

Tab

雖然 Windows 控制台傳統上預期索引標籤會全長八個字元,但使用特定序列的 *nix 應用程式可以操作控制台視窗內製表位的位置,以優化應用程式的數據指標移動。

下列序列可讓應用程式設定主控台視窗中 Tab 的停止位置、將這些位置移除,以及在這些位置之間瀏覽。

序列 代碼 描述 行為
ESC H HTS 水平 Tab 設定 在游標所在的目前資料行中設定 Tab 停止點。
ESC [ <n> I CHT 游標水平 (向前) Tab 使游標前進至下一個資料行 (在相同的資料列中),並使用 Tab 停止點。 如果不再有 Tab 停止點,則移至資料列中的最後一個資料行。 如果游標在最後一個資料行中,則移至下一個資料列的第一個資料行。
ESC [ <n> Z CBT 游標向後 Tab 使游標移至上一個資料行 (在相同的資料列中),並使用 Tab 停止點。 如果不再有 Tab 停止點,則將游標移至第一個資料行。 如果游標在第一個資料行中,則不移動游標。
ESC [ 0 g TBC Tab 清除 (目前的資料行) 清除目前資料行中的 Tab 停止點 (如果有的話)。 沒有的話,則不會執行任何動作。
ESC [ 3 g TBC Tab 清除 (所有資料行) 清除所有目前設定的 Tab 停止點。
  • 對於 CHT 和 CBT,<n> 是選擇性參數 (預設值 = 1),表示要讓游標在指定的方向前進多少次。
  • 如果沒有透過 HTS 設定的 Tab 停止點,CHT 和 CBT 會將視窗的第一個和最後一個資料行視為唯一的兩個 Tab 停止點。
  • 使用 HTS 設定製表位也會導致控制台以與 CHT 相同的方式,流覽至 TAB (0x09, '\t' 字元輸出上的下一個製表位。

指定字元集

下列序列可讓程式變更作用中字元集的對應。 這可讓程式發出 7 位元的 ASCII 字元,但會在終端機畫面本身將其顯示為其他字符。 目前唯一支援的兩個字元集是 ASCII (預設值) 和 DEC 特殊圖形字元集。 如需 DEC 特殊圖形字元集所代表的所有字元清單,請參閱 http://vt100.net/docs/vt220-rm/table2-4.html

序列 描述 行為
ESC ( 0 指定字元集 – DEC 線條繪圖 啟用 DEC 線條繪圖模式
ESC ( B 指定字元集 – US ASCII 啟用 ASCII 模式 (預設值)

值得注意的是,DEC 線條繪圖模式會用來在主控台應用程式中繪製框線。 下表顯示 ASCII 字元與線條繪圖字元的對應。

Hex ASCII DEC 線條繪圖
0x6a j
0x6b k
0x6c l
0x6d m
0x6e n
0x71 q ─ ─
0x74 t
0x75 u
0x76 v
0x77 w
0x78 x

捲動邊界

下列序列可讓程式設定受到捲動作業影響的畫面「捲動區域」。 這是螢幕在 『\n』 或 RI 上捲動時調整的數據列子集。 這些邊界也會影響插入行 (IL) 和刪除行 (DL) 及向上捲動 (SU) 和向下捲動 (SD) 所修改的資料列。

如果畫面有個部分不會在畫面其餘部分填滿時捲動,例如應用程式頂端有標題列或底部有狀態列,則特別適用捲動邊界。

DECSTBM 有兩個選擇性參數:<t> 和 <b>,可用來指定代表捲動區域頂端和底部幾行的資料列 (含)。 如果省略參數,<t> 會預設為1,而 <b> 會預設為目前檢視區的高度。

捲動邊界是為每個緩衝區設定的,所以很重要的是,替代緩衝區和主要緩衝區會維持不同的捲動邊界設定 (因此,替代緩衝區中的全畫面應用程式不會妨礙到主要緩衝區的邊界)。

序列 代碼 描述 行為
ESC [ <t> ; <b> r DECSTBM 設定捲動區域 設定檢視區的 VT 捲動邊界。

視窗標題

下列命令可讓應用程式將主控台視窗的標題設定為指定的 <字串> 參數。 字串必須小於 255 個字元才能被接受。 這相當於以指定字串呼叫 SetConsoleTitle。

請注意,這些序列是 OSC「操作系統命令」序列,而不是像列出的許多其他序列一樣 CSI,例如開頭為 “\x1b]”,而不是 “\x1b[”。 當 OSC 序列時,它們會以表示為 <ST> 的字串終止符結束,並以 ESC \0x1B 0x5C) 傳輸。 BEL0x7) 可以改用為終止符,但偏好較長的格式。

序列 描述 行為
ESC ] 0 ; <字串><聖> 設定 Window 標題 將主控台視窗的標題設定為 <字串>。
ESC ] 2 ; <字串><聖> 設定 Window 標題 將主控台視窗的標題設定為 <字串>。

這裡的終止字元是 “Bell” 字元 '\x07'

替代畫面緩衝區

*Nix 樣式應用程式通常會使用替代螢幕緩衝區,以便修改緩衝區的整個內容,而不會影響啟動它們的應用程式。 替代緩衝區完全是視窗的維度,沒有任何回捲區域。

如需此行為的範例,請考慮從 bash 啟動 Vim 的時機。 Vim 會使用整個畫面來編輯檔案,然後返回 bash 會讓原始緩衝區保持不變。

序列 描述 行為
ESC [ ? 1 0 4 9 h 使用替代畫面緩衝區 切換至新的替代畫面緩衝區。
ESC [ ? 1 0 4 9 l 使用主要畫面緩衝區 切換至主要緩衝區。

視窗寬度

您可以使用下列序列來控制主控台視窗的寬度。 這些序列大致等同於呼叫 SetConsoleScreenBufferInfoEx 主控台 API 來設定視窗寬度。

序列 代碼 描述 行為
ESC [ ? 3 h DECCOLM 將資料行數目設定為 132 將主控台寬度設定為 132 個資料行寬。
ESC [ ? 3 l DECCOLM 將資料行數目設定為 80 將主控台寬度設定為 80 個資料行寬。

軟重設

您可以使用下列序列將某些屬性重設為預設值。下列屬性會重設為下列預設值 (也會列出控制這些屬性的序列):

  • 游標可見度:可見 (DECTEM)
  • 數位鍵盤:數值模式(DECNKM)
  • 資料指標索引鍵模式:標準模式(DECCKM)
  • 上邊界和下邊界:Top=1、Bottom=Console height (DECSTBM)
  • 字元集:US ASCII
  • 圖形轉譯:預設/關閉 (SGR)
  • 儲存游標狀態:首頁位置 (0,0) (DECSC)
序列 代碼 描述 行為
ESC [ ! p DECSTR 軟重設 將特定的終端機設定重設為預設值。

輸入序列

如果使用 SetConsoleMode 旗標在輸入緩衝區句柄上設定ENABLE_VIRTUAL_TERMINAL_INPUT旗標,控制台主機就會發出下列終端機序列。

有兩種內部模式可控制針對指定輸入鍵發出的序列:游標按鍵模式和鍵盤按鍵模式。 這會在 [模式變更] 區段中加以說明。

游標按鍵

索引鍵 正常模式 應用程式模式
向上鍵 ESC [ A ESC O A
向下鍵 ESC [ B ESC O B
向右鍵 ESC [ C ESC O C
向左鍵 ESC [ D ESC O D
家用 ESC [ H ESC O H
結束 ESC [ F ESC O F

此外,如果按下 Ctrl 鍵和這其中任何一個鍵,則會改為發出下列序列 (不論游標按鍵模式為何):

索引鍵 任何模式
Ctrl + 向上鍵 ESC [ 1 ; 5 A
Ctrl + 向下鍵 ESC [ 1 ; 5 B
Ctrl + 向右鍵 ESC [ 1 ; 5 C
Ctrl + 向左鍵 ESC [ 1 ; 5 D

Numpad 與功能鍵

索引鍵 序列
退格鍵 0x7f (DEL)
暫停 0x1a (SUB)
ESC 鍵 0x1b (ESC)
插入​​ ESC [ 2 ~
刪除 ESC [ 3 ~
Page Up ESC [ 5 ~
Page Down ESC [ 6 ~
F1 ESC O P
F2 ESC O Q
F3 ESC O R
F4 ESC O S
F5 ESC [ 1 5 ~
F6 ESC [ 1 7 ~
F7 ESC [ 1 8 ~
F8 ESC [ 1 9 ~
F9 ESC [ 2 0 ~
F10 ESC [ 2 1 ~
F11 ESC [ 2 3 ~
F12 ESC [ 2 4 ~

輔助按鍵

Alt 是藉由在序列前面加上逸出:ESC <c,其中 <c>> 是操作系統所傳遞的字元。 Alt+Ctrl 的處理方式相同,不同之處在於作業系統會將 <c> 鍵預先轉移至適當的控制字元,以轉送至應用程式。

傳遞的 Ctrl 通常會與從系統中收到的完全相同。 這通常是移到控制字元保留空間 (0x0-0x1f) 中的單一字元。 例如,Ctrl+@ (0x40) 會變成 NUL (0x00),Ctrl+[ (0x5b) 變成 ESC (0x1b), 等等。根據下表,會特別處理幾個 Ctrl 按鍵組合:

索引鍵 序列
Ctrl + 空格鍵 0x00 (NUL)
Ctrl + 向上鍵 ESC [ 1 ; 5 A
Ctrl + 向下鍵 ESC [ 1 ; 5 B
Ctrl + 向右鍵 ESC [ 1 ; 5 C
Ctrl + 向左鍵 ESC [ 1 ; 5 D

注意

左側 Ctrl + 右側 Alt 會視為 AltGr。 兩者同時出現時,則會將這兩者移除,並將系統所呈現的字元 Unicode 值傳遞到目標。 系統會根據目前的系統輸入設定,預先轉譯 AltGr 值。

範例

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");

    return 0;
}

注意

在上一個範例中,字串 '\x1b[31m' 是 ESC [ <n> m 的實作,n <> 為 31。

下圖顯示先前程式碼範例的輸出。

output of the console using the sgr command

啟用虛擬終端處理的範例

下列程式碼提供為應用程式啟用虛擬終端處理的建議方式範例。 範例的目的是要示範:

  1. 現有模式應一律透過 GetConsoleMode 取得,並在使用 SetConsoleMode 設定之前進行分析。

  2. 檢查 SetConsoleMode 是否傳回 0 ,而 GetLastError 是否傳回ERROR_INVALID_PARAMETER是目前的機制,以判斷在下層系統上執行時。 接收ERROR_INVALID_PARAMETER且位欄位元中具有其中一個較新控制台模式旗標的應用程式,應該會正常降級行為,然後再試一次。

#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 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;
    }

    return 0;
}

選取年度更新功能的範例

下列範例是使用各種逸出序列來操作緩衝區且更健全的程式碼範例,並且會強調 Windows 10 年度更新版中新增的功能。

此範例會使用替代畫面緩衝區、操控 Tab 停止點、設定捲動邊界及變更字元集。

// 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");

}