Intereting Posts
Обнаружение присутствия или отсутствия аргументов в макросе C В чем разница между указателем на массив и указателем на указатель? Является ли этот код действительным при любом стандарте C? Как выполнить функцию из ОЗУ на Cortex-M3 (STM32)? Является ли это сомнительным использование объявления не-прототипа функции? gcc warning: скобки вокруг скалярного инициализатора Как написать один файл makefile, c файлы находятся в src, а файлы h находятся в папке inc? C – битный файл fwrite размером более 4 ГБ заполнение динамически выделенного массива строк? C strtok () разделяет строку на токены, но сохраняет старые данные без изменений Что здесь происходит в этом цикле C инициализация глобальной статической переменной выполняется компоновщиком? Выделение памяти и ее освобождение. Должны ли мы установить их в NULL? Вычисление обратной матрицы, использующей lapack в C Почему scanf застревает в бесконечном цикле с недопустимым вводом?

Как считывать входной буфер терминала сразу после нажатия клавиши

Я хочу читать стрелочные клавиши в моей программе c и заменять их (сразу в самом терминале) другой строкой. Я пытаюсь реализовать функциональность истории bash, как в терминалах unix. Я написал этот код.

int main(int argc, char *argv[]) { char c; char str[1024]; int i = 0; while((c = fgetc(stdin)) != '\n'){ if(((int)c) == 27){ c=fgetc(stdin); c=fgetc(stdin); if (c == 'A') { printf("%c[A%c[2K",27, 27); printf("UP"); } } str[i++] = c; } printf("\n"); return 0; } 

Но это не работает, потому что терминалы ожидают, что новая строка или EOF отправят входной буфер в stdin. Поэтому я должен нажать клавишу ввода / возврата, чтобы проанализировать ввод пользователя.

Здесь в этом ответе пользователь упомянул использовать system ("/bin/stty raw"); но это заменяет все по умолчанию поведение терминала (например, backspace, delete и т. д.).

Итак, есть ли способ, которым я могу напрямую читать / манипулировать входным буфером терминалов и настраивать сам буфер, если обнаружено стрелочное нажатие?

Окружающая среда – Ubuntu (Linux)

Обновление 1: существует ли способ изменения сигнала / прерывания (по умолчанию используется клавиша ввода), что заставляет терминал отправлять сохраненный вход в буфер? Это также может помочь мне достичь такого же поведения.

Итоговый код:

Я узнал символы ASCII для конкретных нажатий клавиш, проверив вывод strace bash

 #include  #include  #include  #include  #include  #include  #define ESCAPE '\33' #define BACKSPACE '\177' #define DELETE '~' int main(){ struct termios termios_p; struct termios termios_save; tcgetattr(0, &termios_p); termios_save = termios_p; termios_p.c_lflag &= ~(ICANON|ECHO); tcsetattr(0,TCSANOW, &termios_p); char buff; while(read(0, &buff, 1) >= 0){ if(buff > 0){ if(buff == ESCAPE){ read(0, &buff, 1); read(0, &buff, 1); if(buff == 'A'){ write(2, "up", 2); }else if(buff == 'B'){ write(2, "down", 4); }else if(buff == 'C'){ write(2, "\33[C", 3); }else if(buff == 'D'){ write(2, "\10", 2); } }else if(buff == BACKSPACE){ write(2, "\10\33[1P", 5); }else if(buff == DELETE){ write(2, "\33[1P", 4); }else{ write(2,&buff,1); } // write(2,&buff,1); if(buff == 'q'){ break; } } } tcsetattr(0,TCSANOW, &termios_save); return 0; } 

Кажется, вы ищете что-то подобное.

Программа по существу ждет ввода пользователя. Если нажать клавишу со стрелкой вверх, программа напечатает «Стрелка нажата», а затем выйдет. Если что-либо еще нажата, он ждет, когда пользователь выполнит ввод и распечатает его, а затем выйдет.

 #include  #include  #include  #include  int main() { struct termios oldt, newt; char ch, command[20]; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); while(1) { ch = getchar(); if (ch == '\033') { printf("Arrow key\n"); ch=-1; break;} else if(ch == -1) // by default the function returns -1, as it is non blocking { continue; } else { break; } } tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF) { ungetc(ch,stdin);ith putchar(ch); scanf("%s",command); printf("\n%s\n",command); return 1; } return 0; } в #include  #include  #include  #include  int main() { struct termios oldt, newt; char ch, command[20]; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); while(1) { ch = getchar(); if (ch == '\033') { printf("Arrow key\n"); ch=-1; break;} else if(ch == -1) // by default the function returns -1, as it is non blocking { continue; } else { break; } } tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF) { ungetc(ch,stdin);ith putchar(ch); scanf("%s",command); printf("\n%s\n",command); return 1; } return 0; } 

На моей машине Linux я использую ncurses:

 #include #include void checkArrow(){ int ch; initscr(); raw(); keypad(stdscr, TRUE); noecho(); printw("Press q to Exit\t"); do{ switch(ch){ case KEY_UP: { printw("\n\nUp Arrow\n"); printw("Press q to Exit\t"); break; } case KEY_DOWN:{ printw("\n\nDown Arrow\n"); printw("Press q to Exit\t"); break; } case KEY_LEFT:{ printw("\n\nLeft Arrow\n"); printw("Press q to Exit\t"); break; } case KEY_RIGHT:{ printw("\n\nRight Arrow\n"); printw("Press q to Exit\t"); break; } } }while((ch = getch()) != 'q'); printw("\n\n\t\t\t-=GoodBye=-!\n"); refresh(); endwin(); } int main(){ checkArrow(); return 0; } 
 Up Arrow Press q to Exit 
 Down Arrow Press q to Exit Left Arrow Press q to Exit Right Arrow Press q to Exit