Вместо того, чтобы пытаться заставить ungetc()
разблокировать блокирующий вызов fgetc()
с помощью сигнала, возможно, вы могли бы попробовать не иметь блока fgetc()
с самого начала и дождаться активности на стандартном вводе с помощью select()
.
По умолчанию линейная дисциплина для терминального устройства может работать в каноническом режиме. В этом режиме драйвер терминала не представляет буфер пользовательскому пространству до тех пор, пока не будет видна новая строка (нажата клавиша Enter).
Чтобы выполнить то, что вы хотите, вы можете установить терминал в необработанный (неканонический) режим, используя tcsetattr()
для управления структурой termios
. Это должно привести к тому, что блокирующий вызов fgetc()
немедленно вернет символ, вставленный с помощью ungetc()
.
void handler(int sig) {
/* I know I shouldn't do this in a signal handler,
* but this is modeled after the OP's code.
*/
ungetc('A', stdin);
}
void wait_for_stdin() {
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fileno(stdin),&fdset);
select(1, &fdset, NULL, NULL, NULL);
}
void foo () {
int key;
struct termios terminal_settings;
signal(SIGUSR1, handler);
/* set the terminal to raw mode */
tcgetattr(fileno(stdin), &terminal_settings);
terminal_settings.c_lflag &= ~(ECHO|ICANON);
terminal_settings.c_cc[VTIME] = 0;
terminal_settings.c_cc[VMIN] = 0;
tcsetattr(fileno(stdin), TCSANOW, &terminal_settings);
for (;;) {
wait_for_stdin();
key = fgetc(stdin);
/* terminate loop on Ctrl-D */
if (key == 0x04) {
break;
}
if (key != EOF) {
printf("%c\n", key);
}
}
}
ПРИМЕЧАНИЕ. В этом коде для простоты опущена проверка ошибок.
Сброс флагов ECHO
и ICANON
соответственно отключает отображение символов по мере их ввода и приводит к тому, что запросы на чтение выполняются непосредственно из входной очереди. . Установка нулевых значений VTIME
и VMIN
в массиве c_cc
приводит к тому, что запрос на чтение (fgetc()
) возвращается немедленно, а не блокируется; эффективно опрашивая стандартный ввод. Это приводит к тому, что key
устанавливается в EOF
, поэтому необходим другой метод завершения цикла. Ненужный опрос стандартного ввода уменьшается за счет ожидания активности на стандартном вводе с использованием select()
.
Выполнение программы, отправка сигнала SIGUSR1
и ввод t e s t приводит к следующему результату1:
A
t
e
s
t
1) протестировано на Linux
person
jschmier
schedule
15.04.2010