C - Есть ли способ завершить ввод строки с помощью клавиши, отличной от «Enter»? - PullRequest
1 голос
/ 06 апреля 2019

Я работаю над планировщиком назначений для моей школы, код ниже представляет собой сегмент модуля для ввода данных для нового задания и последующей записи этих данных в файл. Поскольку описание назначения может быть длинным абзацем, я решил позволить пользователю перейти к новой строке после нажатия клавиши Enter для простоты ввода. Код, который у меня пока работает, работает по желанию. Однако описание представляет собой одну строку, которая обычно заканчивается клавишей ввода. Можно ли завершить строку другим ключом? Например, клавиша Escape? Если да, то как мне это сделать?

Я думал об использовании клавиши escape «Esc» для завершения ввода строки, но я не уверен, какой код или escape-последовательность для представления ключа.

typedef struct {
    char title[60];
    Time duration;
    Date deadline;
    char descrptn[10000];
} Project;

void setStudioProject() {
    Project newProj;
    FILE *fpProj;

    system("cls");
    printf("-----PROJECT SETUP-----\n\n\n");
    //Prompt for project information
    printf("Title: ");
    fgets(newProj.title, 60, stdin);
    fflush(stdin);
    printf("\n\nDescription: \n");
    printf("(No more than 1000 words)\n");

    //loop of concern
    while (fgets(newProj.descrptn, 10000, stdin)) {
        if (getchar() == '\r') { //Whenever the user presses the enter key
            printf("\n"); //...move to a new line
        }
    }
    fflush(stdin);
    //...
}

Я ожидаю, что строка будет прочитана после нажатия клавиши escape, чтобы продолжить выполнение.

Ответы [ 2 ]

3 голосов
/ 06 апреля 2019

Ввод по умолчанию буферизован.Вы можете использовать ncurses (что не делает этого) или вручную отключить:

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
...
//ensure stdin is a terminal before modifying
if (isatty(STDIN_FILENO)) {
    struct termios t;
    tcgetattr(STDOUT_FILENO, &t);//get current params

    int linebufd = ((t.c_lflag & ICANON) > 0);//check if line-buffered
    if (linebufd) {
        t.c_lflag ^= ICANON;//disable canonical line-buffering
        tcsetattr(STDOUT_FILENO, TCSANOW, &t);//update attributes and enable immediate feedback
    }
}
setvbuf(stdin, NULL, _IONBF, 1);//make stdin stream unbuffered

Подробнее о:

1 голос
/ 06 апреля 2019

В комментарии я предложил спрашивающему, что его проблема может быть лучше решена путем использования двойной новой строки (пустой строки) для указания конца ввода вместо ESC.

Он попросил реализацию, так что вот реализация этого. Функция fgets_until_blankline будет читать несколько строк, возвращаясь при двойном нажатии Enter.

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

char *fgets_until_blankline(char *var, int varsize, FILE *file) {

    int inlen = 0;
    char *rc;

    var[0] = 0;
    while(rc = fgets(var+inlen, varsize-inlen, file)) {
        if(var[inlen] == '\n') {
            var[inlen] = 0;
            break;
        }
        inlen = strlen(var);
    }
    return rc;
}

int main() {

    char var[10000];

    fgets_until_blankline(var, sizeof(var), stdin);
    printf("%s", var);

}
...