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 }