2010-11-09 34 views
10

是否可以通過跨平臺的方式來處理C或OCaml程序中的退格鍵和箭頭鍵?使用stdin識別箭頭鍵

實際上OCaml解決方案將不勝感激,但許多標準的unix函數都直接封裝到相應的API調用中,因此在移植C解決方案時應該沒有問題。

我將要實現的是捕獲箭頭鍵以覆蓋它在shell中的行爲(通過重排最後一行或像這樣的操作)。我認爲這個東西落在實際的程序之前,它不是由代碼本身處理,所以我不知道它是否可能。

的程序編譯無論是在Linux,OS X和Windows(在Cygwin上),所以我想這樣做對所有平臺..

回答

8

我最近做了一些非常相似的事情(雖然我的代碼只是Linux)。您必須將stdin設置爲非規範模式才能讀取箭頭按鍵。這應該適用於OS X和Linux,並且可能適用於Cygwin,儘管我無法確定。

open Unix 
let terminfo = tcgetattr stdin in 
    let newterminfo = {terminfo with c_icanon = false; c_vmin = 0; c_vtime = 0} in 
    at_exit (fun _ -> tcsetattr tsdin TCSAFLUSH terminfo); (* reset stdin when you quit*) 
    tcsetattr stdin TCSAFLUSH newterminfo; 

當規範模式關閉時,您不需要等待換行符以便從標準輸入讀取。 c_vmin表示返回之前要讀取的最少字符數(您可能希望能夠一次讀取一個字符),c_vtime是最大讀取等待時間(以0.1s爲單位)。

你也可能需要設置c_echo爲false,這樣的箭頭按鍵被打印到終端(但你必須手動打印一切。

大多數終端代表箭頭使用ANSI escape sequences按鍵。如果您運行cat不帶任何參數,並開始打方向鍵就可以看到使用的轉義序列。他們是典型的

up - "\027[A" 
down - "\027[B" 
left - "\027[D" 
right - "\027[C" 

其中「\ 027」是esc

ASCII值
+0

我幾乎可以做到這一點,但我應該如何管理角色的手動迴應?我問這個是因爲stdin然後被轉發到一個解析器,該解析器逐行解析並解釋它。我應該放在中間並打印出每個字符?但是當用戶按下UP鍵時,它應該將已經打印出來的字符替換爲不同的東西。 – Jack 2010-11-12 14:09:15

+0

重新閱讀您的問題後,我認爲使用readline/ledit可能是您最好的選擇。但是如果你想手動執行,那麼你將不得不手動控制分析器的stdin。從stdin讀取,檢查一個up-char轉義序列,直到解析器的標準輸入。我在這裏做類似的東西:https://github.com/aplusbi/reflow/blob/master/reflow.ml在'main'函數中,我正在讀stdin到一個字符串,然後把它寫到一個file_descr 。你可能最終會做同樣的事情,但首先檢查轉義序列。 – 2010-11-12 15:17:30

+0

這些箭頭字符實際上來自ECMA 48在這裏標準化http://man7.org/linux/man-pages/man4/console_codes.4.html您可以看到ECMA 48的哪些控制字符支持Linux:它似乎是向左移動光標5個字符,你可以做\ 027 [5D – aeroson 2016-11-17 09:39:51

5

使用ncurses的提取序列的箭頭鍵功能,再看看對他們來說,當你閱讀標準輸入。取而代之的是使用libedit或readline之類的東西可能更容易,並且讓它處理關鍵操作。

+0

一對夫婦進一步注意到ncurses解決方案:在一個平臺上,它是跨終端的,照顧你的毛髮終端差異。此外,還有適用於Windows的版本,因此您可以在Windows控制檯中擁有編輯功能。 – 2010-11-10 13:58:55

2

支持超出可打印字符行的鍵盤輸入的標準方式是通過ncurses庫,該庫有Ocaml binding。另一個常見的可能性是readline庫(Bash最着名)。

如果您所做的只是逐行讀取輸入內容,但希望用戶擁有體面的行編輯器,則不需要在程序中包含任何支持。相反,只要告訴用戶使用包裝程序,如rlwrap(基於readline)或ledit。這些包裝提供線條版本和歷史記錄,這兩個功能是您列出的要求。我建議你只有在你想要更漂亮的東西的時候才能在你的程序中建立輸入處理,比如當用戶按下標籤時程序特定的完成。

1

Backspace是一個ASCII字符,並將像其他任何字符一樣放置在stdin中。字符轉義序列'\b'是退格字符。

對於光標鍵,這些鍵不與任何控制字符關聯,所以不要在標準輸入流中生成數據。儘管有跨平臺的庫可以抽象出平臺差異,但低層訪問必定與平臺相關。我相信ncurses適用於您提到的所有平臺。

+1

我敢肯定,任何規範模式的終端都不會將退格字符放入標準輸入。文本被緩衝,所以如果你輸入「abcd \ b \ n」,你會在程序中得到「abc \ n」。 – 2010-11-10 17:05:06

+0

@Niki:糟糕,我花了大部分時間編寫連接到啞終端仿真器軟件的嵌入式系統。 – Clifford 2010-11-10 23:20:34