Question for GCC programmers

Lisa Milne lisa at ltmnet.com
Fri Oct 8 12:02:39 BST 2010


On Fri, 08 Oct 2010 19:58:34 +1100
David Bowskill <davidbow at tpg.com.au> wrote:

> Hello Fellow Ubuntu Users
> 
> I  have been writing some programs using GCC and I wish to have a
> program receive a character from the keyboard immediately upon
> pressing the key ( not buffered or held until 'enter' is pressed) and
> with no echoing to the screen.
> Is there a simple way to achieve this?
> 
> Thanks in anticipation
> 
> David
> 
> -- 
> ubuntu-au mailing list
> ubuntu-au at lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/ubuntu-au

Hi David,

There's 2 options for this in C, firstly and probably the easiest is to
use ncurses. Something like this will do what you want:

#include <unistd.h>
#include <stdio.h>
#include <ncurses.h>
#include <ctype.h>

int main(int argc, char** argv)
{
	initscr();
	cbreak();
	keypad(stdscr, TRUE);
	int ch = getch();
	endwin();
	printf("you pressed %c\n",ch);
	return 0;
}

make sure to add
 -lncurses
to the compiler command.

Secondly, you can manually set the tty to raw mode, wait for the
keypress, read from stdin, and reset the tty to cooked mode, which
would look something like this:

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif

static struct termios termattr, save_termattr;
static int ttysavefd = -1;
static enum {
	RESET,
	RAW
} ttystate = RESET;

int set_tty_raw(void)
{
	int i;

	i = tcgetattr (STDIN_FILENO, &termattr);
	if (i < 0) {
		return -1;
	}
	save_termattr = termattr;

	termattr.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
	termattr.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
	termattr.c_cflag &= ~(CSIZE | PARENB);
	termattr.c_cflag |= CS8;
	termattr.c_oflag &= ~(OPOST);

	termattr.c_cc[VMIN] = 1;
	termattr.c_cc[VTIME] = 0;

	i = tcsetattr (STDIN_FILENO, TCSANOW, &termattr);
	if (i < 0) {
		return -1;
	}

	ttystate = RAW;
	ttysavefd = STDIN_FILENO;

	return 0;
}

int set_tty_cooked()
{
	int i;
	if (ttystate != RAW) {
		return 0;
	}
	i = tcsetattr(STDIN_FILENO, TCSAFLUSH, &save_termattr);
	if (i < 0) {
		return -1;
	}
	ttystate = RESET;
	return 0;
}

unsigned char getch(void)
{
	unsigned char ch;
	size_t size;

	while (1) {
		usleep(20000);

		size = read(STDIN_FILENO, &ch, 1);
		if (size > 0) {
			/* manually handle Ctrl-C (EOT) */
			if (0x03 == ch) {
				set_tty_cooked();
				exit(0);
			}
			printf("%c", ch);
			break;
		}
	}
	return ch;
}

int main(int argc, char** argv)
{
	set_tty_raw();

	unsigned char ch = getch();

	printf("\nyou pressed %c\n",ch);

	set_tty_cooked();

	return 0;
}


HTH
-- 
Lisa Milne <lisa at ltmnet.com>



More information about the ubuntu-au mailing list