曲径通幽论坛

 找回密码
 立即注册
搜索
12
返回列表 发新帖
楼主: beyes
打印 上一主题 下一主题

终端接口(Terminal interface)

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
11#
 楼主| 发表于 2009-3-7 11:47:25 | 只看该作者

从命令提示符对终端进行设置

你也可以用 stty 命令从命令提示符那里直接设置终端模式.

设置一个终端工作模式,比如你想在你的脚本里可以执行“对单个字符的读取”,你需要关闭掉标准模式并设置 min 为 1 以及 time 为 0.
如下所示命令:
stty -icanon min 1 time 0

现在这个终端已经设置为对字符立即读的模式,可以试图运行一下 http://www.groad.net/bbs/read.php?tid=620 中的 menu-1.exe 这个程序.运行效果如下:
[root@localhost ~]# stty -icanon min 1 time 0
[root@localhost ~]# cd C
[root@localhost C]# ./menu-1.exe
Choice: Please select an cation
a - add new record
d - delete record
q - quit
aYou have chosen: a   #这里,在敲入 a 时,程序马上显示出 You have chosen: a 而不需要输入回车
Choice: Please select an cation
a - add new record
d - delete record
q - quit
dYou have chosen: d
Choice: Please select an cation
a - add new record
d - delete record
q - quit
注意的是,在桌面系统中,如用 ctrl+shift+T 新建立一个终端窗口,那么在这个新的终端窗口里再执行程序则还是以原来的配置状态(需要回车)执行,也就是说这些设置只对当前的窗口有效。

那再把终端模式恢复回来看看(之前已经用 stty save_stty 命令做过备份):
[root@localhost C]# stty $(cat ../save_stty)
[root@localhost C]# ./menu-1.exe
Choice: Please select an cation
a - add new record
d - delete record
q - quit
a     #这里,输入 a 后需要再输入回车才可以继续运行程序
You have chosen: a
Choice: Please select an cation
a - add new record
d - delete record
q - quit

又比如,在一个提示输入口令的程序,可以设置关闭掉输入口令回显,如执行以下命令:
stty -echo
使用完毕后,可以用下面的命令恢复之:
stty echo   #可见,有个 - 号就是关闭,没有 - 号就恢复

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
12#
 楼主| 发表于 2009-3-7 15:02:08 | 只看该作者

终端的速度(Terminal speed)

termios 提供的最后一个功能是对线速度进行操控。termios 结构体中没有为终端速度做定义的成员。它由函数调用来进行设置。输入和输出是分开处理的。

四个函数原型
#include <termios.h>
speed_t cfgetispeed(const struct termios *);
speed_t cfgetospeed(const struct termios *);
int cfsetispeed(struct termios *, speed_t speed);
int cfsetospeed(struct termios *, speed_t speed);

注意:这些函数是对 termios 结构进行操作的,并不是直接作用于通讯端口。这意味着要想设置一个新的速度,就必须先用 tcgetattr() 函数读出当前的设置值,用上面四个函数中其中一个来设置速度,然后用 tcsetattr() 函数写回 termios 结构。只有在 tcsetattr() 函数结束之后,线速度才会改变。

上面4个函数可以为速度设置各种各样的值,但一下几个最为重要:
B0:挂起终端
B1200:1200 波特率
B2400:2400 波特率
B9600:9600 波特率
B19200:19200 波特率
B38400:38400 波特率

有关标准,没有为超过 38400 波特率的速度定义,也没有支持串行口工作大于此速度的标准方法。

一些系统,包括 linux,为了可以选择更快的速度,还定义了 B57600, B115200, B230400。如果现在正在使用的是早期版本的 linux,里面没有对这些函数进行定义,你可以使用 setserial 命令获得非标准的速度--57600 和 115200。在这种情况下,只有当选择 48400 时才能使用这些非标准速度。这些方法都不具备可移植性,所以在使用的时候要很小心。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
13#
 楼主| 发表于 2009-3-7 16:22:37 | 只看该作者

其它功能函数

在控制终端方面还有几个函数。这些函数直接对文件描述符进行操作,不需要读写 termios 结构,定义如下:
#include <termios.h>
int tcdrain(int fd);
int tcflow(int fd, int flowtype);
int tcflush(int fd, int in_out_selector);

函数有以下几点功能

tcdrain 让调用程序等待直到队列输出全部发送完毕

tcflow 用来挂起或重启输出

tcflush 用来清空(flush)输入,输出或者两者

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
14#
 楼主| 发表于 2009-3-7 22:59:33 | 只看该作者

