1 /**
2 Copyright: Copyright (c) 2020, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 Module to manipulate a file descriptor that point to a tty.
7 */
8 module my.tty;
9 
10 import my.from_;
11 
12 /// Used to reset the terminal to the original mode.
13 struct CBreak {
14     import core.sys.posix.termios;
15 
16     termios mode;
17 
18     void reset(int fd) {
19         tcsetattr(fd, TCSAFLUSH, &mode);
20     }
21 }
22 
23 /// Set the terminal to cbreak mode which mean it is change from line mode to
24 /// character mode.
25 CBreak setCBreak(int fd) {
26     import core.sys.posix.termios;
27 
28     termios mode;
29     if (tcgetattr(fd, &mode) == 0) {
30         auto newMode = mode;
31         newMode.c_lflag = newMode.c_lflag & ~(ECHO | ICANON);
32         newMode.c_cc[VMIN] = 1;
33         newMode.c_cc[VTIME] = 0;
34         tcsetattr(fd, TCSAFLUSH, &newMode);
35     }
36 
37     return CBreak(mode);
38 }
39 
40 /// Configure a tty for interactive input.
41 void setInteractiveTty(ref std_.stdio.File tty) {
42     import core.sys.posix.termios;
43     import std.conv : octal;
44 
45     // /usr/include/x86_64-linux-gnu/bits/termios-c_iflag.h
46     enum IUTF8 = octal!40000; /* Input is UTF8 (not in POSIX).  */
47 
48     enum ECHOCTL = octal!1000; /* If ECHO is also set, terminal special
49                                   characters other than TAB, NL, START, and
50                                   STOP are echoed as ^X, where X is the
51                                   character with ASCII code 0x40 greater than
52                                   the special character (not in POSIX).  */
53 
54     enum ECHOKE = octal!4000; /* If ICANON is also set, KILL is echoed by
55                                  erasing each character on the line, as
56                                  specified by ECHOE and ECHOPRT (not in POSIX).
57                                */
58     enum VREPRINT = 12;
59     enum VWERASE = 14;
60     enum VLNEXT = 15;
61 
62     termios mode;
63     mode.c_iflag = ICRNL | IXON | IUTF8;
64     mode.c_oflag = OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
65     mode.c_cflag = CS8 | CREAD;
66     mode.c_lflag = ISIG | ICANON | IEXTEN; // | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE;
67 
68     cfsetispeed(&mode, 38400);
69     cfsetospeed(&mode, 38400);
70 
71     mode.c_cc[VINTR] = 0x1f & 'C';
72     mode.c_cc[VQUIT] = 0x1f & '\\';
73     mode.c_cc[VERASE] = 0x7f;
74     mode.c_cc[VKILL] = 0x1f & 'U';
75     mode.c_cc[VEOF] = 0x1f & 'D';
76     //mode.c_cc[VEOL]     = _POSIX_VDISABLE;
77     //mode.c_cc[VEOL2]    = _POSIX_VDISABLE;
78     mode.c_cc[VSTART] = 0x1f & 'Q';
79     mode.c_cc[VSTOP] = 0x1f & 'S';
80     mode.c_cc[VSUSP] = 0x1f & 'Z';
81     mode.c_cc[VREPRINT] = 0x1f & 'R';
82     mode.c_cc[VWERASE] = 0x1f & 'W';
83     mode.c_cc[VLNEXT] = 0x1f & 'V';
84     mode.c_cc[VMIN] = 1;
85     mode.c_cc[VTIME] = 0;
86 
87     tcsetattr(tty.fileno, TCSAFLUSH, &mode);
88 }
89 
90 /// Returns: if stderr or stdout is an interactive tty
91 bool isStdoutInteractive() {
92     import core.stdc.stdio;
93     import core.sys.posix.unistd;
94 
95     return isatty(STDOUT_FILENO) == 1;
96 }
97 
98 bool isStderrInteractive() {
99     import core.stdc.stdio;
100     import core.sys.posix.unistd;
101 
102     return isatty(STDERR_FILENO) == 1;
103 }