getch() equivalent in UNIX

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?
LVL 1
YamSengAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ozoCommented:
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
jos010697Commented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ozoCommented:
One problem with using struct sgttyb, is that it may not be portable
between BSDish and SYSVish Unixes
0
Learn Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

ahoffmannCommented:
why not using  getc()  ?
0
jos010697Commented:
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
YamSengAuthor Commented:
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
YamSengAuthor Commented:
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
ozoCommented:
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
jos010697Commented:
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
YamSengAuthor Commented:
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
jmcarneyCommented:

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
jos010697Commented:
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
jmcarneyCommented:
jos,

1: Yep, thanks for pointing that out.

2: Woops!

Cheers,
John Carney
jmcarney@bigpond.com



0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.