getch-termios.cpp

(plain text)
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
#include <iostream>
#include <cstring> 
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>

class noncopyable {
 protected:
  noncopyable () { }
  ~noncopyable () { }

 private:
  noncopyable (const noncopyable &);
  noncopyable &operator= (const noncopyable &);
};

class backup_termios : noncopyable {
 public:
  explicit backup_termios (int fd = STDIN_FILENO)
    : myFd(fd) { tcgetattr(myFd, &myAttr); }
  int fd () const { return myFd; }
  const termios &attr () const { return myAttr; }
  ~backup_termios () { tcsetattr(myFd, TCSANOW, &myAttr); }

 private:
  int myFd;
  termios myAttr;
};

void set_flags (tcflag_t flags, bool enabled = true, int fd = STDIN_FILENO);
void echo      (bool enabled = true, int fd = STDIN_FILENO);
void buffer    (bool enabled = true, int fd = STDIN_FILENO);
bool kbhit     (int usec = 0, int fd = STDIN_FILENO);
int  getch     (int fd = STDIN_FILENO);

// ################################################################ //

int main () {
  backup_termios backup_stdin;
  buffer(false);
  echo(false);

  while (true) {
    static const char batons[] = { '-', '\\', '|', '/' };
    enum { n_batons = 4 };

    int baton = 0;

    while (std::cout.put(batons[baton]).put('\b').flush() && !kbhit(100000)) {
      baton = (baton + 1) % n_batons;
    }

    std::cout.write(" \b", 2).put(getch()).flush();
  }
}

// ################################################################ //

void set_flags (tcflag_t flags, bool enable, int fd) {
  termios attr;
  tcgetattr(fd, &attr);
  if (enable) attr.c_lflag |= flags; else attr.c_lflag &= ~flags;
  tcsetattr(fd, TCSANOW, &attr);
}

void echo   (bool enabled, int fd) { set_flags(ECHO, enabled, fd); }
void buffer (bool enabled, int fd) { set_flags(ICANON, enabled, fd); }
int  getch  (int fd) { char c; return (read(fd, &c, 1) == 1) ? c & 0xff : EOF; }

bool kbhit (int usec, int fd) {
  fd_set fds;
  FD_ZERO(&fds);
  FD_SET(fd, &fds);
  struct timeval tv = { 0, usec };
  return select(fd + 1, &fds, 0, 0, &tv) == 1 && FD_ISSET(fd, &fds);
}