ncurses 文字模式下的特殊效果與遊標控制


curses 是一個建構於 termcap/terminfo 之上的通用程式庫; ncurses 是 curses 的改良版本. 喜歡儘量避免使用額外程式庫的讀者, 請先參考 "反樸歸真: 文字模式下的程式設計", 或許你要的功能根本不需要 curses 就可以完成.
  1. 基本使用方式:
    1. 手冊: C 程式設計師請見 ncurses(3); perl 程式設計師還要參考 perldoc Curses
    2. 在 perl 程式最面, 要加一句 use curses; 在 C 程式最前面, 要 #include <ncurses/ncurses.h> 並且在連結時要加 -lncurses
    3. 所有使用 ncurses 的程式, 一開始都要 initscr. 這會設定 ncurses 程式庫的初始狀態, 並且把程式執行之前的螢幕存起來.
    4. 所有使用 ncurses 的程式, 結束時都要 endwin. 這會讓 ncurses 程式庫做一些撿場的動作, 例如把螢幕恢復成程式執行之前的狀態.
    5. 為了提高執行效率, ncurses 中的大部分副程式所製造的效果, 都不是馬上會顯現出來的, 而是等到程式設計師呼叫 refresh 時才把先前所有指定的效果一次顯現出來. 但是輸出入選項設定不在此限, 見 curs_inopts(3) 與 curs_outopts(3).
    6. perl 範例C 範例 注意螢幕並非馬上清除, 而是等呼叫 refresh 之後才清除.
  2. 詢問螢幕大小: getmaxyx (C 程式設計師注意: 這是 macro, 不是一般函數, 所以不必用 '&')
  3. 對使用者按鍵立即做反應:
    1. cbreak 可讓終端機進入 "立即反應狀態": 使用者只要敲一個鍵 (而不必按 Enter 鍵) 程式立即可以看到該字元 (透過 getch). 另一方面, noecho 可避免終端機當下就印出使用者敲進去的鍵, 而讓程式設計師自行安排在其他地方或時間才印出來 (甚或不印或印其他字串). 見 perl 範例C 範例.
    2. 如果你在執行上述範例程式時敲入方向鍵或功能鍵, 會發覺這類鍵每敲一次會讓 getch 以為使用者敲了好幾個鍵. 你的程式想要偵測這些鍵時, 是否邏輯就必須變得很麻煩了呢? 用 keypad 叫 ncurses 替你做前置處理. 見 perl 範例C 範例.
    3. 可以一邊計算一邊看看使用者有沒有按鍵盤嗎? 用 nodelay 見 perl 範例C 範例.
  4. 先前直接送控制碼的效果, 如何用 ncurses 製造? 見 perl 範例C 範例. (注意: 環境變數 TERM 必須設定成 ansi 或 xterm-color 才會有顏色.) 測試環境: 在 RedHat 6.0 + CLE 0.8 下, 使用以下各種 terminals: xterm, cxterm, rxvt, crxvt, linux console; 環境變數 TERM 設定成以下各種值: ansi, xterm, xterm-color, vt100, vt525, linux. 最好的結果為 crxvt 與 TERM=ansi 的組合.
  5. C 版本的 ncurses 程式庫還可以控制滑鼠, 不過目前支援的終端機好像不多, 我只在 X Window 下成功地試出來: xterm, rxvt, cxterm 都可以; crxvt 不行 (環境變數 TERM 設定成 xterm). 見 C 範例
  6. 範例: 用 perl 寫的象棋程式

Java Notes

可能因為鮮少 java 研發者對文字模式的程式設計有興趣, ncurses 函式庫在 java 底下並不流行。 jcurses 使用了 ncurses 函式庫; 但它為 java 語言所提供的介面與 ncurses 其實已經完全不像。 在純粹物件導向的環境下, 要做一些簡單的事情 (例如移動遊標) 反而變得很麻煩。

不過我還是下載了 0.9.5 版 for linux, 在 mandrake 10.1 底下試用。 README 檔裡面提到: 除了將兩個最重要的 .so 與 .jar 分別放入適當位置之外, 兩者必須在同一目錄!。 我用 kaffe 1.0.7 試半天試不出來, 最後找到 這篇回信, 根據建議升級至 1.1.4 版, 果然就可以了。 以下是測試步驟:

  1. 下載並解開 jcurses-linux-0.9.5.tar.gz
  2. 一切都尚未設定時, 直接在 classes/ 目錄底下就可以執行 java jcurses/tests/Test
  3. 將 jcurses.jar 及 libjcurses.so 複製到 /usr/lib/kaffe/lib 底下
  4. 這裡 剪下並存成 JcursesTest.java
  5. 然後就可以像一般的 java 程式一樣, 設定路徑 export CLASSPATH=/usr/lib/kaffe/lib/jcurses.jar:. 編譯 javac JcursesTest.java 執行 java JcursesTest

參考資料

  1. Writing Programs with NCURSES