POSIX.1定義了一個查詢和操縱終端的標準接口termios,他是一個數據結構和一系列操作這些數據結構的函數,
#include <termios.h>
struct termios
{
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
speed_t c_ispeed; /* input speed */
speed_t c_ospeed; /* output speed */
}
c_iflag用來控制輸入處理選項的,他將影響到終端驅動程序把輸入發送給程序之前是否對其進行處理,以及處理的方式,同樣,c_oflag用來控制輸出的處理。c_cflag決定終端的硬件特性的控制標誌。c_lflag用來決定本地終端的特性,例如輸入時是否回顯等,c_cc包含了特殊字符序列的值,以及他們所代表的操作。c_line表示控制協議。
c_iflag flag constants:
IGNBRK 忽略輸入中的BREAK條件
BRKINT 如果設置了IGNBRK,將在BREAK時產生SIGINT
IGNPAR Ignore framing errors and parity errors.
PARMRK If IGNPAR is not set, prefix a character with a parity error or
framing error with \377 \0. If neither IGNPAR nor PARMRK is
set, read a character with a parity error or framing error as
\0.
INPCK Enable input parity checking.
ISTRIP Strip off eighth bit.
INLCR 將輸入的CR轉化成NL
IGNCR 忽略輸入中的CR
ICRNL Translate carriage return to newline on input (unless IGNCR is
set).
IUCLC (not in POSIX) Map uppercase characters to lowercase on input.
IXON Enable XON/XOFF flow control on output.
IXANY (XSI) Typing any character will restart stopped output. (The
default is to allow just the START character to restart output.)
IXOFF Enable XON/XOFF flow control on input.
IMAXBEL
(not in POSIX) Ring bell when input queue is full. Linux does
not implement this bit, and acts as if it is always set.
c_oflag flag constants defined in POSIX.1:
OLCUC (not in POSIX) Map lowercase characters to uppercase on output.
ONLCR 將輸出中的NL,轉化成CR—NL
OCRNL 將輸出中的CR轉換成NL
ONOCR Don’t output CR at column 0.
ONLRET 不輸出CR
OFILL Send fill characters for a delay, rather than using a timed
delay.
OFDEL (not in POSIX) Fill character is ASCII DEL (0177). If unset,
fill character is ASCII NUL (’\0’). (Not implemented on Linux.)
NLDLY Newline delay mask. Values are NL0 and NL1. [requires
_BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
CRDLY Carriage return delay mask. Values are CR0, CR1, CR2, or CR3.
requires _BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
TABDLY Horizontal tab delay mask. Values are TAB0, TAB1, TAB2, TAB3
(or XTABS). A value of TAB3, that is, XTABS, expands tabs to
spaces (with tab stops every eight columns). [requires
_BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
BSDLY Backspace delay mask. Values are BS0 or BS1. (Has never been
implemented.) [requires _BSD_SOURCE or _SVID_SOURCE or
_XOPEN_SOURCE]
VTDLY Vertical tab delay mask. Values are VT0 or VT1.
FFDLY Form feed delay mask. Values are FF0 or FF1. [requires
_BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
c_cflag flag constants:
CBAUD (not in POSIX) Baud speed mask (4+1 bits). [requires
_BSD_SOURCE or _SVID_SOURCE]
CBAUDEX (not in POSIX) Extra baud speed mask (1 bit), included in CBAUD.
[requires _BSD_SOURCE or _SVID_SOURCE]
(POSIX says that the baud speed is stored in the termios struc-
ture without specifying where precisely, and provides
cfgetispeed() and cfsetispeed() for getting at it. Some systems
use bits selected by CBAUD in c_cflag, other systems use sepa-
rate fields, e.g. sg_ispeed and sg_ospeed.)
CSIZE Character size mask. Values are CS5, CS6, CS7, or CS8.
CSTOPB Set two stop bits, rather than one.
CREAD Enable receiver.
PARENB Enable parity generation on output and parity checking for
input.
PARODD Parity for input and output is odd.
HUPCL 在最後處理結束時,關閉設備並關閉連接
CLOCAL 忽略調制解調器控制線
LOBLK (not in POSIX) Block output from a noncurrent shell layer. For
use by shl (shell layers). (Not implemented on Linux.)
CIBAUD (not in POSIX) Mask for input speeds. The values for the CIBAUD
bits are the same as the values for the CBAUD bits, shifted left
IBSHIFT bits. [requires _BSD_SOURCE or _SVID_SOURCE] (Not
implemented on Linux.)
CRTSCTS (not in POSIX) Enable RTS/CTS (hardware) flow control.
[requires _BSD_SOURCE or _SVID_SOURCE]
c_lflag flag constants:
ISIG When any of the characters INTR, QUIT, SUSP, or DSUSP are
received, generate the corresponding signal.
ICANON 啓用規範模式
XCASE (not in POSIX; not supported under Linux) If ICANON is also set,
terminal is uppercase only. Input is converted to lowercase,
except for characters preceded by \. On output, uppercase char-
acters are preceded by \ and lowercase characters are converted
to uppercase.
ECHO 輸入回顯
ECHOE If ICANON is also set, the ERASE character erases the preceding
input character, and WERASE erases the preceding word.
ECHOK If ICANON is also set, the KILL character erases the current
line.
ECHONL 在規範模式中,即使沒有設置ECHO也回顯NL
ECHOCTL
(not in POSIX) If ECHO is also set, ASCII control signals other
than TAB, NL, START, and STOP are echoed as ^X, where X is the
character with ASCII code 0x40 greater than the control signal.
For example, character 0x08 (BS) is echoed as ^H. [requires
_BSD_SOURCE or _SVID_SOURCE]
ECHOPRT
(not in POSIX) If ICANON and IECHO are also set, characters are
printed as they are being erased. [requires _BSD_SOURCE or
_SVID_SOURCE]
ECHOKE (not in POSIX) If ICANON is also set, KILL is echoed by erasing
each character on the line, as specified by ECHOE and ECHOPRT.
[requires _BSD_SOURCE or _SVID_SOURCE]
DEFECHO (not in POSIX) Echo only when a process is reading. (Not imple-
mented on Linux.)
FLUSHO (not in POSIX; not supported under Linux) Output is being
flushed. This flag is toggled by typing the DISCARD character.
[requires _BSD_SOURCE or _SVID_SOURCE]
NOFLSH Disable flushing the input and output queues when generating the
SIGINT, SIGQUIT and SIGSUSP signals.
TOSTOP Send the SIGTTOU signal to the process group of a background
process which tries to write to its controlling terminal.
PENDIN (not in POSIX; not supported under Linux) All characters in the
input queue are reprinted when the next character is read.
(bash handles typeahead this way.) [requires _BSD_SOURCE or
_SVID_SOURCE]
IEXTEN Enable implementation-defined input processing. This flag, as
well as ICANON must be enabled for the special characters EOL2,
LNEXT, REPRINT, WERASE to be interpreted, and for the IUCLC flag
to be effective.
The c_cc array defines the special control characters.
VINTR (003, ETX, Ctrl-C, or also 0177, DEL, rubout) Interrupt charac-
ter. Send a SIGINT signal. Recognized when ISIG is set, and
then not passed as input.
VQUIT (034, FS, Ctrl-\) Quit character. Send SIGQUIT signal. Recog-
nized when ISIG is set, and then not passed as input.
VERASE (0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) Erase charac-
ter. This erases the previous not-yet-erased character, but does
not erase past EOF or beginning-of-line. Recognized when ICANON
is set, and then not passed as input.
VKILL (025, NAK, Ctrl-U, or Ctrl-X, or also @) Kill character. This
erases the input since the last EOF or beginning-of-line. Rec-
ognized when ICANON is set, and then not passed as input.
VEOF (004, EOT, Ctrl-D) End-of-file character. More precisely: this
character causes the pending tty buffer to be sent to the wait-
ing user program without waiting for end-of-line. If it is the
first character of the line, the read() in the user program
returns 0, which signifies end-of-file. Recognized when ICANON
is set, and then not passed as input.
VMIN Minimum number of characters for non-canonical read.
VEOL (0, NUL) Additional end-of-line character. Recognized when
ICANON is set.
VTIME Timeout in deciseconds for non-canonical read.
VEOL2 (not in POSIX; 0, NUL) Yet another end-of-line character. Rec-
gnized when ICANON is set.
VSWTCH (not in POSIX; not supported under Linux; 0, NUL) Switch charac-
ter. (Used by shl only.)
VSTART (021, DC1, Ctrl-Q) Start character. Restarts output stopped by
the Stop character. Recognized when IXON is set, and then not
passed as input.
VSTOP (023, DC3, Ctrl-S) Stop character. Stop output until Start char-
acter typed. Recognized when IXON is set, and then not passed
as input.
VSUSP (032, SUB, Ctrl-Z) Suspend character. Send SIGTSTP signal. Rec-
ognized when ISIG is set, and then not passed as input.
VDSUSP (not in POSIX; not supported under Linux; 031, EM, Ctrl-Y)
Delayed suspend character: send SIGTSTP signal when the charac-
ter is read by the user program. Recognized when IEXTEN and
ISIG are set, and the system supports job control, and then not
passed as input.
VLNEXT (not in POSIX; 026, SYN, Ctrl-V) Literal next. Quotes the next
input character, depriving it of a possible special meaning.
Recognized when IEXTEN is set, and then not passed as input.
VWERASE
(not in POSIX; 027, ETB, Ctrl-W) Word erase. Recognized when
ICANON and IEXTEN are set, and then not passed as input.
VREPRINT
(not in POSIX; 022, DC2, Ctrl-R) Reprint unread characters.
Recognized when ICANON and IEXTEN are set, and then not passed
as input.
VDISCARD
(not in POSIX; not supported under Linux; 017, SI, Ctrl-O) Tog-
gle: start/stop discarding pending output. Recognized when IEX-
TEN is set, and then not passed as input.
VSTATUS
(not in POSIX; not supported under Linux; status request: 024,
DC4, Ctrl-T).
#include <termios.h>
#include <unistd.h>
int tcgetattr (int fd, struct termios *termios_p);
int tcsetattr (int fd, int optional_actions, const struct termios *termios_p);
int tcsendbreak (int fd, int duration);
int tcdrain (int fd);
int tcflush (int fd, int queue_selector);
int tcflow (int fd, int action);
void cfmakeraw (struct termios *termios_p);
speed_t cfgetispeed (const struct termios *termios_p);
speed_t cfgetospeed (const struct termios *termios_p);
int cfsetispeed (struct termios *termios_p, speed_t speed);
int cfsetospeed (struct termios *termios_p, speed_t speed);
屬性控制
tcgetattr用來查詢和fd相關聯的終端的參數,並將他們存儲到termios_p中,成功返回0,失敗返回-1。
tcsetattr用來設置終端的屬性,其中optional_actions決定了改變什麼時候生效,他的值可以爲:
TCSANOW 立即改變這些屬性值
TCSADRAIN 改變發生在當所有fd上的輸出都已經被髮送到終端以後,當要改變輸出設置時
使用此函數
TCSAFLUSH 改變發生在當所有fd上的輸出都已經被髮送到終端以後,但任何掛起的輸入
將會被丟棄。
速度控制
上面列出的速度控制函數都是成對出現,用來獲取和設置相應的動作,其中要說明的是cfsetospeed的speed參數必須是下面列出的常數中的一個:
B0(關閉連接) B50
B75 B110
B134 B150
B200 B300
B600 B1200
B1800 B2400
B4800 B9600
B19200 B38400
B57600 B115200
B230400
行控制
tcdrain函數將一直保持等待,直到所有的輸出都已經寫入到文件描述符fd指向的文件爲止。
爲了強迫輸入,輸出或者兩者同時刷新,便可以使用tcflush函數,queue_selector用來指定要刷新的數據,他的取值如下:
TCIFLUSH flushes data received but not read.
TCOFLUSH flushes data written but not transmitted.
TCIOFLUSH flushes both data received but not read, and data written but
not transmitted.
實際的流量控制,不管是處於開狀態還是關狀態,都由tcflow來控制,參數action用來控制函數的動作,他的取值如下:
TCOOFF suspends output.
TCOON restarts suspended output.
TCIOFF transmits a STOP character, which stops the terminal device from
transmitting data to the system.
TCION transmits a START character, which starts the terminal device
transmitting data to the system.
進程控制
#include <unistd.h>
pid_t tcgetpgrp(int fd);
int tcsetpgrp(int fd, pid_t pgrp);
函數tcgetpgrp返回fd終端上前臺運行的進程組pgrp_id的進程組標識號
如果有足夠的權限,使用tcsetpgrp可以改變進程組的標識號
使用terminfo
對於每種可能的終端類型,terminfo維護了其終端能力和特性的一個列表,被稱爲capname,capname可以分爲:布爾型,數值型,字符串型。其中,布爾型只能表示是否支持某一特定屬性,數值型用來定義和大小有關的能力,字符串型定義訪問某種特性的轉義序列或者定義當用戶按下任意鍵的動作。
常用的終端能力(詳細的可查詢terminfo(5))
capname type 描述
am b (bool) 具有自動頁邊空白
bce b 使用背景色清除
km b 有META鍵
ul b 下劃線字符加粗
cols i (int) 當前終端列數
lines i 當前終端行數
colors i 支持的顏色數
clear s (strring) 清屏並將光標移動到初始位置
cl s 清除行內容
ed s 清除到屏尾的內容
smcup s 進入光標尋址模式
cup s 移動光標
rmcup s 退出光標尋址模式
bel s 蜂鳴
flash s 閃屏
kf[0-63] s 功能鍵F[0-63]
爲了使用terminfo必須包含curses.h和term.h
使用步驟:
1,初始化terminfo數據結構
2,檢索capname
3,修改capname
4,將修改後的capname輸出到終端
5,其他
6,重複2-5
1,初始化
#include <curses.h>
#include <term.h>
int setupterm(char *term, int fildes, int *errret);
term用來指定終端類型,如果爲NULL,則會讀取環境變量TERM的值,否則,就會使用term所指定的終端類型。所有的輸出都將會發送到由fildes指示的文件或設備中,如果errret不是NULL,1表示成功,0表示在terminfo沒有找到term所指示的終端,-1表示terminfo數據庫沒有找到。返回OK表示調用成功,ERR表示失敗。
2,檢索
int tigetflag(char *capname);
int tigetnum(char *capname);
char *tigetstr(char *capname);
他們分別用來檢索布爾型,數值型,字符串型
tigetflag支持返回TRUE,不支持返回FALSE,如果檢索的不是布爾型,就返回-1;
tigetnum不支持capname返回-1,如果不是數值型,返回-2。
tigetstr返回包含capname的轉義序列,如果不支持capname返回(char *)NULL, 如果不是字符串型返回(char *)-1;
3,修改
在發送控制字符串之前,你必須線構造他,這就是tparm的工作。
char *tparm(char *str, ...);
成功時返回一個被恰當格式化過的字符串,失敗則返回NULL。
4,輸出到終端
int tputs(const char *str, int affcnt, int (*putc)(int));
int putp(const char *str);
putp是將str輸出到標準輸出上,他等價與tputs(str,1,putchar)
tputs將str輸出到setupterm中指定的term和fildes,str必須是一個terminfo字符串變量或者調用taprm或tigetstr的返回值,如果str是與行相關的能力,則affcnt便是將會影響的行數,putc是一個指向putchar風格(一次輸出一個字符)的指針。
#include <stdlib.h>
#include <stdio.h>
#include <term.h>
#include <curses.h>
int main(void)
{
int i;
char *buf;
if (ERR == setupterm(NULL, fileno(stdin), NULL))
{
perror("failed on setupterm\n");
exit(EXIT_FAILURE);
}
i = tigetflag("km");
printf("km = %d\n", i);
i = tigetnum("lines");
printf("lines = %d\n", i);
buf = tigetstr("flash");
printf("bel = \\E%s\n", &buf[1]);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
int main(void)
{
struct termios old, new;
char passwd[32] = {0};
if (-1 == tcgetattr(fileno(stdin), &old)) /*get ols attr.*/
{
perror("failed on tcgetattr\n");
exit(EXIT_FAILURE);
}
new = old;
new.c_lflag &= ~ECHO; /*NO ECHO*/
new.c_lflag |= ECHONL; /*echo nl*/
if (-1 == tcsetattr(fileno(stdin), TCSANOW, &new)) /*set new attr*/
{
perror("failed on tcsetattr\n");
exit(EXIT_FAILURE);
}
if ((-1 == tcgetattr(fileno(stdin), &new))) /*check set*/
{
perror("failure set\n");
exit(EXIT_FAILURE);
}
if (new.c_lflag & ECHO)
{
puts("error on ECHO");
exit(EXIT_FAILURE);
}
if (!new.c_lflag & ECHONL)
{
puts("error on ECHONL");
exit(EXIT_FAILURE);
}
puts("Input passwd:");
fgets(passwd, 31, stdin);
puts(passwd);
tcsetattr(fileno(stdin), TCSANOW, &old); /*reset to old*/
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <termios.h>
void err(const char * str);
static void sig_catch(int sig);
int main(void)
{
int fd = fileno(stdin);
char c;
struct termios old, new;
if (signal(SIGINT, sig_catch) == SIG_ERR
|| signal(SIGQUIT, sig_catch) == SIG_ERR
|| signal(SIGTERM, sig_catch) == SIG_ERR)
err("faile on signal\n");
if (-1 == tcgetattr(fd, &old))
err("failed on tcgetattr\n");
new = old;
new.c_lflag &= ~(ECHO | ICANON | ISIG);
new.c_iflag &= ~(BRKINT | ICRNL);
new.c_oflag &= ~OPOST;
new.c_cc[VTIME] = 0;
new.c_cc[VMIN] = 1;
if (-1 == tcsetattr(fd, TCSAFLUSH, &new))
err("failed on tcsetattr");
puts("Input keys:");
while (1)
{
if (1 != read(fd, &c, 1))
break;
if (0161 == c)
break;
printf("%o\n",c);
}
tcsetattr(fd, TCSANOW, &old);
return 0;
}
static void sig_catch(int sig)
{
printf("Catch : %d\n",sig);
}
void err(const char * str)
{
perror(str);
exit(EXIT_FAILURE);
}
#include <stdio.h>
#include <stdlib.h>
#include <term.h>
#include <curses.h>
void moveto(int y, int x);
void clrscr(void);
void err(const char * str);
int main(void)
{
int i;
if (-1 == setupterm(NULL, fileno(stdout), NULL))
err("setupinfo");
printf("test...\n");
getchar();
clrscr();
moveto(3, 3);
i = tigetflag("km");
printf("km = %d\n", i);
printf("lines : %d cols : %d\n",
tigetnum("lines"), tigetnum("cols"));
moveto(10, 10);
printf("X");
moveto(1, 1);
printf("x");
return 0;
}
void moveto(int y, int x)
{
char * buf = tigetstr("cup");
putp(tparm(buf, y, x));
}
void clrscr(void)
{
char *buf = tigetstr("clear");
putp(buf);
}
void err(const char *str)
{
printf("Error on %s\n", str);
exit(EXIT_FAILURE);
}