Solved

getch() equivalent in UNIX

Posted on 1997-10-14
13
738 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
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
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.
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…

635 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