Ответ 1
getch() из библиотеки Curses возможно? Кроме того, вам нужно будет использовать notimeout(), чтобы сообщить getch(), чтобы не ждать следующего нажатия клавиши.
Я использую консоль Linux, и я хотел бы сделать программу, которая выводит случайные символы до нажатия ESC. Как я могу сделать такой обработчик клавиатуры?
getch() из библиотеки Curses возможно? Кроме того, вам нужно будет использовать notimeout(), чтобы сообщить getch(), чтобы не ждать следующего нажатия клавиши.
Линейная дисциплина для терминального устройства по умолчанию работает в каноническом режиме. В этом режиме драйвер терминала не представляет буфер для пользовательского пространства до тех пор, пока не увидит новую строку (нажата клавиша Enter).
Вы можете установить терминал в необработанный (неканонический) режим, используя tcsetattr()
для управления структурой termios
. Очистка флагов ECHO
и ICANON
соответственно отключает эхо-символы символов при их вводе и вызывает запросы чтения непосредственно из входной очереди. Установка значений VTIME
и VMIN
в ноль в массиве c_cc
заставляет запрос чтения (fgetc()
) немедленно возвращаться, а не блокировать; эффективно опрос stdin. Вызов fgetc()
возвращает EOF
, если символ недоступен в потоке.
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
int getkey() {
int character;
struct termios orig_term_attr;
struct termios new_term_attr;
/* set the terminal to raw mode */
tcgetattr(fileno(stdin), &orig_term_attr);
memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
new_term_attr.c_lflag &= ~(ECHO|ICANON);
new_term_attr.c_cc[VTIME] = 0;
new_term_attr.c_cc[VMIN] = 0;
tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
/* read a character from the stdin stream without blocking */
/* returns EOF (-1) if no character is available */
character = fgetc(stdin);
/* restore the original terminal attributes */
tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);
return character;
}
int main()
{
int key;
/* initialize the random number generator */
srand(time(NULL));
for (;;) {
key = getkey();
/* terminate loop on ESC (0x1B) or Ctrl-D (0x04) on STDIN */
if (key == 0x1B || key == 0x04) {
break;
}
else {
/* print random ASCII character between 0x20 - 0x7F */
key = (rand() % 0x7F);
printf("%c", ((key < 0x20) ? (key + 0x20) : key));
}
}
return 0;
}
Примечание. Этот код пропускает проверку ошибок для простоты.
измените настройки tty для одного нажатия клавиши:
int getch(void) {
int c=0;
struct termios org_opts, new_opts;
int res=0;
//----- store old settings -----------
res=tcgetattr(STDIN_FILENO, &org_opts);
assert(res==0);
//---- set new terminal parms --------
memcpy(&new_opts, &org_opts, sizeof(new_opts));
new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL);
tcsetattr(STDIN_FILENO, TCSANOW, &new_opts);
c=getchar();
//------ restore old settings ---------
res=tcsetattr(STDIN_FILENO, TCSANOW, &org_opts);
assert(res==0);
return(c);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
char * me = "Parent";
void sigkill(int signum)
{
//printf("=== %s EXIT SIGNAL %d ===\n", me, signum);
exit(0);
}
main()
{
int pid = fork();
signal(SIGINT, sigkill);
signal(SIGQUIT, sigkill);
signal(SIGTERM, sigkill);
if(pid == 0) //IF CHILD
{
int ch;
me = "Child";
while(1)
{
ch = (rand() % 26) + 'A'; // limit range to ascii A-Z
printf("%c",ch);
fflush(stdout); // flush output buffer
sleep(2); // don't overwhelm
if (1 == getppid())
{
printf("=== CHILD EXIT SINCE PARENT DIED ===\n");
exit(0);
}
}
printf("==CHILD EXIT NORMAL==\n");
}
else //PARENT PROCESS
{
int ch;
if((ch = getchar())==27)
kill(pid, SIGINT);
//printf("==PARENT EXIT NORMAL (ch=%d)==\n", ch);
}
return(0);
}
В этой программе u нужно только нажать enter
после esc
char, потому что getchar()
является блокирующей функцией.
Кроме того, u может удалить или уменьшить время сна для дочернего процесса по мере необходимости.