Keyboard

如何為定義 GNU 螢幕“命令字元”提供一套全面的可能性?

  • November 29, 2015

我想以某種方式生成一個全面的“菜單”,其中包含所有可能的方式來為標準、現成的“美國鍵盤”和特定的終端仿真器設置 GNU 螢幕“命令字元”,比如xfce4-terminal

我想這個宇宙的可能性會分解成三個列表:

  • list Aescape :指令的所有可能值
  • 列表B<CODE> :表達式中參數的所有可能值bindkey -k <CODE> command,以及“空設置”(即未使用指令的.screenrc配置)bindkey -k <CODE> command
  • 列表C:從任何對 ( ab )(其中a  ∈  Ab  ∈  B)到一個明確描述如何在標準美國鍵盤上鍵入相應 GNU 螢幕命令字元的映射,並假設特定終端仿真器(IOW,相當於,例如,“同時按下Ctrl\”)。

但是請記住,這些規範是真正不了解底層基礎知識的人(我)的“最大努力” 。希望那些理解這些基礎知識的人能夠“在字裡行間”,並根據需要修改這些規範,同時仍然保留問題的精神(參見背景),以使問題易於處理。

我意識到我希望的“菜單”可能非常大,但我認為它不可能如此棘手,因為畢竟標準美式鍵盤上的按鍵數量是有限的,而不是巨大的,而且可以用於此目的的一組手指更是如此。(如果重要的話,我可以進一步規定我只對包含最多 2 個連續“鍵和弦”的鍵組合感興趣,每個鍵和弦最多 3 個鍵。“鍵和弦”的意思是“設置同時按下的鍵數”。)


背景

(又名 tl;博士)

這個問題實際上是 Gilles 在我之前開始的一個執行緒中的評論的後續。事實證明,該評論所說的大部分內容都超出了我的理解範圍。我認為我對這裡的基礎知識的理解存在巨大差距,事實上,差距如此之大,以至於我什至無法表達出足夠清晰的問題來填補它們。

簡而言之,對我來說,這是一個巨大的謎團,例如,組合鍵Ctrl+\可用於鍵入 GNU-screen 的“命令字元”,而其他外觀相似的組合鍵,如 (maybe) Ctrl+'則不能1 .

如果使用者(像我一樣)沒有清楚地了解底層基礎知識,搜尋合適的 GNU 螢幕命令字元會簡化為一系列孤立的建議(“ *+*怎麼樣?畢竟,沒有人將它用於其他任何事情。Ctrl``H “) 使用者依次評估,直到彈出一個可接受的值。

這一系列建議和評估需要持續多長時間取決於該使用者可接受的組合鍵的大小。顯然,這個大小會因使用者而異。就我而言,它似乎小於平均水平,因此這種方法還沒有給我一個可接受的 GNU-screen 的“命令字元”。

無論如何,這種方法在我看來本質上是低效的。能夠從明確的“宇宙”(即“詳盡的集合”)的可能性中選擇最佳選項對我來說更有意義。這就是我想在這裡得到的。


**編輯:**好的,經過一些研究,我現在清楚地了解瞭如何在\0001和之間的 ASCII 範圍內鍵入(1 字節)字元\0177,包括在內。這些包括所有“真正的”“控製字元”。

此外,我認為列表A可以描述為 和 之間的所有可能的整數對\0001\0377儘管可能其中許多對可以被排除為完全不切實際。(例如,其中第一個元素是常見的“可列印字元”,例如“e”或“8”)。

我仍在嘗試找出以下內容:

  • 如何將 ASCII 範圍內的(1 字節)字元鍵入\0200\0377,包括在內;我預計終端和終端仿真器之間會有一些變化,但目前我不知道變化有多混亂;這些角色中是否存在有實質性共識的子集?如果是這樣,我很想知道這些字元是什麼(以及如何輸入它們)
  • 如何獲得列表B的有用值;我意識到這些值是termcap程式碼;我在這裡的困難是沒有辦法辨識那些termcap整齊地映射到方便的組合鍵的程式碼;例如,我知道程式碼F2映射到F12(原文如此),但我想大多數termcap程式碼都沒有與單個鍵如此整齊的關聯。
  • 如何完成列表C,即使對於特定的終端仿真器,以及列表B中的“空設置” 。

1不要試圖向我解釋這個謎團:很多知識淵博、非常耐心的人都試過了,但我還是不明白。那些了解正在發生的事情的人和我之間的“知識差距”是如此之大,以至於他們的答案總是和他們想要解決的問題一樣讓我感到困惑。我希望通過這篇文章實現的正是解決這個巨大的知識鴻溝,通過將問題轉換為搜尋,本質上,一種算法(建構規定的有限可能性集),甚至可以由不了解底層基礎知識的人。

