#c #linux #terminal
#c #linux #терминал
Вопрос:
Я пытаюсь прочитать ввод от пользователя в необработанном режиме терминала.
Вот функция, которая включает режим raw и отключает некоторые escape-символы и все. Он также ссылается на disableRawMode, который используется для повторного входа в канонический режим после считывания входных данных:
void enableRawMode() {
if (tcgetattr(STDIN_FILENO, amp;orig_termios) == -1)
die("tcgetattr");
atexit(disableRawMode);
struct termios raw = orig_termios;
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 amp; editorprocessKeypress) для считывания нажатия клавиши и обработки ввода символов:
char editorReadKey() {
int nread;
char c;
while ((nread = read(STDIN_FILENO, amp;c, 1) != 1)) {
if (nread == -1 amp;amp; errno != EAGAIN)
die("read");
}
}
void editorProcessKeypress() {
char c = editorReadKey();
switch (c) {
case CTRL_KEY('q'):
exit(0);
break;
}
}
Но когда я вызываю функции в основной программе:
int main(void) {
enableRawMode();
while (1) {
editorRefreshScreen();
editorProcessKeypress();
}
return 0;
}
Мой терминал просто зависает, и я должен перезапустить его, чтобы он снова заработал. Какие-либо причины, по которым это может происходить?
Комментарии:
1. Существует разница между «при компиляции» и «при запуске».
2. Если вы вставляете вывод в бесконечный цикл внутри
main()
, как часто вы видите этот вывод?3. Извините за это. Так получилось, что английский не является моим родным языком, и я все еще привыкаю к нему. Отредактировал вопрос.
4. @Yunnosch Я использую бесконечный цикл только потому, что хочу считывать входные данные до нажатия кнопки «q». В этом случае, я полагаю, цикл завершится.
5. Вы ничего не возвращаете
editorReadKey()
, и компилятор C просто принимает это. Это означает, что ни одна из ваших операций с ключами никогда не срабатывает, поэтому ваш код никогда ничего не делает и поэтому выглядит замороженным. Всегда создавайте код на C с-Wall
Ответ №1:
Возможно, этот пример делает то, что вы хотите. Вывод минимален, поскольку в этом суть 🙂
terminal info saved
raw mode will be set now
Enter 'q' to exit!
terminal configuration restored
Программа просто сохраняет конфигурацию терминала, переходит в режим raw и считывает данные с ввода до тех пор, пока не будет прочитан «q» или пользователь не нажмет control-C. Затем терминал сбрасывается и конфигурация восстанавливается.
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
typedef struct termios Termios;
void editorProcessKeypress();
char editorReadKey();
void editorRefreshScreen();
void enableRawMode(Termios*);
void gameOver();
int getMode(Termios*);
int setMode(Termios*);
int main(void)
{
Termios original_termios;
Termios raw;
if ( getMode(amp;original_termios) < 0)
{
fprintf(stderr,"Could not get terminal info");
return(-1);
}
printf("terminal info savedn");
enableRawMode(amp;raw);
printf("Enter 'q' to exit!n");
editorRefreshScreen();
char in = editorReadKey();
while( in != 'q' )
{
editorRefreshScreen();
in = editorReadKey();
};
if ( setMode(amp;original_termios) < 0)
{
fprintf(stderr,"Could not reset terminal. Please run 'tput reset'!");
return(-1);
}
printf("nterminal configuration restoredn");
return 0;
};
void enableRawMode(Termios* raw)
{
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[VINTR] = 3;
raw->c_cc[VMIN] = 0;
raw->c_cc[VTIME] = 10;
signal(SIGINT, gameOver);
printf("raw mode will be set nown");
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, raw) < 0)
printf("raw mode NOT set!!n");
fflush(stdin);
};
char editorReadKey() {
int nread;
char c = 0;
while ((nread = read(STDIN_FILENO, amp;c, 1) != 1)) {
if (nread == -1 amp;amp; errno != EAGAIN)
return 0;
};
return c;
};
void editorRefreshScreen()
{
return;
};
void gameOver()
{
Termios reset;
reset.c_iflag = ~IGNCR | ICRNL | INPCK | ISTRIP | IXON | BRKINT | ICANON;
reset.c_oflag = ECHO | OPOST;
reset.c_lflag = ECHO | ICANON | IEXTEN;
tcsetattr(STDIN_FILENO, TCSANOW, amp;reset);
printf("n^C: Aborting... Issue a 'tput reset' if terminal not okn");
exit(1);
};
int getMode( Termios* term )
{
return tcgetattr(STDIN_FILENO, term);
};
int setMode(Termios* term)
{
return tcsetattr(STDIN_FILENO, TCSANOW, term);
};