Question for GCC programmers

David Bowskill davidbow at tpg.com.au
Sat Oct 9 04:26:31 BST 2010


Thanks Lisa for your reply, my requirement I gather is not that unusual.
Since you enlightened me on the concepts of  'raw' or 'cooked'
terminals, I have found several other sources on this as follows:
http://osr507doc.sco.com/en/OSUserG/_How_to_get_a_character.html
http://stackoverflow.com/questions/421860/c-c-capture-characters-from-standard-input-without-waiting-for-enter-to-be-pre.
There are others as well.
I wish to be able to compile the code to run under MSWindows (ugh!) for
friends to use, so the solution must satisfy this.
Thanks again for your invaluable help.
Regards
David Bowskill

On 08/10/10 22:02, Lisa Milne wrote:
> 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
>   



More information about the ubuntu-au mailing list