如何在C中正确读取stdin?

时间:2017-03-16 00:52:53

标签: c stdin ncurses

我想在C中编写类似sgtpep/pmenu的应用程序。

然后我开始查看ncurses库。我的第一次尝试是能够选择菜单。例如当我ls | ./a.out时,它应该能够显示所有文件,并突出显示第一个文件,当我按 UP DOWN 时,它将更改相应地突出显示不同的项目。

完整代码为here

该程序没有收到任何按键。循环内的mvprintw(n+1, 0, "%d\n", ch);始终打印-1

然后我删除不相关的代码,并得到最小的例子。

#include <stdio.h>

char buf[100];

int main(int argc, char **argv) {
    int ch;

    while (fgets(buf, sizeof(buf), stdin)) puts(buf);

    ch = getch();
    printf("%d\n", ch);
    ch = getch();
    printf("%d\n", ch);
    ch = getch();
    printf("%d\n", ch);
    ch = getch();
    printf("%d\n", ch);

    return 0;
}

ch始终为-1。我怀疑stdin不干净,所以我在fflush(stdin)之后使用fgets,但结果相同。

那么从stdin读取的正确方法是什么?

UPD1

#include <stdio.h>

char buf[100];

int main(int argc, char **argv) {
    int ch;

    while (fgets(buf, sizeof(buf), stdin)) puts(buf);

    fflush(stdin);

    ch = getchar();
    printf("%d\n", ch);
    ch = getchar();
    printf("%d\n", ch);
    ch = getchar();
    printf("%d\n", ch);
    ch = getchar();
    printf("%d\n", ch);

    return 0;
}

我修改了该程序,因此它与ncurses不再相关,但在运行ls | ./a.out时,ch会一直显示-1

UPD2

使用newterm重定向inout

FILE *fd = fopen("/dev/tty", "r+");
set_term(newterm(NULL, fd, fd)); // instead of initscr()
noecho();
cbreak();
keypad(stdscr, TRUE);

print_menu(cur, n);

while (true) {
    ch = getch();

    if (ch == KEY_UP || ch == 'k') --cur;
    else if (ch == KEY_DOWN || ch == 'j') ++cur;

    cur = (cur + n) % n;

    print_menu(cur, n);
}

endwin();

2 个答案:

答案 0 :(得分:1)

如果您要以这种方式从 stdin 切换到curses,则必须打开终端设备,例如,当您阅读完标准后,/dev/tty输入。打开终端后,可以使用newterm初始化curses(其中包含与initscr不同的输入/输出流参数。)

例如,请参阅ncurses test-programdialog

答案 1 :(得分:0)

curses是stdin的替代品。

C模型是用户在控制台中编写一行,这为他提供了行编辑功能。他可以退格并使用箭头键在线上移动,直到他对它感到满意为止。然后他按下回车,程序得到整行。程序然后处理它,通常会提示下一行。

curses接管键盘以便它可以用作键盘 - 你可以有一个小的太空入侵者游戏,“z”表示“左”,“x”表示“右”。因此,您不应该同时尝试从stdin读取,您将获得字符,但是curses系统将以奇怪的方式与它们进行交互。通过诅咒独家阅读。

在上一个程序中,您读取的输入最多为EOF。因此,后续输入是EOF。