简体   繁体   中英

C - Is there a way to terminate string input with a key other than 'Enter'?

I'm working on an assignment scheduler for my school, the code below is a segment of a module for inputting data for a new assignment and subsequently writing that data to file. Since the assignment description may be a lengthy paragraph, I decided to allow the user to move to a new line upon pressing the Enter key for ease of input. The code I have so far works as desired. The description is a single string however which is usually terminated with the enter key. Is it possible to terminate the string with another key? For example the Escape Key? If so, how do I go about doing this?

I was thinking of using the escape 'Esc' key to terminate string entry but I'm not sure which code or escape sequence with which to represent the key.

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);
    //...
}

I expect the string to be read upon pressing the escape key so that execution can continue.

Input is line-buffered by default. You can use ncurses (which doesn't do this) or manually disable:

#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

Read more about:

In comment, I suggested to the questioner that his problem could possibly be better resolved by using a double newline (blank line) to indicate end-of-input instead of ESC.

He has asked for an implementation, so here's an implementation of that. The fgets_until_blankline function will read multiple lines, returning when Enter is pressed twice.

#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);

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM