asciimation

An ASCII animation interpreter for the terminal.


asciimation

/

src

/

term.hh

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
#ifndef OB_TERM_HH
#define OB_TERM_HH

#include "ansi_escape_codes.hh"
namespace AEC = OB::ANSI_Escape_Codes;

#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <stdexcept>
#include <iostream>
#include <cstdio>
#include <thread>
#include <chrono>

namespace OB
{

class Term
{
public:
  Term()
  {
    cursor_hide();
    set_raw();
  }

  ~Term()
  {
    cursor_show();
    set_cooked();
  }

  void set_cooked()
  {
    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_) == -1)
    {
      throw std::runtime_error("tcsetattr failed");
    }
  }

  void set_raw()
  {
    if (tcgetattr(STDIN_FILENO, &old_) == -1)
    {
      throw std::runtime_error("tcgetattr failed");
    }

    raw_ = old_;
    raw_.c_lflag &= ~(ECHO | ICANON);
    raw_.c_cc[VMIN]  = 0;
    raw_.c_cc[VTIME] = 0;

    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_) == -1)
    {
      throw std::runtime_error("tcsetattr failed");
    }
  }

  static void cursor_hide()
  {
    std::cout << AEC::cursor_hide << std::flush;
  }

  static void cursor_show()
  {
    std::cout << AEC::cursor_show << std::flush;
  }

  static size_t height()
  {
    struct winsize w;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
    return w.ws_row;
  }

  static size_t width()
  {
    struct winsize w;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
    return w.ws_col;
  }

  static void size(size_t &width, size_t &height)
  {
    struct winsize w;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
    width = w.ws_col;
    height = w.ws_row;
  }

  static int cursor_get(size_t& width, size_t& height)
  {
    std::cout << "\033[6n" << std::flush;
    char buf[32];
    uint8_t i = 0;
    for (;i < sizeof(buf) -1; ++i)
    {
      while (read(STDIN_FILENO, &buf[i], 1) != 1)
      {
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
      }
      if (buf[i] == 'R') break;
    }
    buf[i] = '\0';
    if (buf[0] != '\x1b' || buf[1] != '[') return -1;
    int x;
    int y;
    if (sscanf(&buf[2], "%d;%d", &y, &x) != 2) return -1;
    width = x;
    height = y;
    return 0;
  }

private:
  termios old_;
  termios raw_;

}; // class Term

} // namespace OB

#endif // OB_TERM_HH
Back to Top