Прерывание по нажатию клавиши (Прерывание по нажатию клавиши)
Модератор: Модераторы разделов
-
serzz
- Сообщения: 6
Прерывание по нажатию клавиши
Пишется прогамма для запуска в терминальном режиме. Она должна непрерывно работать, а по нажатию любой (или не любой) клавиши выходить из цикла в некоторый новый режим. Что-то оператора подходящего не нашел. Кто знает, как выйти из цикла по нажатию клавиши? Под ОС/2 цикл выглядел так
while(!kbhit())
{
....
}
А под Линукс что? kbhit отсутствует
while(!kbhit())
{
....
}
А под Линукс что? kbhit отсутствует
-
Zmoukie
- Сообщения: 29
Re: Прерывание по нажатию клавиши
#include <conio.h>
..................
while (!_getch())
{
//нажали
}
..................
while (!_getch())
{
//нажали
}
-
serzz
- Сообщения: 6
Re: Прерывание по нажатию клавиши
(Zmoukie @ Вторник, 30 Ноября 2004, 20:52) писал(а):#include <conio.h>
..................
while (!_getch())
{
//нажали
}
так ведь #include <conio.h> в линуксе отсутсвует, или я чего не понимаю?
serzz добавил в 30.11.2004 23:13
(Ananas @ Вторник, 30 Ноября 2004, 13:39) писал(а):man getch
Пробуем написать test.c
#include <curses.h>
int q;
int main()
{
q = getch();
return q;
}
компилируем gcc -o qq test.c
Запускаем ./qq
Получаем
/tmp/cc8dspXP.o(.text+0x15): In function `main':
: undefined reference to `stdscr'
/tmp/cc8dspXP.o(.text+0x1a): In function `main':
: undefined reference to `wgetch'
collect2: ld returned 1 exit status
Где грабли?
-
nercus
- Сообщения: 150
Re: Прерывание по нажатию клавиши
может стоит посмотреть в сторону select(2)?
2.6.14-gentoo-r5
kde-3.5.0 | openbox-3.2
Deep Purple | Rob Zombie | Led Zeppelin | ДДТ
kde-3.5.0 | openbox-3.2
Deep Purple | Rob Zombie | Led Zeppelin | ДДТ
-
nercus
- Сообщения: 150
Re: Прерывание по нажатию клавиши
Не, ncurses это конечно хорошо, но нафига ее тянуть за собой, если надо только клавишу считать... Тем более в man 2 select приведен пример, практически полностью соответствующий задаче - только таймаут поставить не 5 секунд, конечно, и в цикл завернуть.
2.6.14-gentoo-r5
kde-3.5.0 | openbox-3.2
Deep Purple | Rob Zombie | Led Zeppelin | ДДТ
kde-3.5.0 | openbox-3.2
Deep Purple | Rob Zombie | Led Zeppelin | ДДТ
-
serzz
- Сообщения: 6
Re: Прерывание по нажатию клавиши
(Ananas @ Среда, 01 Декабря 2004, 14:38) писал(а):gcc -lncurses test.c
Ну да, правильно. Делаю, запускаю вышеозначенную программу, получаю
Segmentation fault
Где грабли на этот раз?
serzz добавил в 01.12.2004 19:26
(nercus @ Среда, 01 Декабря 2004, 18:38) писал(а):Не, ncurses это конечно хорошо, но нафига ее тянуть за собой, если надо только клавишу считать... Тем более в man 2 select приведен пример, практически полностью соответствующий задаче - только таймаут поставить не 5 секунд, конечно, и в цикл завернуть.
Так вроде бы select останавливается на заданное время и ожидает нажатие. Т.е. если его встроить в цикл, в котором много других дел делается, то возникают потери времени на остановку и придется успеть нажать во время остановки, иначе опять в цикл вернемся. Так?
-
brazhe
- Сообщения: 89
Re: Прерывание по нажатию клавиши
А если задача ещё сложнее? Например, программа получает поток данных через stdin, выводит куда-нибудь, а нужна возможность её по нажатию клавиши остановить, при этом правильно освободив занятую память. Такое возможно?
Ni Ansa
My LJ: Журнал мечтательного биофизика
My LJ: Журнал мечтательного биофизика
-
nercus
- Сообщения: 150
Re: Прерывание по нажатию клавиши
(serzz @ Среда, 01 Декабря 2004, 19:26) писал(а):Так вроде бы select останавливается на заданное время и ожидает нажатие. Т.е. если его встроить в цикл, в котором много других дел делается, то возникают потери времени на остановку и придется успеть нажать во время остановки, иначе опять в цикл вернемся. Так?
Во-первых, "потери на остановку" - afaik можно поставить нулевой таймаут. Во-вторых, "успеть нажать" не надо - ключевое слово: "буферизованный io".
К сожалению, из-за этого самого буферизованного io , работать это будет не совсем так, как надо. То есть, чтение ввода будет только после <CR>.
Чуть сложнее, но как вариант, можно так (вроде все по POSIX):
Код: Выделить всё
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
int
main(int argc, char **argv) {
int c;
struct termios tio;
tcflag_t old_lf;
long old_fl;
/* fgetc() won't block */
old_fl = (long) fcntl(0, F_GETFL);
fcntl(0, F_SETFL, O_NONBLOCK);
/* disable buffering by lines... and some more. see termios(2) */
tcgetattr(0, &tio);
old_lf = tio.c_lflag;
tio.c_lflag &= ~(ICANON | ECHO);
tcsetattr(0, TCSANOW, &tio);
while (EOF == (c = fgetc(stdin))) {
/* do something good unless key is pressed */
}
printf("User pressed key 0x%02x\n", c);
/* be a good boy and restore initial settings */
tcgetattr(0, &tio);
tio.c_lflag = old_lf;
tcsetattr(0, TCSANOW, &tio);
fcntl(0, F_SETFL, old_fl);
return 0;
}Хотя, конечно, если использовать ncurses, то попроще
(brazhe @ Среда, 01 Декабря 2004, 19:47) писал(а):А если задача ещё сложнее? Например, программа получает поток данных через stdin, выводит куда-нибудь, а нужна возможность её по нажатию клавиши остановить, при этом правильно освободив занятую память. Такое возможно?
Вполне возможно. signal(2), signal(7) - см сигнал SIGINT. Только это если под нажатием клавиши понимать ^c
А вот если не ^c - то это либо выставлять tio.c_cc[VINTR] (tio - это в контексте приведенного выше кода) в любой понравившийся символ, либо никак
2.6.14-gentoo-r5
kde-3.5.0 | openbox-3.2
Deep Purple | Rob Zombie | Led Zeppelin | ДДТ
kde-3.5.0 | openbox-3.2
Deep Purple | Rob Zombie | Led Zeppelin | ДДТ
-
serzz
- Сообщения: 6
Re: Прерывание по нажатию клавиши
Код: Выделить всё
#include <curses.h>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
int
main(int argc, char **argv) {
int c;
struct termios tio;
tcflag_t old_lf;
long old_fl;
/* fgetc() won't block */
old_fl = (long) fcntl(0, F_GETFL);
fcntl(0, F_SETFL, O_NONBLOCK);
/* disable buffering by lines... and some more. see termios(2) */
tcgetattr(0, &tio);
old_lf = tio.c_lflag;
tio.c_lflag &= ~(ICANON | ECHO);
tcsetattr(0, TCSANOW, &tio);
while (EOF == (c = fgetc(stdin))) {
/* do something good unless key is pressed */
}
printf("User pressed key 0x%02x\n", c);
/* be a good boy and restore initial settings */
tcgetattr(0, &tio);
tio.c_lflag = old_lf;
tcsetattr(0, TCSANOW, &tio);
fcntl(0, F_SETFL, old_fl);
return 0;
}Кудряво и затейливо (по сравнению с !kbhit()), но ведь работает, да еще и нажатую клавишу определяет, спасибо! Пойду вставлять это в свою программу. А тем временем из любви к искусству попроще кто-нибудь предложить не сможет? Если, например, нажатую клавишу анализировать не обязательно, а нажатие нужно лишь для прервания цикла.
serzz добавил в 03.12.2004 00:54
А вот попытка краткого варианта:
Код: Выделить всё
#include <curses.h>
int main() {
while (!_getch())
{
//Нажали
}
return 0;
}имеем ошибку на стадии компиляции
$ gcc -o qq test.c -lcurses
/tmp/ccUn34EP.o(.text+0x11): In function `main':
: undefined reference to `_getch'
collect2: ld returned 1 exit status
Наученные опытом делаем по-другому
Код: Выделить всё
#include <curses.h>
int main() {
while (!getch())
{
//нажали
}
return 0;
}$ gcc -o qq test.c -lcurses
Segmentation fault
Аналогичный результат с -lncurses
В цикл для разнообразия и заполнения пустоты вставлял sleep(1); (+ #include <unistd.h>) - не помогает. Где выход из этого густого леса в три сосны?
:helpsmilie:
-
nercus
- Сообщения: 150
Re: Прерывание по нажатию клавиши
2serzz:
man ncurses:
... и далее по тексту
man ncurses:
Код: Выделить всё
.........
To initialize the routines, the routine initscr or newterm must be called
before any of the other routines that deal with windows and screens are
used. The routine endwin must be called before exiting. To get charac-
ter-at-a-time input without echoing (most interactive, screen oriented
programs want this), the following sequence should be used:
initscr(); cbreak(); noecho();
............ и далее по тексту
2.6.14-gentoo-r5
kde-3.5.0 | openbox-3.2
Deep Purple | Rob Zombie | Led Zeppelin | ДДТ
kde-3.5.0 | openbox-3.2
Deep Purple | Rob Zombie | Led Zeppelin | ДДТ
-
serzz
- Сообщения: 6
Re: Прерывание по нажатию клавиши
2nercus
Спасибо! В man ncurses действительно есть ответы на все вопросы.
Спасибо! В man ncurses действительно есть ответы на все вопросы.