Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

getch() equivalent in UNIX

Posted on 1997-10-14
13
Medium Priority
?
765 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
  • 4
  • 3
  • 3
  • +2
13 Comments
 
LVL 85

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 85

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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
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 85

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

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

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

Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
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.
This course is ideal for IT System Administrators working with VMware vSphere and its associated products in their company infrastructure. This course teaches you how to install and maintain this virtualization technology to store data, prevent vuln…
Suggested Courses

916 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