Как использовать ввод, одновременно перехватывая нажатия стрелок (C++, Linux)

Я пишу CLI программу и при нажатии стрелок вверх/вниз должна прокручиваться история команд. Но есть проблема: при использовнии std::getline и std::cin невозможно перехватить их нажатие. Единственное, до чего я додумался, это реализовать цикл с функцией getchar, но получается относительно раздутый код:

constexpr int ENTER_KEY_CODE = 10;
constexpr int ARROW_KEY_CODE_SEQUENCE_1 = 27;
constexpr int ARROW_KEY_CODE_SEQUENCE_2 = 91;
constexpr int UP_ARROW_KEY_CODE = 65;
constexpr int DOWN_ARROW_KEY_CODE = 66;
constexpr int BACKSPACE_KEY_CODE = 127;

static std::string read() noexcept
{
  std::string input;
  int inputCode = 0;
  while (inputCode != ENTER_KEY_CODE)
  {
    inputCode = getchar();
    switch (inputCode)
    {
    case ARROW_KEY_CODE_SEQUENCE_1:
      if (getchar() == ARROW_KEY_CODE_SEQUENCE_2)
      {
        switch (getchar())
        {
        case UP_ARROW_KEY_CODE:
          /* ... */
          break;
        case DOWN_ARROW_KEY_CODE:
          /* ... */
          break;
        }
      }
      break;
    case ENTER_KEY_CODE:
      /* ... */
      break;
    case BACKSPACE_KEY_CODE:
      /* ... */
      break;
    default:
      /* ... */
      break;
    }
  }
  return std::move(input);
}

Как перехватить нажатие стрелок при вводе? Только без (n)curses.


Ответы (1 шт):

Автор решения: user589514

Да, я думал в верном направлении: без (n)curses всё делается вручную вместе с перехватом нажатий на Backspace, Enter и т.д. Вот как это примерно выглядит:

constexpr int ENTER_KEY_CODE = 10;
constexpr int ARROW_KEY_CODE_SEQUENCE_1 = 27;
constexpr int ARROW_KEY_CODE_SEQUENCE_2 = 91;
constexpr int UP_ARROW_KEY_CODE = 65;
constexpr int DOWN_ARROW_KEY_CODE = 66;
constexpr int BACKSPACE_KEY_CODE = 127;

static std::string read() noexcept
{
  std::string input;
  int inputCode = 0;
  while (inputCode != ENTER_KEY_CODE)
  {
    inputCode = getchar();
    switch (inputCode)
    {
    case ARROW_KEY_CODE_SEQUENCE_1:
      if (getchar() == ARROW_KEY_CODE_SEQUENCE_2)
      {
        switch (getchar())
        {
        case UP_ARROW_KEY_CODE:
          /* ... */
          break;
        case DOWN_ARROW_KEY_CODE:
          /* ... */
          break;
        }
      }
      break;
    case ENTER_KEY_CODE:
      std::cout << std::endl;
      break;
    case BACKSPACE_KEY_CODE:
      input = std::move(input.substr(1, input.size()));
      std::cout << "\b \b";
      break;
    default:
      input += inputCode;
      std::cout << (char)inputCode;
      break;
    }
  }
  return std::move(input);
}

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

Update: Как подсказали в комментариях, можно использовать библиотеку GNU Readline, что тоже подойдет для решения данной проблемы.

→ Ссылка