Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

getch() equivalent in UNIX

Posted on 1997-10-14
13
Medium Priority
?
750 Views
Last Modified: 2013-12-26
Hi,

I like to know what's the closest function to getch() in UNIX platform.

Basically, I need a function that reads a character from the keyboard without echo.  I don't want to type the "enter" key too.

If there's no such function, how about reading a string without echo?
0
Comment
Question by:YamSeng
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 3
  • +2
13 Comments
 
LVL 84

Expert Comment

by:ozo
ID: 1295226
The closest function to getch() in UNIX would probably be:

#include <curses.h>
character = getch();

see
man getch
also
man noecho
or
man cbreak
0
 
LVL 4

Accepted Solution

by:
jos010697 earned 20 total points
ID: 1295227
If you don't want to use curses, there are some nasty
details to be solved. The terminal is (normally) set
in 'cooked' mode with echo enabled. If you don't want
buffering (part of the cooked mode) and if you don't
want echo, this is where those ioctl() calls come in.

The following function does what you want to accomplish:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>

int getch()
{
struct sgttyb tty, tty_org;
char           key;
int            retval= EOF;

ioctl(fileno(stdin), TIOCGETP, &tty_org);
tty = tty_org;
tty.sg_flags |= CRMOD;
tty.sg_flags &= ~ECHO;
tty.sg_flags &= ~XTABS;

tty.sg_flags |= RAW;
ioctl(0, TIOCSETP, &tty);
fcntl(0, F_SETFL, O_NDELAY);

if ((retval= read(0, &key, 1)) == 1)
        retval= key;

ioctl(fileno(stdin), TIOCSETP, &tty_org);
fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0)&~O_NDELAY);

return retval;
}

kind regards,

Jos aka jos@and.nl
0
 
LVL 84

Expert Comment

by:ozo
ID: 1295228
One problem with using struct sgttyb, is that it may not be portable
between BSDish and SYSVish Unixes
0
Moving data to the cloud? Find out if you’re ready

Before moving to the cloud, it is important to carefully define your db needs, plan for the migration & understand prod. environment. This wp explains how to define what you need from a cloud provider, plan for the migration & what putting a cloud solution into practice entails.

 
LVL 51

Expert Comment

by:ahoffmann
ID: 1295229
why not using  getc()  ?
0
 
LVL 4

Expert Comment

by:jos010697
ID: 1295230
getc() uses buffered I/O streams (the FILE stuff); echoing
and buffering is beyond the scope of getc(). You need to dig
down to the bare metal to get rid of buffering and echoing,
hence the ioctl() and fcntl() stuff in my answer.

Ozo is right though; those sgttyb structs aren't the same
on all platforms (if they even exist).

kind regards,

Jos aka jos@and.nl
0
 
LVL 1

Author Comment

by:YamSeng
ID: 1295231
jos, thanks for the long answer.  I expected a short answer because of the points....hee!  

I actually wanted to do a password retrieving function......and only just now, I found that there's 1 built in function that does the job.  The function is getpass().

Anyway, ozo, can I use getch() in unix just like how I use it in windows?  I encountered some errors while using it.....
0
 
LVL 1

Author Comment

by:YamSeng
ID: 1295232
I've increased the points by a bit.  Sorry, but I didn't expect so many comments.  I thought it should be straight forward.
0
 
LVL 84

Expert Comment

by:ozo
ID: 1295233
What errors did you encounter?  
(if you still care now that you can use getpass -
which does wait for a newline, so it's not quite what you asked)
0
 
LVL 4

Expert Comment

by:jos010697
ID: 1295234
If you want to read a password, getpass() is your friend,
but that is not what you've asked for (see above).

If you don't mind the whole curses gorilla to be linked
in, while asking for a small getch() banana, have a look
at the (curses aware) terminal modes: NODELAY, CBREAK and
NOECHO ...

kind regards,

Jos aka jos@and.nl
0
 
LVL 1

Author Comment

by:YamSeng
ID: 1295235
Sorry for the confusion.

I do not want the enter key to be in because I want to make it such that if the user types a key, the screen only echo an * and stops when enter is pressed.  For getc or any other functions, I need to type enter for every key, which is not practical for a string of password.

getpass does not actually soved 100% of what I wanted initally.  It does not prints * ....

But anyway, I've got what I need.  Thanks for your effort.
0
 

Expert Comment

by:jmcarney
ID: 1295236

I actually had some trouble implementing jos' solution under SGI irix - the interface used seems to be 'deprecated'. A little digging with 'man' and on the web revealed the following alternate solution...

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

struct termios SavedAttributes ;

int SetInputMode (void)
  {
  struct termios attr ;

  /* Make sure stdin is a terminal... */
  if (!(isatty (fileno (stdin))))
    return 0 ;

  /* Save current attributes. */
  tcgetattr (fileno (stdin), &SavedAttributes) ;

  /* Set terminal modes. */
  tcgetattr (fileno (stdin), &attr) ;
  attr.c_lflag &= ~(ICANON | ECHO) ;
  attr.c_cc[VMIN] = 1 ;
  attr.c_cc[VTIME] = 0 ;

  return 1 ;
  }

void ResetInputMode (void)
  {
  tcsetattr (fileno (stdin), TCSANOW, &SavedAttributes) ;
  }

int getch (void)
  {
  char c ;
  while (read (fileno (stdin), &c, 1) == 0) ;
  return (int) c ;
  }

void main (void)
  {
  int c ;

  if (!(SetInputMode ()))
    printf ("stdin is not a terminal!\n") ;
  else
    {
    do
      {
      c = getch () ;
      fputc (c, stdout) ;
      fflush (stdout) ;
      }
    while ((c != '\r') && (c != '\n')) ;
    ResetInputMode () ;
    }
  }

SetInputMode() sets stdin to be non-canonical (raw) and non-echoing. It will fail if stdin is not a terminal. It returns 1 if successful,  0 if otherwise.

ResetInputMode() restores stdin to its original state.

getch() waits for a character to come in from stdin and returns its value.

Cheers,
John Carney

0
 
LVL 4

Expert Comment

by:jos010697
ID: 1295237
To jmcarney: your solution is definitely more 'up to date'; my solution saw the
light somewhere in the stone age and I carried it with my 'till now ;-)

Two remarks though:

1: shouldn't the last lines of function SetInputMode read:

/* Set terminal modes. */

        attr.c_lflag &= ~(ICANON | ECHO) ;
        attr.c_cc[VMIN] = 1 ;
        attr.c_cc[VTIME] = 0 ;
        tcsetattr (fileno (stdin), &attr) ;

        return 1 ;

2: never ever write 'void main', in comp.lang.c they'd tar and feather you for that ;-)

kind regards,

Jos aka jos@and.nl
0
 

Expert Comment

by:jmcarney
ID: 1295238
jos,

1: Yep, thanks for pointing that out.

2: Woops!

Cheers,
John Carney
jmcarney@bigpond.com



0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Displaying information on the statusbar.   Continuing from the third article about sudoku.   Open the project in visual studio. Status bar – let’s display the timestamp there.  We need to get the timestamp from the document s…
In this post we will learn different types of Android Layout and some basics of an Android App.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses

688 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question