user2151486
user2151486

Reputation: 848

breaking loop with keypress in linux c

I need to write a program in C language which will be doing something like this: For example, when I will press "a", terminal will be writing that typed character in the unending loop like this: aaaaaaaaaaaaaaaa...until another key, for example "b" will be pressed. Final output should look like this: aaaaaaaaabbbbbbq (q should terminate the program). My code here:

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

    int c;
    static struct termios staryTermios, novyTermios;


    tcgetattr(STDIN_FILENO, &staryTermios);

    novyTermios = staryTermios;
    novyTermios.c_lflag &= ~(ICANON);
    tcsetattr(STDIN_FILENO, TCSANOW, &novyTermios);
    while ((c = getchar()) != 'q') {
        putchar(c);
    }

    tcsetattr( STDIN_FILENO, TCSANOW, &staryTermios);

    return 0;
}

this version writes the typed characters only once and then it waits for another keypress

Upvotes: 3

Views: 2028

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 754570

To achieve the result you want, you need to make the standard input non-blocking. You can do that with this minor adaptation of your code. It worked fine on Mac OS X 10.7.5. Note that getchar() returns EOF when there's no character ready to read (which will be most of the time; neither you nor I can type fast enough to matter to a modern computer). I'm mildly concerned that on some systems, once getchar() has returned EOF once when there was no character to read, it might never return anything other than EOF again, but that wasn't a problem for Mac OS X.

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>

static void err_exit(const char *msg);

int main(void)
{
    int c;
    int oc = '\0';
    struct termios staryTermios, novyTermios;
    int oflags, nflags;

    if (tcgetattr(STDIN_FILENO, &staryTermios) != 0)
        err_exit("tcgetattr() failed");

    novyTermios = staryTermios;
    novyTermios.c_lflag &= ~(ICANON);
    if (tcsetattr(STDIN_FILENO, TCSANOW, &novyTermios) != 0)
        err_exit("tcsetattr() failed to set standard input");

    oflags = fcntl(STDIN_FILENO, F_GETFL);
    if (oflags < 0)
        err_exit("fcntl() F_GETFL failed");

    nflags = oflags;
    nflags |= O_NONBLOCK;
    if (fcntl(STDIN_FILENO, F_SETFL, nflags) == -1)
        err_exit("fcntl() F_SETFL failed");

    while ((c = getchar()) != 'q')
    {
        if (c != EOF)
            oc = c;
        if (oc != '\0')
            putchar(oc);
    }

    if (tcsetattr(STDIN_FILENO, TCSANOW, &staryTermios) != 0)
        err_exit("tcsetattr() failed to reset standard input");

    putchar('\n');
    return 0;
}

static void err_exit(const char *msg)
{
    fprintf(stderr, "%s\n", msg);
    exit(1);
}

Upvotes: 2

uba
uba

Reputation: 2031

I guess you will need two threads which will both be accessing a common variable. The job of one thread would be to continuously print the common variable. The job of the second would be to wait for input from the keyboard and update the variable accordingly.

Upvotes: 0

Related Questions