ncurses и блокировка стандартного ввода

У меня есть stdin в наборе select(), и я хочу брать строку из stdin всякий раз, когда пользователь вводит ее и нажимает Enter.

Но select запускает stdin как готовый к чтению до нажатия Enter и, в редких случаях, до того, как что-либо вообще будет набрано. Моя программа зависает на getstr(), пока я не нажму Enter.

Я попытался установить nocbreak(), и это действительно прекрасно, за исключением того, что ничего не отображается на экране, поэтому я не вижу, что печатаю. И установка echo() этого не меняет.

Я также пытался использовать timeout(0), но результаты были еще более сумасшедшими и не работали.


person graw    schedule 10.11.2009    source источник
comment
Ну, в основном мне интересно, ДОЛЖЕН ли я использовать потоки сейчас из-за ncurses, потому что я могу это сделать, но это не так элегантно, как просто использовать select. Единственный другой вариант, который я могу придумать, - это прочитать каждый символ и попытаться выполнить их радикальную обработку. Кажется, это может быть еще грязнее.   -  person graw    schedule 10.11.2009


Ответы (1)


Что вам нужно сделать, так это проверить, доступен ли символ с помощью функции getch(). Если вы используете его в режиме без задержки, метод не будет блокироваться. Затем вам нужно поглощать символы, пока не встретите '\n', добавляя каждый символ к результирующей строке по мере продвижения.

В качестве альтернативы — и метод, который я использую, — использовать библиотеку GNU readline. Он поддерживает неблокирующее поведение, но документация по этому разделу не так уж отлично.

Здесь приведен небольшой пример, который вы можете использовать. Он имеет цикл выбора и использует библиотеку чтения GNU:

#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <stdbool.h>

int quit = false;

void rl_cb(char* line)
{
    if (NULL==line) {
        quit = true;
        return;
    }

    if(strlen(line) > 0) add_history(line);

    printf("You typed:\n%s\n", line);
    free(line);
}

int main()
{
    struct timeval to;
    const char *prompt = "# ";

    rl_callback_handler_install(prompt, (rl_vcpfunc_t*) &rl_cb);

    to.tv_sec = 0;
    to.tv_usec = 10000;

    while(1){
        if (quit) break;
        select(1, NULL, NULL, NULL, &to);
        rl_callback_read_char();
    };
    rl_callback_handler_remove();

    return 0;
}

Скомпилировать с:

gcc -Wall rl.c -lreadline
person Johan    schedule 10.11.2009
comment
Спасибо. Я попытался использовать решение readline, оно выглядит красиво, но при одновременном использовании проклятий оно по-прежнему не воспроизводится должным образом. Вероятно, они не предназначены для совместного использования. Я решил просто использовать getch() и поддерживать внутренний буфер строки. Это удивительно легко. - person graw; 10.11.2009