设置控制台这样一个软件可能会拦截所有键入的字符的方法是将终端设置为 RAW 模式。这种方式可能出现的问题是所有不在 ASCII 0-255 空间中的键,例如 è、ì、à 将从控制台作为字节序列接收,并且所有函数和包含光标和退格的控制键不会完成任何动作,一些代码如CR、LF和一些ANSI序列可能会在从输入通道读取并在输出通道上重写时完成动作。
要将终端设置为原始模式,您必须使用函数cfmakeraw,然后使用函数tcsetattr。
下面的代码实现了一个简单但不是很好实现的终端,无论如何我认为这段代码是一个很好的起点。无论如何,代码流和错误控制至少必须安排得更好。
当键入一个键时,代码会写入所有进入控制台的 ASCII 字符序列。所有值小于 32 或大于 126 的字符都将写入[HEX-CODE]
I.E.在控制台点击Esc会写成[1B],Ctrl+C的代码会写成[03], F1 将是[1B]OP,F11 将是[1B][23~,Enter 将是[0D]。
如果您按下 Ctrl+X,[18] 将被写入并且程序停止,但正如您在代码中看到的那样,此行为受 SW 控制。
代码如下:
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions (struct termios)
#include <sys/ioctl.h> // Used for TCGETS2, which is required for custom baud rates
#include <sys/select.h> // might be used to manage select
int setAttr(int ch, int resetToOld);
#define IN 0
#define OUT 1
typedef struct TermCap
{
int fd;
struct termios oldTermios;
struct termios newTermios;
// fd_set fds; // might be used to manage select
} TermCap;
TermCap m_termCap[2];
int main()
{
int i,ex=0;
char msg;
char buff[20];
m_termCap[IN].fd=STDIN_FILENO;
m_termCap[OUT].fd=STDOUT_FILENO;
// Gets STDIN config and set raw config
setAttr(IN,0);
// Gets STDOUT config and set raw config
setAttr(OUT,0);
// Console loop ... the console terminates when ^X is intercepted.
do {
do {
i=read(m_termCap[IN].fd,&msg,1);
if (i>0){
if (msg<32 || msg>126) {
sprintf(buff,"[%02X]",(unsigned char)msg);
write(m_termCap[OUT].fd,buff,4);
if (msg==24)
ex=1;
}else{
write(m_termCap[OUT].fd,&msg,i);
}
}
usleep(10000); // a minimal delay of 10 millisec
} while(i>0 && !ex);
} while(!ex);
// Reset console to initial state.
setAttr(IN,1);
setAttr(OUT,1);
printf("\r\n\nThe end!");
return 0;
}
int setAttr(int ch, int resetToOld)
{
int retVal=0;
int i;
if (!resetToOld) {
// Read old term config
i=tcgetattr(m_termCap[ch].fd, &m_termCap[ch].oldTermios);
if (i==-1) {
return 1;
}
}
m_termCap[ch].newTermios = m_termCap[ch].oldTermios;
if (!resetToOld) {
// Terminal in raw mode
cfmakeraw(&m_termCap[ch].newTermios);
}
i=tcsetattr(m_termCap[ch].fd, TCSANOW, &m_termCap[ch].newTermios);
if (i==-1) {
retVal = 2;
}
return retVal;
}