Перехват клавиш со стрелками с помощью TermCaps

В настоящее время я работаю над полной оболочкой, построенной на C.

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

Вот как я настроил свой терминал:

static int      set_terminal_mode(t_shell *shell, const int mode)
 {
   char          *term_name;

   if (mode == 0)
     {
       if ((term_name = getenv("TERM")) == NULL)
         return (-1);
       ioctl(0, TCGETS, &shell->term);
       shell->term.c_lflag &= ~ICANON;
       shell->term.c_cc[VMIN] = 1;
       shell->term.c_cc[VTIME] = 0;                                         
       ioctl(0, TCGETS, &shell->term_save);
       ioctl(0, TCSETS, &shell->term);
     }
   if (mode == 1)
     ioctl(0, TCSETS, &shell->term_save);
   return (0);
 }

Я могу поймать, когда нажата левая или правая клавиша, а затем я использую \r, чтобы стереть строку (что на самом деле не работает), но основная проблема в том, что я больше не могу использовать клавишу возврата (отображается только ^?). Как я могу это исправить ?


person rak007    schedule 31.05.2016    source источник


Ответы (1)


Эта линия

       shell->term.c_lflag &= ~ICANON;

отключает канонический режим, который согласно POSIX< /a> делает несколько вещей, включая отключение буферизации строк, что включает специальную обработку возврата каретки:

При обработке ввода в неканоническом режиме входные байты не собираются в строки, и обработка стирания и уничтожения не должна выполняться.

а также

CR
Специальный символ при вводе, который распознается, если установлен флаг ICANON; это символ возврата каретки. Если ICANON и ICRNL установлены, а IGNCR не задано, этот символ будет преобразован в NL, и будет иметь тот же эффект, что и символ NL.

Если вы хотите читать отдельные байты (для клавиш курсора), вам придется обрабатывать однобайтовые управляющие символы, такие как возврат каретки (CR) и перевод строки (называемый NL или новой строкой).

Кстати, в вашем примере сохраненные/измененные настройки меняются местами: вызов

     ioctl(0, TCSETS, &shell->term_save);

использует настройки терминала, сохраненные в

       ioctl(0, TCGETS, &shell->term_save);

то есть после того, как вы уже изменили настройки терминала.

person Thomas Dickey    schedule 08.06.2016