85

I am not able to find the equivalent header file for conio.h in Linux.

Is there any option for getch() & getche() function in Linux?

I want to make a switch case base menu where the user will give his option just by pressing one key & process should be moved ahead. I don't want to let user to press ENTER after pressing his choice.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Jeegar Patel
  • 26,264
  • 51
  • 149
  • 222

6 Answers6

99
#include <termios.h>
#include <stdio.h>

static struct termios old, current;

/* Initialize new terminal i/o settings */
void initTermios(int echo) 
{
  tcgetattr(0, &old); /* grab old terminal i/o settings */
  current = old; /* make new settings same as old settings */
  current.c_lflag &= ~ICANON; /* disable buffered i/o */
  if (echo) {
      current.c_lflag |= ECHO; /* set echo mode */
  } else {
      current.c_lflag &= ~ECHO; /* set no echo mode */
  }
  tcsetattr(0, TCSANOW, &current); /* use these new terminal i/o settings now */
}

/* Restore old terminal i/o settings */
void resetTermios(void) 
{
  tcsetattr(0, TCSANOW, &old);
}

/* Read 1 character - echo defines echo mode */
char getch_(int echo) 
{
  char ch;
  initTermios(echo);
  ch = getchar();
  resetTermios();
  return ch;
}

/* Read 1 character without echo */
char getch(void) 
{
  return getch_(0);
}

/* Read 1 character with echo */
char getche(void) 
{
  return getch_(1);
}

/* Let's test it out */
int main(void) {
  char c;
  printf("(getche example) please type a letter: ");
  c = getche();
  printf("\nYou typed: %c\n", c);
  printf("(getch example) please type a letter...");
  c = getch();
  printf("\nYou typed: %c\n", c);
  return 0;
}

Output:

(getche example) please type a letter: g
You typed: g
(getch example) please type a letter...
You typed: g
S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
niko
  • 9,285
  • 27
  • 84
  • 131
  • 5
    Thank you, it works but i had to replace **new** with something else because it's a keyword i guess – Mihai Vilcu Jun 04 '13 at 19:33
  • 1
    @cipher On Windows you have `_getch` included in the Windows APIs, in – Paul Stelian Jan 07 '17 at 21:01
  • 2
    @MihaiVilcu `new` is a keyword in C++, but not in C. – Paul Stelian Jan 07 '17 at 21:01
  • 1
    @PaulStelian I was using mingw-gcc back then, and if my memory serves me well, it did not have conio or termios. – cipher Jan 12 '17 at 16:24
  • mingw does have a reduced version of conio featuring _getch() [that, or Code::Blocks with MinGW includes something else] @cipher – Paul Stelian Jan 13 '17 at 05:47
  • 2
    there is a bug in this sample: when echo is true `new.c_lflag &= ECHO` is incorrect, it will clear all bits except ECHO, should be `new.c_lflag |= ECHO` – RedSoft Mar 10 '18 at 02:43
  • `getchar()` returns an *int*. Squeezing it into a *char* causes it to be unable to tell the differce between a possibly valid character with value 255 (such as `ÿ` in the ISO-8859-1 or CP1252 charsets) from an input error. – Paulo1205 Apr 01 '19 at 18:56
  • Is it better to use `getch()` from `` if you're on windows? or is this way better? – Alex Jul 22 '20 at 22:58
  • How would this interact with the fact that, from what I've observed, Unix normally echoes characters typed at the console before code tries to read them? What would happen if e.g. the program waited for a second before the first getch() call, and a user typed characters at the console during that time? – supercat May 25 '21 at 16:50
44
#include <unistd.h>
#include <termios.h>

char getch(void)
{
    char buf = 0;
    struct termios old = {0};
    fflush(stdout);
    if(tcgetattr(0, &old) < 0)
        perror("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
    if(tcsetattr(0, TCSANOW, &old) < 0)
        perror("tcsetattr ICANON");
    if(read(0, &buf, 1) < 0)
        perror("read()");
    old.c_lflag |= ICANON;
    old.c_lflag |= ECHO;
    if(tcsetattr(0, TCSADRAIN, &old) < 0)
        perror("tcsetattr ~ICANON");
    printf("%c\n", buf);
    return buf;
 }

Remove the last printf if you don't want the character to be displayed.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
mf_
  • 605
  • 8
  • 17
  • 2
    @mr-32 this is the exactly linux equivalent to getch() used by visual studio for windows, minus the printf() on the last line of this function – mf_ May 04 '13 at 12:10
  • I hope it's not, because it has a bug in it. It's assuming that ICANON and ECHO were set prior to the call when resetting to the old state. – pjcard Jun 14 '22 at 18:21
7

I suggest you use curses.h or ncurses.h these implement keyboard management routines including getch(). You have several options to change the behavior of getch (i.e. wait for keypress or not).

Fafaman
  • 141
  • 10
4

There is a getch() function in the ncurses library. You can get it by installing the ncurses-dev package.

Jan S
  • 1,831
  • 15
  • 21
-1

You can use the curses.h library in linux as mentioned in the other answer.

You can install it in Ubuntu by:

sudo apt-get update

sudo apt-get install ncurses-dev

I took the installation part from here.

Community
  • 1
  • 1
Box Box Box Box
  • 5,094
  • 10
  • 49
  • 67
-1

As said above getch() is in the ncurses library. ncurses has to be initialized, see i.e. getchar() returns the same value (27) for up and down arrow keys for this

ralf htp
  • 9,149
  • 4
  • 22
  • 34