Solved

getch() equivalent in UNIX

Posted on 1997-10-14
13
671 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 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
 
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
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Get filename and folder into excel 7 67
modThree challenge 4 64
fix34  challenge 9 97
wordappend challenge 8 86
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
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.
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.
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

747 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now