LINUX.ORG.RU

Си: читать клавиши без паузы


0

0

В программе требуется посмотреть есть ли в буфере нажатые клавиши. Если есть — обработать их, если нет — продолжать работу. getchar не подходит, так как останавливает программу на время ожидания ввода.

Всё, что нашёл в манах, относится к Allegro и Curses. Рекомендации в сети относятся к досу:

        mov ah,1 
        int 16h             ; проверяет нажимали ли клавишу
        jne @@key_pressed
@@return: 
        ret                 ; Если нет — возврат
@@key_pressed:
        xor ax,ax
        int 16h             ; если нажали — считать
        cmp ah,1
        jne @@return        ; Если не ESC — тоже возврат
        jmp EXIT            ; если ESC — выйти из программы

Как это осуществить пользуясь только libc и системными вызовами?

★★★★★
Ответ на: комментарий от question4

> А можно ли просто использовать эту kbhit() совместно со стандартной getchar()?

#define getchar getch

:)

а если серьёзно, то, скорее всего, можно, но для этого в начале работы программы необходимо перевести терминал в raw-режим, а перед завершением (в т.ч. и по SIGINT/SIGTERM/…) возвращать в дефолтный.

arsi ★★★★★
()

Такой вариант подойдет?

unsigned char read_console(){ // считываем данные с консоли
	unsigned char rb;
	struct timeval tv;
	int retval;
	tcgetattr( STDIN_FILENO, &oldt ); // открываем терминал для реакции на клавиши без эха
	newt = oldt;
	newt.c_lflag &= ~( ICANON | ECHO );
	tcsetattr( STDIN_FILENO, TCSANOW, &newt );
	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(STDIN_FILENO, &rfds); // 0 - стандартный вход
	tv.tv_sec = 0; tv.tv_usec = 10000; // ждем 0.01с
	retval = select(1, &rfds, NULL, NULL, &tv);
	if (!retval) rb = 0;
	else {
		if(FD_ISSET(STDIN_FILENO, &rfds)) rb = getchar();
		else rb = 0;
	}
	tcsetattr( STDIN_FILENO, TCSANOW, &oldt );	
	return rb;
}

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от question4

> использовать эту kbhit() совместно со стандартной getchar()

Не получается, getchar() всегда дожидается нажатия Enter.

question4 ★★★★★
() автор топика

два варианта

1. ioctl(0,FIONREAD,&num) - возвращает число символов в stdin
2. можно сделать дескриптор неблокирующим и читать из него

ps: нужно также не забывать про режим ввода (канонический он или нет)

Chumka ★★★
()
Ответ на: комментарий от Eddy_Em

> Такой вариант подойдет?

Спасибо. Немного не то, что нужно, но я уже разобрался, как его переделать.

question4 ★★★★★
() автор топика
Ответ на: комментарий от Chumka

> ioctl(0,FIONREAD,&num) - возвращает число символов в stdin

Спасибо. А что сделать, чтобы оно начало видеть нажатые символы до того, как я нажму Enter?

можно сделать дескриптор неблокирующим и читать из него

Как?

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

>Спасибо. А что сделать, чтобы оно начало видеть нажатые символы до того, как я нажму Enter?
Отключить канонический режим ввода. В примере выше это делается (Флаг I_CANON)

Как?

man fcntl

Chumka ★★★
()

мопед не мой

int
kbhit(void)
{
        struct timeval tv;
        fd_set read_fd;

        tv.tv_sec = 0;
        tv.tv_usec = 0;

        FD_ZERO(&read_fd);
        FD_SET(0,&read_fd);

        if (select(1, &read_fd, NULL, NULL, &tv) == -1)
                return 0;

        if (FD_ISSET(0,&read_fd))
                return 1;

        return 0;
}

int
main()
{
        printf("hello\n");
        printf("Press any key to continue..\n");
        while (!kbhit());
                printf("bye bye\n");

return 0;
}

cite: http://www.ozzu.com/unix-linux-forum/kbhit-t34401.html

beastie ★★★★★
()
Ответ на: комментарий от question4

Спасибо, но не работает. Ждёт Enter.

Отключите сначала канонический режим и эхо (как в моем «мопеде» :) ).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Всё понимаю, но в рассматриваемом случае они не мешают.

question4 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.