OneZero
OneZero

Reputation: 11914

Keyboard catch in C

So I'm thinking about how to catch keyboard activities in C. As we all know, we can type something and press Enter to stream in whatever we want to send to the computer. But the first question is, how to input some untypeable characters like up arrow, down arrow (especially these two guys because I'm using Linux but want to use them for something other than their default meanings), shift, ctrl or whatever. Second, how to make the program proceed right after we press any key, so we don't need to enter and enter all the time. (It's like "Press any key to continue" in Windows).

Upvotes: 1

Views: 3604

Answers (4)

paulsm4
paulsm4

Reputation: 121799

The "universal" method is getchar (). Getchar()" uses "buffered input": you don't actually get any output until the user presses "Enter". And it isn't really applicable unless you're using a command prompt (or equivalent).

The old DOS way was getch() and getche(), from "conio.h". That method doesn't exist in modern C/C++ libraries targeting modern operating systems.

SUGGESTION:

If you want to create a text-mode UI (especially on Linux), take a look at ncurses:

If you want to program a game (on Windows or Linux), take a look at SDL:

=== ADDENDUM ===

I still recommend a library ... but here's a function that illustrates "raw keyboard input" (aka "uncooked", or "non-canonical" input) under Linux:

http://cboard.cprogramming.com/c-programming/63166-kbhit-linux.html

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

void changemode(int);
int  kbhit(void);

int 
main(int argc, char *argv[])
{
  int ch;
  changemode(1);
  while ( !kbhit() )
  {
    putchar('.');
  }

  ch = getchar();

  printf("\nGot %c\n", ch);

  changemode(0);
  return 0;
}

void 
changemode(int dir)
{
  static struct termios oldt, newt;

  if ( dir == 1 )
  {
    tcgetattr( STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newt);
  }
  else
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
}

int 
kbhit (void)
{
  struct timeval tv;
  fd_set rdfs;

  tv.tv_sec = 0;
  tv.tv_usec = 0;

  FD_ZERO(&rdfs);
  FD_SET (STDIN_FILENO, &rdfs);

  select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
  return FD_ISSET(STDIN_FILENO, &rdfs);

}

Upvotes: 0

Wernsey
Wernsey

Reputation: 5491

In the DOS days, there was a kbhit() function. If you need that functionality you can look at this thread: kbhit() for linux.

I vaguely recall trying the user Thantos' function and it working rather well.

I do recommend you read up on what the tcgetattr() and tcsetattr() functions first.

Upvotes: 1

madper
madper

Reputation: 796

There are two ways.

Using stty command.

  • you can add system ("/bin/stty raw"); before you using getchar()
  • for more details, please man stty.

Using termios.h here

  • you should change your tty's mode like this newt.c_lflag &= ~(ICANON | ECHO);
  • for more details, please man termios.h

Upvotes: 2

Shane
Shane

Reputation: 667

If you are using Linux the best bet for keyboard input is the GNU readline library.

This provides all the functionality out of the box including emacs and vi editing modes if you want them.

/* A static variable for holding the line. */
static char *line_read = (char *)NULL;

/* Read a string, and return a pointer to it.  Returns NULL on EOF. */
char *
rl_gets ()
{
    /* If the buffer has already been allocated, return the memory to the free pool. */
    if (line_read)
    {
        free (line_read);
        line_read = (char *)NULL;
    }

    /* Get a line from the user. */
    line_read = readline ("");

    /* If the line has any text in it, save it on the history. */
    if (line_read && *line_read)
        add_history (line_read);

    return (line_read);
}

MIT has some great tutorials.

Upvotes: 0

Related Questions