我想在我的C程序中读取箭头按键,并用其他字符串替换它们(立即在终端本身中)。我正在尝试在UNIX终端中实现bash历史记录功能。我写了这段代码。
int main(int argc, char *argv[]) { char c; char str[1024]; int i = 0; while((c = fgetc(stdin)) != '\n'){ if(((int)c) == 27){ c=fgetc(stdin); c=fgetc(stdin); if (c == 'A') { printf("%c[A%c[2K",27, 27); printf("UP"); } } str[i++] = c; } printf("\n"); return 0; }
但是,这不起作用,因为终端等待换行符或EOF将输入缓冲区发送到stdin。因此,我必须按Enter / Return键来分析用户输入。
用户在此回答中提到要使用,system("/bin/stty raw");但这将替换所有默认的终端行为(例如,退格键,删除等)。
system("/bin/stty raw");
因此,如果检测到箭头按键,有什么办法可以直接读取/操作终端输入缓冲区并调整缓冲区本身?
环境-Ubuntu(Linux)
更新1: 是否有一种方法可以改变信号/中断(默认是按Enter键),从而使终端将存储的输入发送到缓冲区?这也可以帮助我实现相同的行为。
最终代码:
我通过检查的输出发现了特定按键的ASCII字符 strace bash
strace bash
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #define ESCAPE '\33' #define BACKSPACE '\177' #define DELETE '~' int main(){ struct termios termios_p; struct termios termios_save; tcgetattr(0, &termios_p); termios_save = termios_p; termios_p.c_lflag &= ~(ICANON|ECHO); tcsetattr(0,TCSANOW, &termios_p); char buff; while(read(0, &buff, 1) >= 0){ if(buff > 0){ if(buff == ESCAPE){ read(0, &buff, 1); read(0, &buff, 1); if(buff == 'A'){ write(2, "up", 2); }else if(buff == 'B'){ write(2, "down", 4); }else if(buff == 'C'){ write(2, "\33[C", 3); }else if(buff == 'D'){ write(2, "\10", 2); } }else if(buff == BACKSPACE){ write(2, "\10\33[1P", 5); }else if(buff == DELETE){ write(2, "\33[1P", 4); }else{ write(2,&buff,1); } // write(2,&buff,1); if(buff == 'q'){ break; } } } tcsetattr(0,TCSANOW, &termios_save); return 0; }
看来您正在寻找这样的东西。
该程序实际上等待用户输入。如果按下向上箭头键,程序将打印“按下箭头键”,然后退出。如果按下了其他任何按钮,它将等待用户完成键入的内容并打印出来,然后退出。
#include <termios.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> int main() { struct termios oldt, newt; char ch, command[20]; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); while(1) { ch = getchar(); if (ch == '\033') { printf("Arrow key\n"); ch=-1; break;} else if(ch == -1) // by default the function returns -1, as it is non blocking { continue; } else { break; } } tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF) { ungetc(ch,stdin);ith putchar(ch); scanf("%s",command); printf("\n%s\n",command); return 1; } return 0; }