How can I make my program not echo input, like login does when asking for your password?
There is an easy way, and a slightly harder way:
The easy way, is to use getpass()
, which is probably found on
almost all Unices. It takes a string to use as a prompt. It will read up
to an EOF
or newline and returns a pointer to a static area of
memory holding the string typed in.
The harder way is to use tcgetattr()
and tcsetattr()
, both
use a struct termios
to manipulate the terminal. The following
two routines should allow echoing, and non-echoing mode.
#include <stdlib.h> #include <stdio.h> #include <termios.h> #include <string.h> static struct termios stored_settings; void echo_off(void) { struct termios new_settings; tcgetattr(0,&stored_settings); new_settings = stored_settings; new_settings.c_lflag &= (~ECHO); tcsetattr(0,TCSANOW,&new_settings); return; } void echo_on(void) { tcsetattr(0,TCSANOW,&stored_settings); return; }
Both routines used, are defined by the POSIX standard.
How can I read single characters from the terminal? My program is always waiting for the user to press RETURN.
Terminals are usually in canonical mode, where input is read in lines
after it is edited. You may set this into non-canonical mode, where you
set how many characters should be read before input is given to your
program. You also may set the timer in non-canonical mode terminals to
0, this timer flushs your buffer at set intervals. By doing this, you
can use getc()
to grab the key pressed immediately by the
user. We use tcgetattr()
and tcsetattr()
both of which are
defined by POSIX to manipulate the termios
structure.
#include <stdlib.h> #include <stdio.h> #include <termios.h> #include <string.h> static struct termios stored_settings; void set_keypress(void) { struct termios new_settings; tcgetattr(0,&stored_settings); new_settings = stored_settings; /* Disable canonical mode, and set buffer size to 1 byte */ new_settings.c_lflag &= (~ICANON); new_settings.c_cc[VTIME] = 0; new_settings.c_cc[VMIN] = 1; tcsetattr(0,TCSANOW,&new_settings); return; } void reset_keypress(void) { tcsetattr(0,TCSANOW,&stored_settings); return; }
How can I check and see if a key was pressed? On DOS I use the
kbhit()
function, but there doesn't seem to be an equivalent?
If you set the terminal to single-character mode (see previous answer),
then (on most systems) you can use select()
or poll()
to
test for readability.
How can I move the cursor around the screen? I want to do full screen editing without using curses.
Seriously, you probably don't want to do this. Curses knows about how to handle all sorts of oddities that different terminal types exhibit; while the termcap/terminfo data will tell you whether any given terminal type possesses any of these oddities, you will probably find that correctly handling all the combinations is a huge job.
However, if you insist on getting your hands dirty (so to speak), look
into the termcap
functions, particularly tputs()
,
tparm()
and tgoto()
.
Pseudo-teletypes (pttys, ptys, other variant abbreviations) are pseudo-devices that have two parts: the master side, which can be thought of as the `user', and the slave side, which behaves like a standard tty device.
They exist in order to provide a means to emulate the behaviour of a
serial terminal under the control of a program. For example,
telnet
uses a pseudo-terminal on the remote system; the remote
login shell sees the behaviour it expects from a tty device, but the
master side of the pseudo-terminal is being controlled by a daemon that
forwards all data over the network. They are also used by programs such
as xterm
, expect
, script
, screen
,
emacs
, and many others.
The handling of serial devices under Unix is heavily influenced by the traditional use of serial terminals. Historically, various combinations of ioctls and other hacks were necessary to control the precise behaviour of a serial device, but fortunately this is one of the areas that POSIX made some efforts to standardise.
If you're using a system that doesn't understand <termios.h>
,
tcsetattr()
and related functions, then you'll have to go
elsewhere for information (or upgrade your system to something less
archaeological).
There are still significant differences between systems, however, mainly in the area of device names, handling of hardware flow control, and modem signalling. (Whenever possible, leave the device driver to do all the handshaking work, and don't attempt to manipulate handshaking signals directly.)
The basic steps for opening and initialising a serial device are:
open()
the device; this may require the use of certain flags:
O_NONBLOCK
O_NOCTTY
tcgetattr()
to retrieve the current device modes. While one
will often ignore most or all of the initial settings thus obtained, it's
still a convenient way of initialising a struct termios
.
c_iflag
, c_oflag
, c_cflag
,
c_lflag
, and c_cc
in the termios structure. (See below.)
cfsetispeed()
and cfsetospeed()
to set the desired
baud rate. Very few systems allow you to set differing input and output
speeds, so as a general rule you should set both to your desired speed.
tcsetattr()
to set the device modes.
O_NONBLOCK
when opening the port, to
use fcntl()
to ensure that O_NONBLOCK
is turned off again.
Systems seem to differ as to whether a nonblocking open on a tty will
affect subsequent read()
calls; better to be explicit.
Once you have opened and set up the port, you can then use read()
and write()
normally. Note that the behaviour of read()
will
be controlled by the flag settings you gave to tcsetattr()
.
tcflush()
, tcdrain()
, tcsendbreak()
and
tcflow()
are additional useful functions that you should be aware
of.
When you're done with the port, and want to close it, be aware of a very
nasty little hazard on some systems; if there's any pending output waiting
to be written to the device (e.g. if output flow is stopped by hardware
or software handshaking), your process can hang unkillably in the
close()
call until the output drains. Calling tcflush()
to
discard any pending output is probably a wise move.
(Blocked output on tty devices is by far the most common cause of "unkillable" processes in my experience.)
The device names used for serial port devices vary quite widely between systems. Some examples from different systems are:
The precise interaction between the device name used, and the effect on any hardware handshake lines is system-, configuration- and hardware-dependant, but will usually follow approximately these rules (assuming that the hardware is RS-232 DTE):
Some hints on setting up the termios flags when using a serial device that you've opened yourself (as opposed to using your existing control tty):
You probably want to set all the bits in c_iflag
to 0,
unless you want to use software flow control (ick) in which case you set
IXON
and IXOFF
.
Most of the bits of c_oflag
are hacks of one sort or another to
make output to slow terminals work, and as such some newer systems have
dropped almost all of them as obsolete (especially all the gory
output-padding options). As with c_iflag
, setting everything to 0
is reasonable for most applications.
When setting the character size, remember to mask using CSIZE
first; e.g. to set 8-bit characters, use:
attr.c_cflag &= ~CSIZE; attr.c_cflag |= CS8;
Other important flags found in c_cflag
that you probably want to
turn on and CREAD
and HUPCL
.
If you need to generate even parity, then set PARENB
and clear
PARODD
; if you need to generate odd parity then set both
PARENB
and PARODD
. If you don't want parity at all, then
make sure PARENB
is clear.
Clear CSTOPB
unless you actually need to generate two stop bits.
Flags for enabling hardware flow control may also be found in
c_cflag
, but they aren't standardised (pity).
Most applications will probably want to turn off ICANON
(canonical, i.e. line-based, input processing), ECHO
, and
ISIG
.
IEXTEN
is a more complex issue. If you don't turn it off, the
implementation is allowed to do nonstandard things (like define
additional control characters in c_cc
) that might cause
unexpected results, but you might need to leave IEXTEN
enabled
on some systems to get useful features like hardware flow control.
This is an array of characters that have special meanings on input.
These characters are given names like VINTR
, VSTOP
etc.;
the names are indexes into the array.
(Two of these "characters" are not really characters at all, but control
the behaviour of read()
when ICANON
is disabled; these are
VMIN
and VTIME
.)
The indexes are often referred to as though they were actual variables, e.g. "set VMIN to 1" actually means "set c_cc[VMIN] to 1". The shorthand is useful and only occasionally confusing.
Many of the slots in c_cc
are only used if some other combination
of flags is set:
ICANON
is set
VEOF
, VEOL
, VERASE
, VKILL
(and also
VEOL2
, VSTATUS
and VWERASE
if defined and
IEXTEN
is set)
ISIG
is set
VINTR
, VQUIT
, VSUSP
(and also VDSUSP
if
defined and IEXTEN
is set)
IXON
or IXOFF
is set
VSTOP
, VSTART
ICANON
is not set
VMIN
, VTIME
Implementations may define additional entries in c_cc
. It may
be prudent to initialise all the entries to _POSIX_VDISABLE
(the constant NCCS
gives the array size) before setting the
specific values you wish to use.
VMIN
and VTIME
(which may share slots with VEOF
and
VEOL
respectively, depending on the implementation) have the
following meaning. The value of VTIME
is (if not 0) always
interpreted as a timer in tenths of seconds.
c_cc[VMIN] > 0, c_cc[VTIME] > 0
read()
will return when either VMIN bytes of input are available,
or if at least one character has been read and VTIME has expired between
characters, or if interrupted by a signal.
c_cc[VMIN] > 0, c_cc[VTIME] == 0
read()
will return when VMIN bytes of input are available, or if
interrupted. Otherwise it will wait indefinitely.
c_cc[VMIN] == 0, c_cc[VTIME] > 0
read()
will return as soon as any input is available; if VTIME
expires with no data arriving, it will return with no characters read.
(This conflicts slightly with the end-of-file indication received in
the event of modem hangup; using 1 for VMIN and either alarm()
or select()
for a timeout avoids this particular problem.)
c_cc[VMIN] == 0, c_cc[VTIME] == 0
read()
will always return immediately; if no data is available
it will return with no characters read (with the same problem as above).
Go to the first, previous, next, last section, table of contents.