How to handle key pressed in a Linux console in C?

2019-01-09 03:48发布

I'm using Linux console and I would like to do a program which outputs random characters until ESC is pressed. How can I make such a keyboard handler?

标签: c linux keyboard
4条回答
Viruses.
2楼-- · 2019-01-09 04:05

getch() from Curses library perhaps? Also, you will need to use notimeout() to tell getch() not to wait for next keypress.

查看更多
别忘想泡老子
3楼-- · 2019-01-09 04:09

change the tty settings for one key press:

int getch(void) {
      int c=0;

      struct termios org_opts, new_opts;
      int res=0;
          //-----  store old settings -----------
      res=tcgetattr(STDIN_FILENO, &org_opts);
      assert(res==0);
          //---- set new terminal parms --------
      memcpy(&new_opts, &org_opts, sizeof(new_opts));
      new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL);
      tcsetattr(STDIN_FILENO, TCSANOW, &new_opts);
      c=getchar();
          //------  restore old settings ---------
      res=tcsetattr(STDIN_FILENO, TCSANOW, &org_opts);
      assert(res==0);
      return(c);
}
查看更多
小情绪 Triste *
4楼-- · 2019-01-09 04:14
#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

char * me = "Parent";

void sigkill(int signum)
{
    //printf("=== %s EXIT SIGNAL %d ===\n", me, signum);
    exit(0);
}

main()
{
    int pid = fork();
    signal(SIGINT, sigkill);
    signal(SIGQUIT, sigkill);
    signal(SIGTERM, sigkill);
    if(pid == 0) //IF CHILD
    {  
        int ch;
        me = "Child";
        while(1)
        {  
            ch = (rand() % 26) + 'A';   // limit range to ascii A-Z
            printf("%c",ch);
            fflush(stdout); // flush output buffer
            sleep(2);   // don't overwhelm
            if (1 == getppid())
            {  
                printf("=== CHILD EXIT SINCE PARENT DIED ===\n");
                exit(0);
            }
        }
        printf("==CHILD EXIT NORMAL==\n");
    }
    else //PARENT PROCESS
    {  
        int ch;
        if((ch = getchar())==27)
            kill(pid, SIGINT);
        //printf("==PARENT EXIT NORMAL (ch=%d)==\n", ch);
    }
    return(0);
}

In this program u will only need to press enter after esc char,because getchar()is a blocking function. Also u may remove or decrease sleep time for child process as ur need.

查看更多
爷、活的狠高调
5楼-- · 2019-01-09 04:19

The line discipline for a terminal device often works in canonical mode by default. In this mode, the terminal driver doesn't present the buffer to userspace until the newline is seen (Enter key is pressed).

You can set the terminal into raw (non-canonical) mode by using tcsetattr() to manipulate the termios structure. Clearing the ECHO and ICANON flags respectively disables echoing of characters as they are typed and causes read requests to be satisfied directly from the input queue. Setting the values of VTIME and VMIN to zero in the c_cc array causes the read request (fgetc()) to return immediately rather than block; effectively polling stdin. The call to fgetc() will return EOF if a character is not available in the stream.

#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>

int getkey() {
    int character;
    struct termios orig_term_attr;
    struct termios new_term_attr;

    /* set the terminal to raw mode */
    tcgetattr(fileno(stdin), &orig_term_attr);
    memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
    new_term_attr.c_lflag &= ~(ECHO|ICANON);
    new_term_attr.c_cc[VTIME] = 0;
    new_term_attr.c_cc[VMIN] = 0;
    tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);

    /* read a character from the stdin stream without blocking */
    /*   returns EOF (-1) if no character is available */
    character = fgetc(stdin);

    /* restore the original terminal attributes */
    tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);

    return character;
}

int main()
{
    int key;

    /* initialize the random number generator */
    srand(time(NULL));

    for (;;) {
        key = getkey();
        /* terminate loop on ESC (0x1B) or Ctrl-D (0x04) on STDIN */
        if (key == 0x1B || key == 0x04) {
            break;
        }
        else {
            /* print random ASCII character between 0x20 - 0x7F */
            key = (rand() % 0x7F);
            printf("%c", ((key < 0x20) ? (key + 0x20) : key));
        }
    }

    return 0;
}

Note: This code omits error checking for simplicity.

查看更多
登录 后发表回答