要理解這個問題的答案,您需要對鍵盤輸入的處理方式有所了解。我向您推薦鍵盤輸入和文本輸出如何工作?為背景。在這個答案中,我將以不同的方式解釋相關部分,但我會假設我之前的答案給出了一些普遍的熟悉度。

我在這裡的回答涉及典型的 unix 系統;非 Unix 系統的行為可能不同。我會在這里和那裡做一些簡化;額外的並發症與回答這個問題無關。(這個答案已經夠複雜了。)

大多數通信和儲存,包括基於終端的應用程序和終端(硬體或軟體)之間的通信,都採用字節流的形式。一個字節是一個資訊單位,可以取 256 個不同的值;它可以細分為 8。字節由 0 到 255 之間的數字表示。

為了傳輸資訊,各方需要就將資訊編碼為字節的方式達成一致。有多種方法可以將字元流編碼為字節流,但它們都以一種或另一種方式基於ASCII。ASCII 定義了從 0 到 127 的 7 位值與一組 128 個字元之間的對應關係;這會在每個字節中留下一個未使用的位。128 個字元分為兩類:

  • 95 個可列印字元:字母(A-Z、小寫和大寫)、數字 (0-9)、空格、一些標點符號;
  • 33個控製字元

控製字元對發送到終端或從終端發送的命令和輔助資訊進行編碼,例如“將游標移動到下一行”、“按鈴”、“等我”、“再見”等。歷史終端引入了一個標記為“ Control”(或簡稱“Ctrl”),允許使用者輸入控製字元。為了保持終端的電子設備簡單,Ctrl與鍵一起按下將在通常由字元發送的字節值中執行簡單的位遮罩。例如A發送A字節65表示的字元(二進制1000001);Ctrl+A發送由字節值 1(二進制中的 0000001)表示的字元,該字元被稱為“控制-A”字元,通常寫成^A.