用 termios 来控制密码输入

测试程序
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

#define PASSWORD_LEN 8

int main()
{
        struct termios initialrsettings, newrsettings; /*声明两个 termios 型数组*/
        char password[PASSWORD_LEN + 1]; /*密码存储数组*/

        tcgetattr(fileno(stdin), &initialrsettings); /*得到相应终端控制参数*/

        newrsettings = initialrsettings; /*initialrsettings为备份,newrsetting为需更改的参数*/

        newrsettings.c_lflag &= ~ECHO; /*屏蔽回显*/

        printf("Enter password: ");

        if(tcsetattr(fileno(stdin), TCSAFLUSH, &newrsettings) != 0) {
                fprintf(stderr, "Could not set attributes\\n");
        }
        else {
                fgets(password, PASSWORD_LEN, stdin);
                tcsetattr(fileno(stdin), TCSANOW, &initialrsettings); /*恢复*/
                fprintf(stdout, "\\nYou entered %s\\n", password);
        }

        exit(0);
}
运行及输出
[root@localhost C]# ./password.exe
Enter password:         #这里输入密码不回显
You entered love

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
15#
 楼主| 发表于 2009-3-8 17:09:45 | 只看该作者

菜单-4(终端控制示例)

/*程序功能:读取每一个字符*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <termios.h>

char *menu[] = {
        "a - add new record",
        "d - delete record",
        "q - quit",
        NULL,
};

int getchoice(char *greet, char *choices[], FILE *in, FILE *out);

int main()
{
        int choice = 0;
        FILE *input;
        FILE *output;
        struct termios initial_settings, new_settings;

        if(!isatty(fileno(stdout))) {
                fprintf(stderr, "You are not a terminal, OK.\\n");
        }

        input = fopen("/dev/tty", "r");
        output = fopen("/dev/tty", "w");
        if(!input || !output) {
                fprintf(stderr, "Unable to open /dev/tty\\n");
                exit(1);
        }

        /*进行终端各个参数的设置*/

        /*获取与标准输入相关联的终端控制属性*/
        tcgetattr(fileno(input), &initial_settings);

        new_settings = initial_settings; /*转存*/
        new_settings.c_lflag &= ~ICANON; /*非标准模式*/
        new_settings.c_lflag &= ~ECHO;  /*不回显*/
        new_settings.c_cc[VMIN] = 1;    /*读到1个字符时就返回*/
        new_settings.c_cc[VTIME] = 0;   /*不设置时间影响*/
        new_settings.c_lflag &= ~ISIG;  /*终端不响应信号*/

        if(tcsetattr(fileno(input), TCSANOW, &new_settings) != 0) {
                fprintf(stderr, "could not set attributes\\n");
        }

        do {
                choice = getchoice("Please select an action", menu, input, output);
                printf("You have chosen: %c\\n", choice);
        } while(choice != 'q');

        tcsetattr(fileno(input), TCSANOW, &initial_settings);
        exit(0);
}

int getchoice(char *greet, char *choices[], FILE *in, FILE *out)
{
        int chosen = 0;
        int selected;
        char **option;

        do {
                fprintf(out, "choice: %s\\n", greet);
                option = choices;
                while(*option) {                    /*打印menu菜单*/
                        fprintf(stdout, "%s\\n", *option);
                        option++;
                }

                do {
                        selected = fgetc(in); /*读取一个字符,遇到回车或换行则继续读取*/
                } while(selected == '\\n' || selected == '\\r');
                option = choices;
                while(*option) { /*查询输入的字符和menu中的首字符是否一样*/
                        if(selected == *option[0]) {
                                chosen = 1;
                                break;
                        }
                        option++;
                }
                if(!chosen) { /*错误选择*/
                        fprintf(out, "Incorrect choice, select again\\n");
                }
                } while(!chosen); /*错误选择则需重新输入*/

                return selected; /*输入正确返回选择结果*/
}
运行及输出
[root@localhost C]# ./password-2.exe
choice: Please select an action
a - add new record
d - delete record
q - quit
You have chosen: a  #每次输入都会理解响应
choice: Please select an action
a - add new record
d - delete record
q - quit
You have chosen: d
choice: Please select an action #这里按下 Ctrl+C 测试,结果程序并不相应信号,这是因为程序中的 ~ISIG 的缘故
a - add new record
d - delete record
q - quit
Incorrect choice, select again
choice: Please select an action
a - add new record
d - delete record
q - quit
You have chosen: q
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-6-17 16:26 , Processed in 0.085550 second(s), 19 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表