要在类UNIX操作系统(如Linux)下从终端获取字符,请从STDIN(文件号0)读取.通常,读取系统调用将阻塞,直到用户按下回车键.这称为规范模式.要在不等待用户按Enter的情况下读取单个字符,必须先禁用规范模式.当然,如果您希望稍后输入行,并且在程序退出之前,则必须重新启用它.
要在Linux上禁用规范模式,请使用ioctl系统调用将IOCTL(IO ControL)发送到STDIN.我假设您知道如何从汇编程序进行Linux系统调用.
ioctl系统调用有三个参数.第一个是将命令发送到(STDIN)的文件,第二个是IOCTL编号,第三个通常是指向数据结构的指针.成功时ioctl返回0,失败时返回负错误代码.
您需要的第一个IOCTL是TCGETS(编号0x5401),它获取termios结构中的当前终端参数.第三个参数是指向termios结构的指针.从内核源代码,termios结构定义为:
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 */ };
其中tcflag_t为32位长,cc_t为一个字节长,NCCS当前定义为19.有关如何方便地为此类结构定义和保留空间的信息,请参阅NASM手册.
所以,一旦你有了当前的termios,你需要清除规范的旗帜.该标志位于c_lflag字段中,带有掩码ICANON(0x00000002).要清除它,请计算c_lflag AND(NOT ICANON).并将结果存储回c_lflag字段.
现在您需要通知内核您对termios结构的更改.使用TCSETS(编号0x5402)ioctl,第三个参数设置termios结构的地址.
如果一切顺利,终端现在处于非规范模式.您可以通过设置规范标志(通过ORing c_lflag与ICANON)并再次调用TCSETS ioctl来恢复规范模式.在退出之前始终恢复规范模式
正如我所说,这并不容易.