2013-11-29 68 views
5

read-lineread-char都需要您在輸入內容後按Enter鍵。 Common Lisp中是否有任何機制允許程序在立即按下任何單個字符時繼續運行,而不需要按Enter鍵的額外步驟?讀取字符時無需按下Enter按鈕

我正在嘗試爲程序構建一個快速,動態的文本輸入界面,以便用戶可以快速瀏覽並按與屏幕菜單對應的數字或字母執行不同的操作。所有額外按Enter鍵嚴重中斷工作流程。這也類似於提示中的「y/n」型詢問,只需按「y」或「n」就足夠了。

我正在使用SBCL,如果這有所作爲。也許這是特定於實現的,因爲我在this page上嘗試了兩個示例,但它不起作用(我仍然需要按Enter鍵);這裏是第一個:

(defun y-or-n() 
(clear-input *standard-input*) 
(loop as dum = (format t "Y or N for yes or no: ") 
    as c = (read-char) 
    as q = (and (not (equal C#\n)) (not (equal C#\y))) 
    when q do (format t "~%Need Y or N~%") 
    unless q return (if (equal C#\y) 'yes 'no))) 

回答

8

read-char不需要按Enter鍵。例如,

CL-USER> (with-input-from-string (x "hello") 
      (print (read-char x))) 

#\h 

同樣,如果你在命令行中發送一些輸入 SBCL,將不換行寫着:

$ echo -n hello | sbcl --eval "(print (read-char))" 
… 
#\h 

閱讀和打印#\h後,SBCL看到ello

* 
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD 
                "initial thread" RUNNING 
                {1002979011}>: 
    The variable ELLO is unbound. 

我認爲這是足以證實它不是read-char需要換行,而是說緩衝的輸入是問題所在。我認爲這是在2008年的comp.lang.lisp線程中描述的相同問題(或非問題):Re: A problem with read-char。用戶問:

是否有可能使讀取字符表現得像С殘培交互式流(標準輸入)工作 時?在SBCL中,read-char希望 「輸入」鍵從REPL懸空,在C中,getchar在用戶按下鍵盤後立即返回 。可能有可能運行代碼 ,使用read-char和直接控制檯訪問,除了REPL?

有四個響應(請參閱thread index以獲得所有這些響應)。這些解釋爲什麼這種行爲是觀察到(即,Lisp進程沒有從終端獲取原始輸入,而是緩衝輸入)。 Pascal Bourguignon described the problem和方式與CLISP來處理這個(但不提供那麼多的幫助,除了平時的好建議)關於解決此工作在SBCL:

不同的是,詛咒把終端原始模式能夠 一次接收一個鍵盤上的字符,而不是 使終端處於熟化模式,其中unix驅動程序緩衝行 行和處理退格鍵等等。

...

現在,我不知道SBCL,(檢查SBCL的手冊)。我只有 CLISP的實現說明加載到我的溼件中。在CLISP中, 可以使用EXT:WITH-KEYBOARD宏(而SCREEN軟件包提供了curses的基本輸出功能 )。

Rob Warnock's response列入CMUCL一些解決方法的代碼,可能會或可能不會進行SBCL工作:

我曾經寫了CMUCL以下爲想 能夠輸入一個字符響應的應用程序無需 提示搞亂終端屏幕:

(defun read-char-no-echo-cbreak (&optional (stream *query-io*)) 
    (with-alien ((old (struct termios)) 
       (new (struct termios))) 
    (let ((e0 (unix-tcgetattr 0 old)) 
      (e1 (unix-tcgetattr 0 new)) 
      (bits (logior tty-icanon tty-echo tty-echoe 
         tty-echok tty-echonl))) 
     (declare (ignorable e0 e1)) ;[probably should test for error here] 
     (unwind-protect 
      (progn 
      (setf (slot new 'c-lflag) (logandc2 (slot old 'c-lflag) bits)) 
      (setf (deref (slot new 'c-cc) vmin) 1) 
      (setf (deref (slot new 'c-cc) vtime) 0) 
      (unix-tcsetattr 0 tcsadrain new) 
      (read-char stream)) 
     (unix-tcsetattr 0 tcsadrain old))))) 

SBCL可能已經大大從CMUCL在這方面的分歧,但 類似的東西應該可以和SBCL一起使用。通過查看 SB-UNIX或者也許是SB-POSIX包開始......

User vippstar's response提供一個鏈接,既然你想要做的事是什麼可能是最便攜的解決方案

那可能不能移植到微控制器(但效果更好),可使用非標準庫 ,例如CL-ncurses

+2

非常好,就是當我看到問題時我在想什麼。現在我不必寫答案。 – Vatine

0

我發現cl-charms,這似乎是被遺棄的cl-curses的一個分支。但是,包含的示例程序charms-paint使用100%的CPU來運行平凡的繪畫應用程序。問題似乎是主循環忙等待輸入。