Вместо того, чтобы пытаться заставить ungetc()
разблокировать блокирующий вызов fgetc()
с помощью сигнала, возможно, вы могли бы попытаться не иметь блока fgetc()
для начала и подождать активности на stdin, используя select()
.
По умолчанию дисциплина линии для оконечного устройства может работать в каноническом режиме. В этом режиме драйвер терминала не представляет буфер пользовательскому пространству до появления новой строки (нажата клавиша Enter ).
Чтобы выполнить то, что вы хотите, вы можете установить терминал в необработанный (неканонический) режим, используя <a href="http://www.opengroup.org/onlinepubs/000095399/functions/tcsetattr.html" rel="noreferrer"><b>tcsetattr()</b></a>
для управления структурой 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