On Fri, 08 Oct 2010 19:58:34 +1100
David Bowskill <[email protected]> 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
> [email protected]
> 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 <[email protected]>

-- 
ubuntu-au mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-au

Reply via email to