Terminal Keyboard Input
This page was last modified 2007-02-21 16:29:53 by Puchu.Net user Choco. (Show history)

When you are writing an interactive application under Linux, often it is necessary to constantly poll terminal for keyboard input. This can be done by using termio and stdio functions.

Sample Loop

The code below outlines a simple loop for dispatching key hits:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/types.h>

int             r = 1;  // if r == 0, exit loop
fd_set          fd;     // to store file descriptor masks
struct timespec d;      // insert delay to give up CPU
struct timeval  t;      // used by select()
unsigned char   k;      // stores the key input
struct termios  i, n;   // stores terminal settings

// get current terminal settings so that we may restore it later
tcgetattr(0, &i);

// duplicate current settings and add the settings we want
memcpy(&n, &i, sizeof(struct termios));
n.c_lflag &= ~ICANON;
n.c_lflag &= ~ECHO;
n.c_lflag &= ~ISIG;
n.c_cc[VMIN] = 1;
n.c_cc[VTIME] = 0;

// update terminal settings with our own
tcsetattr(0, TCSANOW, &n);

// set up a sleep delay, to give up the input thread
d.tv_sec = 0;
d.tv_nsec = 1000000000 / 60;

while (r == 1) {
  FD_ZERO(&fd);
  FD_SET(STDIN_FILENO, &fd);
  t.tv_sec = 0;
  t.tv_usec = 0;

  if (select(STDIN_FILENO + 1, &fd, NULL, NULL, &t) > 0) {
    if (read(STDIN_FILENO, &k, 1) == 1) {
      switch(k) {
      	case 'q':
      	case 'Q':
          r = 0;
      	  break;

      	default:
      	  break;
      }
    }
  }

  nanosleep(&d, NULL);
}

// done with terminal input, restore initial settings
tcsetattr(0, TCSANOW, &i);

The code above exits after user hits the Q key. You can add more cases to the switch statement to handle other key presses. I used this loop to implement Tetris on an embedded Linux machine.

Analysis

The function select() tells us whether a file is ready for read/write, or if there is an error associated with it and stores the result in fd_set*. We are only interested in reading key presses, so the 3rd and 4th parameters are NULL. Once we know there is something from STDIN, we can read the key character using normal read() function.

For an interactive application it is often undesirable to have all of the key presses echoed in the terminal and you may want to filter certain key combinations, so we use tcsetattr() to set our own terminal settings with ECHO and ISIG bits switched off.

References

Puchu.Net

Document is accessible from http://www.puchu.net. © 2002-2010 Sean Yang, Karen Yang, Don Yang and/or respective authors, all rights reserverd.

This material may contain (biased) opinions, inappropriate materials for numerous individuals, work of other authors from the internet, links that refer to other web documents and resources, or origial work that cannot be use for personal or commercial purposes. Please respect the work of original authors.


Creative Commons License
Powered By MediaWiki

© 2002-2010 Sean Yang, all rights reserved.