Tuesday, January 10, 2012
[L] termios, curses, Terminal Control
好吧,终于到 terminal 了。那真叫一个纠结,最后还是看完了。。
附上实践:
/*
* =====================================================================================
*
* Filename: menu.c
*
* Description: Reading Each Character,
* Without processing some signal characters even like C-c
* Using Terminal Control
*
* Version: 2.0
* Created: Wednesday, December 28, 2011 11:27:45 HKT
* Revision: none
* Compiler: gcc
*
* Author: Hongchao Deng (fengjingchao), fengjingchao@gmail.com
* Company: Sun Yat-sen University
*
* =====================================================================================
*/
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <term.h>
#include <ncurses.h>
char *menu[] = {
"a - add new record",
"d - delete record" ,
"q - quit",
NULL
};
FILE *output_stream = NULL;
/*
* === FUNCTION ======================================================================
* Name: char_to_terminal
* Description: use output_stream to which the program writes the output.
* Otherwise in the getchoice() function we can use putp();
* =====================================================================================
*/
int
char_to_terminal ( int char_to_write )
{
if (output_stream) putc(char_to_write, output_stream);
return 0;
} /* ----- end of function char_to_terminal ----- */
/*
* === FUNCTION ======================================================================
* Name: getchoice
* Description: get the choice from prompt.
* it will simply discard any invalid input including chars like ^C
* =====================================================================================
*/
int
getchoice ( FILE *input, FILE *output)
{
int choice;
int chosen = 0;
int screenrow = 4, screencol = 10;
char **option;
char *cursor, *clear;
output_stream = output;
setupterm(0,1,0);
cursor = tigetstr("cup");
clear = tigetstr("clear");
tputs(clear, 1, char_to_terminal );
while(!chosen){
tputs(tparm(cursor,screenrow++,screencol), 1, char_to_terminal);
fprintf(output,"Please select an option:\n");
for(option = menu; *option != NULL; option++, screenrow++){
tputs(tparm(cursor,screenrow++,screencol), 1, char_to_terminal);
fprintf(output,"%s\n", *option);
}
for(choice = '\n'; choice == '\n';choice = fgetc(input));
for(option = menu; *option != NULL; option++){
if(choice == *option[0]){
chosen = 1; break;
}
}
if(!chosen) {
tputs(tparm(cursor,screenrow++,screencol), 1, char_to_terminal);
fprintf(output, "Incorrect choice: '%c'\n",choice);
}
}
tputs(clear, 1, char_to_terminal );
return choice;
} /* ----- end of function getchoice ----- */
/*
* === FUNCTION ======================================================================
* Name: main
* Description: main function
* =====================================================================================
*/
int
main ( int argc, char *argv[] )
{
int choice = 0;
FILE *input; /* input-file pointer */
input = fopen( "/dev/tty", "r" );
FILE *output;
output = fopen( "/dev/tty", "w");
if ( input == NULL || output == NULL ) {
fprintf ( stderr, "couldn't open file '%s'; %s\n",
"/dev/tty", strerror(errno) );
exit (EXIT_FAILURE);
}
struct termios initialSetting, newSetting;
tcgetattr(fileno(stdin),&initialSetting);
newSetting = initialSetting;
newSetting.c_lflag &= ~ISIG;
newSetting.c_lflag &= ~ECHO;
newSetting.c_cc[VMIN] = 1;
newSetting.c_cc[VTIME]= 0;
newSetting.c_lflag &= ~ICANON;
if(tcsetattr(fileno(stdin), TCSANOW , &newSetting) != 0)
fprintf(stderr, "Could not set terminal attributes!");
for(choice = 0; choice != 'q';){
choice = getchoice(input, output);
printf("You have chosen %c\n",choice);
sleep(1);
}
tcsetattr(fileno(stdin), TCSANOW , &initialSetting);
if( fclose(input) == EOF || fclose(output) == EOF ) {/* close input file */
fprintf ( stderr, "couldn't close file '%s'; %s\n",
"/dev/tty", strerror(errno) );
exit (EXIT_FAILURE);
}
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */
输出可以当场试,都已经是 terminal 了。。
总结一下:
功能:
1. 能调整光标的行列。
2. 能使得输入输出不显示,操作输入输出怎么读写。
经验:
1. setupterm就直接 setupterm(0,1,0), 不知道第二个参数 (flie descriptor) 干嘛用的。
2. 逃过stdout , 用‘/dev/tty’ .. 但是注意对terminal输出控制的时候不能用putp()了,要用tputs().
3. 其实操作terminal都是一堆字符输过去的,而且不同类型的terminal还有不同的控制方法,所以才有 curses这个库。
4. 父进程会直接将stdin这些copy到子进程里面,就是说如果不回复过来的话,那么terminal就变成那样了。。所以对std 三剑客in,out,err做修改之前一定要保存一份,程序结束后回复。
我也不太懂。。下次弄个牛逼一点的再写份好点的总结。这次算记录。。
Labels:
Linux C
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment