如何在没有回车的情况下执行按键对应的选项? (C 编程)

How to execute the key-corresponding option without an Enter? (C programming)

我正在尝试用 C 编写一个“更多”(就像 Linux 中的“更多”指令)程序。 按“q”时退出,按“”时再显示一页。 但每次我必须在命令后按 Enter 键。 我尝试使用 setbuf() 和 setvbuf() 但它没有 work.Why?我该怎么办?

FILE *fp_tty; //read from keyboard
fp_tty = fopen("/dev/tty", "r");
setbuf(fp_tty, NULL);
see_more(fp_tty);
......
int see_more(FILE *cmd) {
    int c;
    printf("3[7m more? 3[m"); 
    while ((c = getc(cmd)) != EOF) {
        if (c == 'q') {
            return 0; //quit
        }
        if (c == ' ') {
            return PAGELEN; //next page
        }
        if (c == '\n') {
            return 1; //1 line
        }
    }
    return 0;
}

正如@rici 在评论中指出的那样,termios 可以帮助将终端切换到非规范模式。

在您的情况下,您可以使用以下方式处理这些键:

#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#define KEY_ESCAPE  0x001b
#define KEY_ENTER   0x000a

static struct termios term, oterm;

static int getch(void);
static int kbhit(void);
static int kbesc(void);
static int kbget(void);

static int getch(void)
{
    int c = 0;

    tcgetattr(0, &oterm);
    memcpy(&term, &oterm, sizeof(term));
    term.c_lflag &= ~(ICANON | ECHO);
    term.c_cc[VMIN] = 1;
    term.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &term);
    c = getchar();
    tcsetattr(0, TCSANOW, &oterm);
    return c;
}

static int kbhit(void)
{
    int c = 0;

    tcgetattr(0, &oterm);
    memcpy(&term, &oterm, sizeof(term));
    term.c_lflag &= ~(ICANON | ECHO);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;
    tcsetattr(0, TCSANOW, &term);
    c = getchar();
    tcsetattr(0, TCSANOW, &oterm);
    if (c != -1) ungetc(c, stdin);
    return ((c != -1) ? 1 : 0);
}

static int kbesc(void)
{
    int c;

    if (!kbhit()) return KEY_ESCAPE;
    c = getch();
    while (kbhit()) getch();
    return c;
}

static int kbget(void)
{
    int c;

    c = getch();
    return (c == KEY_ESCAPE) ? kbesc() : c;
}

int main(void)
{
    int c;

    while (1) {
        c = kbget();
        if (c == 'q')
        {
            return 0; //quit
        }
        if (c == ' ') {
            return PAGELEN; //next page
        }
        if (c == '\n') {
            return 1; //1 line
        }
    }
    return 0;
}

Linux 共享大多数 Unix 系统的 tty 规则。当设备被视为 终端输入 时,这里意味着接收来自人类的按键的东西,默认情况下输入是面向行的。基本原理是允许用户按错键,取消它,最后按正确的键。在这种情况下,tty 驱动程序会处理修复并仅将最终字符串呈现给应用程序。

这对于面向行的应用程序来说工作得很好,但对于像 emacs 或 vi 这样的纯屏幕应用程序来说是愚蠢的(是的,它们也是 70 年代的......),所以 tty 驱动程序可以在原始模式下设置为立即将任何字符传递给应用程序(存在其他选项......)。 curses 库在幕后使用的是能够立即对任何按键做出反应。

TL/DR:您必须将 tty 驱动程序置于原始模式才能立即处理字符。详细信息在 tcflush 手册页上。