#c #linux #terminal
#c #linux #терминал
Вопрос:
Я следую руководству по созданию собственного текстового редактора о том, как запрограммировать свой собственный текстовый редактор.
В настоящее время я нахожусь на низкоуровневом чтении нажатий клавиш и сопоставляю его с операциями редактора (раздел: Рефакторинг ввода с клавиатуры). Но когда я реализую то же самое в своем коде и запускаю его, мой терминал просто зависает, и мне приходится перезапускать, чтобы вернуться к нормальной жизни. Я использую Parrot OS (если это имеет значение). Вот соответствующий раздел моего исходного кода:
char editorReadKey() {
int nread;
char c;
while ((nread = read(STDIN_FILENO, amp;c, 1) != 1)) {
if (nread == -1 amp;amp; errno != EAGAIN)
die("read");
/*if (iscntrl(c))
printf("%drn", c);
else
printf("%d('%c')rn", c, c);
*/
}
return c;
}
void editorProcessKeypress() {
char c = editorReadKey();
switch (c) {
case CTRL_KEY('q') : exit(0);
break;
}
}
int main(void) {
enableRawMode();
while (1) {
editorProcessKeypress();
}
return 0;
Функции enableRawMode и disableRawMode не отличаются и более или менее являются точной реализацией руководства.
void disableRawMode() {
if(tcsetattr(STDIN_FILENO, TCSAFLUSH, amp;orig_termios) == -1)
die("tcsetattr");
}
void enableRawMode() {
if(tcgetattr(STDIN_FILENO, amp;orig_termios) == -1)
die("tcgetattr");
atexit(disableRawMode);
struct termios raw = orig_termios;
tcgetattr(STDIN_FILENO, amp;raw);
//turns off echoing the command on the screen
//turn off cannonical mode
raw.c_iflag amp;= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
raw.c_oflag amp;= ~(OPOST);
raw.c_cflag |= (CS8);
raw.c_lflag amp;= ~(ECHO | ICANON | IEXTEN | ISIG);
raw.c_cc[VMIN] = 0;
raw.c_cc[VTIME] = 1;
if(tcsetattr(STDIN_FILENO, TCSAFLUSH, amp;raw) == -1)
die("tcsetattr");
}
Какие-либо причины, по которым это может происходить? Или я делаю что-то не так?
РЕДАКТИРОВАТЬ: добавлено возвращаемое значение, к editorReadKey()
которому я как-то пропустил его здесь.
Комментарии:
1. Начните с
int c;
и, вероятно, вы используете termcap или curses: по крайней мере, добавьте соответствующие заголовки.2. @wildplasser
int c;
— не в этот раз3. Итак, что вы имели в виду под «зависанием терминала»? У вас там есть клавиша
ctrl q
выхода, ты нажалctrl q
?!4. @wildplasser уже пробовал то же самое. Проблема по-прежнему сохраняется.
5.
editorReadKey
необходимо вернуть значение.
Ответ №1:
Ctrl-S и Ctrl-Qиспользуются для приостановки и возобновления вывода на консоль в готовом режиме, что может объяснить ваши наблюдения, хотя вы отключаете этот режим, отключив IXON
raw.c_iflag
его . Настройки VMIN
and VTIME
также могут быть неверными: установка VMIN
нуля кажется неправильной.
В Quick Emacs я использую этот код для настройки режима raw:
tcgetattr(fileno(s->STDIN), amp;tty);
ts->oldtty = tty;
/* input modes: no break, no CR to NL, no parity check, no strip char,
* no start/stop output control. */
tty.c_iflag amp;= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON |
IGNBRK | PARMRK | INLCR | IGNCR);
/* output modes - enable post processing? */
tty.c_oflag amp;= ~(OPOST);
/* control modes - set 8 bit chars, no parity checking */
tty.c_cflag amp;= ~(CSIZE | PARENB);
tty.c_cflag |= CS8;
/* local modes - echoing off, canonical off, no extended functions,
* no signal chars (^Z,^C) */
tty.c_lflag amp;= ~(ECHO | ICANON | IEXTEN | ISIG | ECHONL);
/* control chars - set return condition: min number of bytes and timer.
* We want read to return every single byte, without timeout. */
tty.c_cc[VMIN] = 1; /* 1 byte */
tty.c_cc[VTIME] = 0; /* no timer */
tcsetattr(fileno(s->STDIN), TCSANOW, amp;tty);
Подробное объяснение флагов можно найти на странице руководства Linux для termios.
Комментарии:
1. Я ценю объяснение. Но я не понимаю, как
VMIN = 0
здесь может быть неправильно. Я установил его равным нулю, потому что я хочуread()
, чтобы он возвращался, как только ввод считывается. Я должен добавить, что код работал отлично, пока я не дошел доRefactor Keyboard Input
части руководства, а затем он начал вести себя странно. Я не понимаю, почему это может происходить.