大多數控製字元對應一個大寫字母,位模式為 10xxxxx,位 6 設置為 0 而不是 1。佔其中的 26 個。另外 6 個控製字元對應於也具有 10xxxxx 形式的位模式的標點字元:這些是@[\]^_(參見ASCII 可列印字元表。除了範圍 0-31 之外,字元 127 也是一個控製字元;眾所周知作為“控制-?”(?是 0111111;控制-?是 1111111)。

多年來,非 ASCII 字節值被賦予了不同的含義。世界正在向Unicode作為任何人都可能想要的所有字元的集合。Unix 世界(以及 Internet)大多已將UTF-8標準化為將字元編碼為字節序列的一種方式。UTF-8 通過將與 ASCII 相同的字元分配給 0-127 範圍內的任何字節,並使用 128-255 範圍內的 2 到 4 個字節序列來表示大約百萬個其他字元,從而保持與 ASCII 的兼容性。unix 世界中使用了其他一些字元編碼;大多數基於 ASCII,對於 128 以上的字節有不同的含義。

我現在可以回答您的後續問題之一:

如何在 ASCII 範圍內鍵入(1 字節)字元\0200\0377

這取決於您使用的字元編碼。如果您使用最常見的 UTF-8,則無法發送這些單獨的字節,因為它們僅用作代表單個字元的 2 到 4 個字節序列的一部分。

至於

list Aescape :指令的所有可能值

那隻是字節值。該escape指令需要一個兩字節參數。如果 Screen 從終端接收到第一個字節值,則確定它的退出鍵已被按下。如果終端發送的下一個字節是escape設置中的第二個字節,那麼 Screen 決定您希望將第一個字節發送到在 Screen 視窗內執行的應用程序。

bind命令的描述解釋瞭如何以 Screen 理解的方式指定字節值。在文件中讀取“字元”的地方,改為讀取“字節”。

在我們進入列表 B 之前,我們需要了解鍵和弦。keychord 是按下一個鍵以及諸如 , 等修飾符CtrlShift我們之前看到終端傳輸的所有資訊都被編碼為字節流。為簡單起見,所有可列印字元都以標準方式編碼,如果它們是 ASCII 字元,則編碼為 32–126 範圍內的一個字節,其他字元則編碼為 128–255 範圍內的字節。這僅留下控製字元來編碼功能鍵和具有除 . 以外的修飾符的字元Shift。但是控製字元只有33個!

幾個功能鍵發送一個控製字元。例如,Tab鍵發送^I(字節值 9),因為字節 9 是指示列印機移動到下一個製表符列的製表符控製字元。Return鍵發送(^M字節值 13),因為字節 13 是 CR 控製字元,指示列印機將其頭部移動到行首。由於類似的原因,Escapesend^[和sendBackSpace要麼^H^?由於一些歷史上的胡扯,我不會在這裡討論。

大多數功能鍵和鍵弦發送一個轉義序列:從字節 27 開始的字節序列,由 ASCII 定義的轉義字元(ESC),恰好是^[(control-[)。不同的終端發送不同的轉義序列。有標準,但他們沒有定義所有鍵弦的編碼,遠非如此,並且在某種程度上存在競爭標準。

我們現在準備好了解

list B<CODE> :表達式中參數的所有可能值bindkey -k <CODE>

Screen 文件解釋說這些程式碼是termcap鍵盤功能名稱。Termcap 是一個程式庫,應用程序可以使用它從終端之間的變化中抽像出來。(現在它已大部分被Terminfo取代。) Termcap 數據庫專門包含有關終端的資訊,例如行數和列數(當 Termcap 出現時,終端是硬體設備,調整大小的概念並不適用) ,應用程序可以用來執行諸如移動游標或清除螢幕等操作的字節序列(通常以 ESC 開頭),以及由各種鍵發送的字節序列。Termcap 賦予功能鍵的符號名稱是您可以在之後使用的名稱bindkey -k.

Termcap 手冊列出了該數據庫中的所有條目。這些條目都有兩個字元的名稱;FreeBSD 手冊還為每個條目提供了一個更具表現力的名稱。FreeBSD在第一列中列出的條目是描述功能鍵的條目;您需要的是第二列中的名稱,例如for 、for 、for等。key_*SOMETHING*``<CODE>``bindkey -k``kl``Left``k1``F1``F1``F11

您會注意到這個數據庫缺少很多鍵弦。如果此數據庫中沒有鍵弦條目,則沒有可用於帶有 的鍵的名稱bindkey -k。請注意,支持的密鑰集因 unix 變體而異。

bindkey也可以傳遞一個轉義序列。要使用此功能,您需要知道您的終端為您感興趣的鍵弦發送什麼。雖然不同的終端為同一個鍵弦發送不同的轉義序列,幸運的是,從轉義序列到鍵弦很少有歧義:很少有轉義序列對應於不同終端上的不同鍵弦。

Ctrl您可以通過按+V然後按 keychord 來找出 keychord 發送的轉義序列。在預設模式下的終端中,以及在所有常見 shell 的命令行中,Ctrl+V表示“按字面解釋下一個字節”。如果後面跟著一個轉義序列,這會導致按字面意思插入 ESC 字節,而不是啟動轉義序列的解析。由於轉義序列幾乎總是由 ESC 之後的可列印字元組成,因此這有效地插入了轉義序列。例如,按Ctrl+V然後Ctrl+Left查看轉義序列Ctrl+Left發送的內容:您會看到類似^[O5Dwhere^[是 ESC 控製字元的視覺化表示。(再一次,您的終端可能會發送不同的轉義序列。)

至於null設置,當Screen讀取一個ESC字節時,進入轉義序列解析模式。每個新字節都被添加到累積的轉義序列中。如果累積的序列有關聯的綁定,Screen 退出轉義序列解析模式並觸發綁定。如果累積序列不是具有關聯綁定的任何序列的前綴,則 Screen 退出轉義序列解析模式並丟棄累積序列。所以這裡的 null 設置是“什麼都沒有發生”的複雜形式。

在完成所有這些工作之後,讓我們轉向

列表 C:從任何對 ( a , b )(其中aAbB)到一個明確描述如何在標準美國鍵盤上鍵入相應 GNU 螢幕命令字元的映射,並假設特定終端模擬器

正如我上面所暗示的,特定的終端仿真器在這裡很重要:不同的終端以不同的方式對鍵弦進行編碼,並且某些終端可以以不同的方式進行配置。該映射不對應於一對 ( a , b ):A × B不是一個有趣的集合。大多數鍵弦映射到列印字元(如上所示,擴展A轉義序列(如上所示,擴展B)。換句話說,映射是AB的超集。

不幸的是,許多終端沒有完整記錄如何發送轉義序列。幸運的是,這很少需要。不是從轉義序列到鍵弦,而是從鍵弦到轉義序列。如上所述,這可以使用Ctrl+為每個終端確定。V

一些終端,特別是 xterm,可以配置為以系統的方式對鍵盤進行編碼。有關面向 Emacs 的討論,請參閱使用終端時的鍵綁定問題。不幸的是,這不包括許多終端仿真器使用的 vte 庫,尤其是在 GNOME 世界中。

引用自:https://unix.stackexchange.com/questions/244933