Improve tty settings

This commit is contained in:
Markus Gans 2016-11-20 18:26:15 +01:00
parent fc8ee51e72
commit 082bbfbaa2
7 changed files with 242 additions and 166 deletions

View File

@ -1,10 +1,14 @@
2016-11-20 Markus Gans <guru.mail@muenster.de>
* Improve tty settings
2016-11-13 Markus Gans <guru.mail@muenster.de> 2016-11-13 Markus Gans <guru.mail@muenster.de>
* Do not draw shadows on a linux console if not * Do not draw shadows on a linux console if not
all characters are available all characters are available
2016-11-12 Markus Gans <guru.mail@muenster.de> 2016-11-12 Markus Gans <guru.mail@muenster.de>
* Better support for Linux terminals with 8 colors * Better support for Linux terminals with 8 colors
* Optimized input cursor positioning for terminals without hidden cursor * Optimized input cursor positioning for terminals without
hidden cursor
* Switch locale name from "en_US" to "C" * Switch locale name from "en_US" to "C"
* Fix FString toLong() * Fix FString toLong()

View File

@ -33,7 +33,7 @@ FApplication::eventQueue* FApplication::event_queue = 0;
// constructors and destructor // constructors and destructor
//---------------------------------------------------------------------- //----------------------------------------------------------------------
FApplication::FApplication (int& _argc, char**& _argv) FApplication::FApplication (int& _argc, char* _argv[])
: FWidget(0) : FWidget(0)
, app_argc(_argc) , app_argc(_argc)
, app_argv(_argv) , app_argv(_argv)
@ -59,8 +59,8 @@ FApplication::FApplication (int& _argc, char**& _argv)
if ( ! (_argc && _argv) ) if ( ! (_argc && _argv) )
{ {
static char* empty = const_cast<char*>(""); static char* empty = const_cast<char*>("");
_argc = 0; app_argc = 0;
_argv = static_cast<char**>(&empty); app_argv = static_cast<char**>(&empty);
} }
init(); init();

View File

@ -55,7 +55,7 @@ class FApplication : public FWidget
{ {
public: public:
// Constructor // Constructor
FApplication (int&, char**& ); FApplication (int&, char*[]);
// Destructor // Destructor
virtual ~FApplication(); virtual ~FApplication();

View File

@ -690,7 +690,7 @@ long FString::toLong() const
p++; p++;
} }
while ( std::iswdigit(*p) ) while ( std::iswdigit(wint_t(*p)) )
{ {
register uChar d = uChar((*p) - L'0'); register uChar d = uChar((*p) - L'0');
@ -704,7 +704,7 @@ long FString::toLong() const
p++; p++;
} }
if ( *p != L'\0' && ! std::iswdigit(*p) ) if ( *p != L'\0' && ! std::iswdigit(wint_t(*p)) )
throw std::invalid_argument ("no valid number"); throw std::invalid_argument ("no valid number");
return num; return num;
@ -736,7 +736,7 @@ uLong FString::toULong() const
p++; p++;
} }
while ( std::iswdigit(*p) ) while ( std::iswdigit(wint_t(*p)) )
{ {
register uChar d = uChar((*p) - L'0'); register uChar d = uChar((*p) - L'0');
@ -750,7 +750,7 @@ uLong FString::toULong() const
p++; p++;
} }
if ( *p != L'\0' && ! std::iswdigit(*p) ) if ( *p != L'\0' && ! std::iswdigit(wint_t(*p)) )
throw std::invalid_argument ("no valid number"); throw std::invalid_argument ("no valid number");
return num; return num;

View File

@ -128,6 +128,14 @@ FTerm::~FTerm() // destructor
// public methods of FTerm // public methods of FTerm
//----------------------------------------------------------------------
termios FTerm::getTTY()
{
struct termios t;
tcgetattr (stdin_no, &t);
return t;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
int FTerm::getLineNumber() int FTerm::getLineNumber()
{ {
@ -228,52 +236,77 @@ void FTerm::setConsoleCursor (fc::consoleCursorStyle style, bool hidden)
std::fflush(stdout); std::fflush(stdout);
} }
//----------------------------------------------------------------------
void FTerm::setTTY (termios& t)
{
tcsetattr (stdin_no, TCSADRAIN, &t);
}
//----------------------------------------------------------------------
void FTerm::noHardwareEcho()
{
// Info under: man 3 termios
struct termios t;
tcgetattr (stdin_no, &t);
// local mode
t.c_lflag &= uInt(~(ECHO | ECHONL));
// input mode
t.c_iflag &= uInt(~(ICRNL | INLCR | IGNCR));
// output mode
t.c_oflag &= uInt(~ONLCR);
// set the new termios settings
setTTY (t);
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
bool FTerm::setRawMode (bool on) bool FTerm::setRawMode (bool on)
{ {
// set + unset flags for raw mode
if ( on == raw_mode ) if ( on == raw_mode )
return raw_mode; return raw_mode;
std::fflush(stdout);
if ( on ) if ( on )
{ {
// Info under: man 3 termios // Info under: man 3 termios
struct termios t; struct termios t;
tcgetattr (stdin_no, &t); tcgetattr (stdin_no, &t);
/* set + unset flags for raw mode */
// input mode
t.c_iflag &= uInt(~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON));
// output mode
t.c_oflag &= uInt(~OPOST);
// local mode // local mode
#if DEBUG #if DEBUG
// Exit with ctrl-c only if compiled with "DEBUG" option // Exit with ctrl-c only if compiled with "DEBUG" option
t.c_lflag &= uInt(~(ECHO | ECHONL | ICANON | IEXTEN)); t.c_lflag &= uInt(~(ICANON | IEXTEN));
#else #else
// Plus disable signals. t.c_lflag &= uInt(~(ICANON | ISIG | IEXTEN));
t.c_lflag &= uInt(~(ECHO | ECHONL | ICANON | IEXTEN | ISIG));
#endif #endif
// control mode // input mode
t.c_cflag &= uInt(~(CSIZE | PARENB)); t.c_iflag &= uInt(~(IXON | BRKINT | PARMRK));
t.c_cflag |= uInt(CS8);
// defines the terminal special characters for noncanonical read // defines the terminal special characters for noncanonical read
t.c_cc[VTIME] = 0; // Timeout in deciseconds t.c_cc[VTIME] = 0; // Timeout in deciseconds
t.c_cc[VMIN] = 1; // Minimum number of characters t.c_cc[VMIN] = 1; // Minimum number of characters
// set the new termios settings // set the new termios settings
tcsetattr (stdin_no, TCSAFLUSH, &t); setTTY (t);
raw_mode = true; raw_mode = true;
} }
else else
{ {
// restore termios settings struct termios t;
tcsetattr (stdin_no, TCSAFLUSH, &term_init); tcgetattr (stdin_no, &t);
// local mode
t.c_lflag |= uInt(ISIG | ICANON | (term_init.c_lflag & IEXTEN));
// input mode
t.c_iflag |= uInt(IXON | BRKINT | PARMRK);
// set the new termios settings
setTTY (t);
raw_mode = false; raw_mode = false;
} }
@ -328,7 +361,7 @@ bool FTerm::setNonBlockingInput (bool on)
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
int FTerm::parseKeyString ( char* buffer int FTerm::parseKeyString ( char buffer[]
, int buf_size , int buf_size
, timeval* time_keypressed ) , timeval* time_keypressed )
{ {
@ -762,24 +795,32 @@ const FString FTerm::getXTermFont()
if ( xterm_terminal || screen_terminal || FTermcap::osc_support ) if ( xterm_terminal || screen_terminal || FTermcap::osc_support )
{ {
if ( raw_mode && non_blocking_stdin ) fd_set ifds;
{ struct timeval tv;
int n;
char temp[150] = {}; char temp[150] = {};
oscPrefix(); oscPrefix();
putstring (OSC "50;?" BEL); // get font putstring (OSC "50;?" BEL); // get font
oscPostfix(); oscPostfix();
std::fflush(stdout); std::fflush(stdout);
usleep(150000); // wait 150 ms
FD_ZERO(&ifds);
FD_SET(stdin_no, &ifds);
tv.tv_sec = 0;
tv.tv_usec = 150000; // 150 ms
// read the terminal answer // read the terminal answer
n = int(read(fileno(stdin), &temp, sizeof(temp)-1)); if ( select (stdin_no+1, &ifds, 0, 0, &tv) > 0)
{
if ( std::scanf("\033]50;%[^\n]s", temp) == 1 )
{
size_t n = std::strlen(temp);
// BEL + '\0' = string terminator // BEL + '\0' = string terminator
if ( n >= 6 && temp[n-1] == BEL[0] && temp[n] == '\0' ) if ( n >= 5 && temp[n-1] == BEL[0] && temp[n] == '\0' )
{
temp[n-1] = '\0'; temp[n-1] = '\0';
font = static_cast<char*>(temp + 5);
font = temp;
} }
} }
} }
@ -795,22 +836,30 @@ const FString FTerm::getXTermTitle()
if ( kde_konsole ) if ( kde_konsole )
return title; return title;
if ( raw_mode && non_blocking_stdin ) fd_set ifds;
{ struct timeval tv;
int n;
char temp[512] = {}; char temp[512] = {};
putstring (CSI "21t"); // get title putstring (CSI "21t"); // get title
std::fflush(stdout); std::fflush(stdout);
usleep(150000); // wait 150 ms
FD_ZERO(&ifds);
FD_SET(stdin_no, &ifds);
tv.tv_sec = 0;
tv.tv_usec = 150000; // 150 ms
// read the terminal answer // read the terminal answer
n = int(read(fileno(stdin), &temp, sizeof(temp)-1)); if ( select (stdin_no+1, &ifds, 0, 0, &tv) > 0)
{
if ( std::scanf("\033]l%[^\n]s", temp) == 1 )
{
size_t n = std::strlen(temp);
// Esc + \ = OSC string terminator // Esc + \ = OSC string terminator
if ( n >= 5 && temp[n-1] == '\\' && temp[n-2] == ESC[0] ) if ( n >= 4 && temp[n-1] == '\\' && temp[n-2] == ESC[0] )
{
temp[n-2] = '\0'; temp[n-2] = '\0';
title = static_cast<char*>(temp + 3);
title = temp;
} }
} }
@ -822,9 +871,8 @@ const FString FTerm::getXTermColorName (int color)
{ {
FString color_str(""); FString color_str("");
if ( raw_mode && non_blocking_stdin ) fd_set ifds;
{ struct timeval tv;
int n;
int c = color; int c = color;
int digits = 0; int digits = 0;
@ -834,16 +882,28 @@ const FString FTerm::getXTermColorName (int color)
char temp[512] = {}; char temp[512] = {};
putstringf (OSC "4;%d;?" BEL, color); // get color putstringf (OSC "4;%d;?" BEL, color); // get color
std::fflush(stdout); std::fflush(stdout);
usleep(150000); // wait 150 ms
FD_ZERO(&ifds);
FD_SET(stdin_no, &ifds);
tv.tv_sec = 0;
tv.tv_usec = 150000; // 150 ms
// read the terminal answer // read the terminal answer
n = int(read(fileno(stdin), &temp, sizeof(temp)-1)); if ( select (stdin_no+1, &ifds, 0, 0, &tv) > 0)
{
if ( std::scanf("\033]4;%d;%[^\n]s", &color, temp) == 2 )
{
size_t n = std::strlen(temp);
// BEL + '\0' = string terminator // BEL + '\0' = string terminator
if ( n >= 6 && temp[n-1] == BEL[0] && temp[n] == '\0' ) if ( n >= 6 && temp[n-1] == BEL[0] && temp[n] == '\0' )
{
temp[n-1] = '\0'; temp[n-1] = '\0';
color_str = static_cast<char*>(temp + 6 + digits);
// Esc + \ = OSC string terminator (mintty)
if ( n >= 6 && temp[n-1] == '\\' && temp[n-2] == ESC[0] )
temp[n-2] = '\0';
color_str = temp;
} }
} }
@ -1294,33 +1354,22 @@ const FString FTerm::getAnswerbackMsg()
{ {
FString answerback = ""; FString answerback = "";
if ( raw_mode )
{
ssize_t n;
fd_set ifds; fd_set ifds;
struct timeval tv; struct timeval tv;
char temp[10] = {}; char temp[10] = {};
std::putchar (ENQ[0]); // send enquiry character
std::fflush(stdout);
FD_ZERO(&ifds); FD_ZERO(&ifds);
FD_SET(stdin_no, &ifds); FD_SET(stdin_no, &ifds);
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 150000; // 150 ms tv.tv_usec = 150000; // 150 ms
std::putchar (ENQ[0]); // send enquiry character
std::fflush(stdout);
// read the answerback message // read the answerback message
if ( select (stdin_no+1, &ifds, 0, 0, &tv) > 0) if ( select (stdin_no+1, &ifds, 0, 0, &tv) > 0)
{ if ( std::fgets (temp, sizeof(temp)-1, stdin) != 0 )
n = read(fileno(stdin), &temp, sizeof(temp)-1);
if ( n > 0 )
{
temp[n] = '\0';
answerback = temp; answerback = temp;
}
}
}
return answerback; return answerback;
} }
@ -1330,39 +1379,23 @@ const FString FTerm::getSecDA()
{ {
FString sec_da_str = ""; FString sec_da_str = "";
if ( raw_mode ) int a=0, b=0, c=0;
{
ssize_t n;
fd_set ifds; fd_set ifds;
struct timeval tv; struct timeval tv;
char temp[16] = {};
// get the secondary device attributes
putstring (SECDA);
std::fflush(stdout);
FD_ZERO(&ifds); FD_ZERO(&ifds);
FD_SET(stdin_no, &ifds); FD_SET(stdin_no, &ifds);
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 550000; // 150 ms tv.tv_usec = 600000;; // 600 ms
// get the secondary device attributes
std::putchar (SECDA[0]);
std::putchar (SECDA[1]);
std::putchar (SECDA[2]);
std::putchar (SECDA[3]);
std::fflush(stdout);
usleep(150000); // min. wait time 150 ms (need for mintty)
// read the answer // read the answer
if ( select (stdin_no+1, &ifds, 0, 0, &tv) > 0 ) if ( select (stdin_no+1, &ifds, 0, 0, &tv) == 1 )
{ if ( std::scanf("\033[>%d;%d;%dc", &a, &b, &c) == 3 )
n = read(fileno(stdin), &temp, sizeof(temp)-1); sec_da_str.sprintf("\033[>%d;%d;%dc", a, b, c);
if ( n > 0 )
{
temp[n] = '\0';
sec_da_str = temp;
}
}
}
return sec_da_str; return sec_da_str;
} }
@ -1436,7 +1469,7 @@ int FTerm::putchar_UTF8 (register int c)
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
int FTerm::UTF8decode(char* utf8) int FTerm::UTF8decode (const char utf8[])
{ {
register int ucs=0; register int ucs=0;
@ -1883,6 +1916,20 @@ void FTerm::identifyTermType()
std::strncpy (termtype, const_cast<char*>("vt100"), 6); std::strncpy (termtype, const_cast<char*>("vt100"), 6);
} }
//----------------------------------------------------------------------
void FTerm::storeTTYsettings()
{
// store termios settings
term_init = getTTY();
}
//----------------------------------------------------------------------
void FTerm::restoreTTYsettings()
{
// restore termios settings
setTTY (term_init);
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
int FTerm::getScreenFont() int FTerm::getScreenFont()
{ {
@ -2224,8 +2271,9 @@ char* FTerm::parseAnswerbackMsg (char*& current_termtype)
else else
putty_terminal = false; putty_terminal = false;
// cygwin needs a backspace to delete the '♣' char
if ( cygwin_terminal ) if ( cygwin_terminal )
std::putchar (BS[0]); // cygwin needs a backspace to delete the '♣' char putstring (BS " " BS);
return new_termtype; return new_termtype;
} }
@ -3021,11 +3069,8 @@ void FTerm::init()
// initialize terminal and Linux console // initialize terminal and Linux console
init_console(); init_console();
// make stdin non-blocking
setNonBlockingInput();
// save termios settings // save termios settings
tcgetattr (stdin_no, &term_init); storeTTYsettings();
// get output baud rate // get output baud rate
baudrate = getBaudRate(&term_init); baudrate = getBaudRate(&term_init);
@ -3057,7 +3102,13 @@ void FTerm::init()
// terminal detection // terminal detection
if ( terminal_detection ) if ( terminal_detection )
{ {
setRawMode(); struct termios t;
tcgetattr (STDIN_FILENO, &t);
t.c_lflag &= uInt(~(ICANON | ECHO));
t.c_cc[VTIME] = 1; // Timeout in deciseconds
t.c_cc[VMIN] = 0; // Minimum number of characters
tcsetattr (STDIN_FILENO, TCSANOW, &t);
// Identify the terminal via the answerback-message // Identify the terminal via the answerback-message
new_termtype = parseAnswerbackMsg (new_termtype); new_termtype = parseAnswerbackMsg (new_termtype);
@ -3066,7 +3117,11 @@ void FTerm::init()
new_termtype = parseSecDA (new_termtype); new_termtype = parseSecDA (new_termtype);
// Determine xterm maximum number of colors via OSC 4 // Determine xterm maximum number of colors via OSC 4
if ( ! color256 && ! tera_terminal && getXTermColorName(0) != "" ) if ( ! color256
&& ! cygwin_terminal
&& ! tera_terminal
&& ! linux_terminal
&& getXTermColorName(0) != "" )
{ {
if ( getXTermColorName(256) != "" ) if ( getXTermColorName(256) != "" )
{ {
@ -3107,12 +3162,10 @@ void FTerm::init()
if ( linux_terminal && getFramebuffer_bpp() >= 4 ) if ( linux_terminal && getFramebuffer_bpp() >= 4 )
FTermcap::max_color = 16; FTermcap::max_color = 16;
unsetRawMode(); t.c_lflag |= uInt(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSADRAIN, &t);
} }
// stop non-blocking stdin
unsetNonBlockingInput();
// Test if the terminal is a xterm // Test if the terminal is a xterm
if ( std::strncmp(termtype, const_cast<char*>("xterm"), 5) == 0 if ( std::strncmp(termtype, const_cast<char*>("xterm"), 5) == 0
|| std::strncmp(termtype, const_cast<char*>("Eterm"), 4) == 0 ) || std::strncmp(termtype, const_cast<char*>("Eterm"), 4) == 0 )
@ -3217,14 +3270,18 @@ void FTerm::init()
std::fflush(stdout); std::fflush(stdout);
} }
setRawMode();
if ( (xterm_terminal || urxvt_terminal) && ! rxvt_terminal ) if ( (xterm_terminal || urxvt_terminal) && ! rxvt_terminal )
{ {
setNonBlockingInput(); struct termios t;
tcgetattr (STDIN_FILENO, &t);
t.c_lflag &= uInt(~(ICANON | ECHO));
tcsetattr (STDIN_FILENO, TCSANOW, &t);
xterm_font = new FString(getXTermFont()); xterm_font = new FString(getXTermFont());
xterm_title = new FString(getXTermTitle()); xterm_title = new FString(getXTermTitle());
unsetNonBlockingInput();
t.c_lflag |= uInt(ICANON | ECHO);
tcsetattr (STDIN_FILENO, TCSADRAIN, &t);
} }
if ( kde_konsole ) if ( kde_konsole )
@ -3266,6 +3323,12 @@ void FTerm::init()
signal(SIGILL, FTerm::signal_handler); // Illegal Instruction signal(SIGILL, FTerm::signal_handler); // Illegal Instruction
signal(SIGSEGV, FTerm::signal_handler); // Invalid memory reference signal(SIGSEGV, FTerm::signal_handler); // Invalid memory reference
signal(SIGWINCH, FTerm::signal_handler); // Window resize signal signal(SIGWINCH, FTerm::signal_handler); // Window resize signal
// turn off hardware echo
noHardwareEcho();
// switch to the raw mode
setRawMode();
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -3283,7 +3346,8 @@ void FTerm::finish()
if ( xterm_title && xterm_terminal && ! rxvt_terminal ) if ( xterm_title && xterm_terminal && ! rxvt_terminal )
setXTermTitle (*xterm_title); setXTermTitle (*xterm_title);
setCookedMode(); // leave raw mode // restore the saved termios settings
restoreTTYsettings();
// turn off all attributes // turn off all attributes
if ( tcap[fc::t_exit_attribute_mode].string ) if ( tcap[fc::t_exit_attribute_mode].string )

View File

@ -103,6 +103,7 @@ class FTerm
// Accessors // Accessors
virtual const char* getClassName() const; virtual const char* getClassName() const;
static termios getTTY();
static int getLineNumber(); static int getLineNumber();
static int getColumnNumber(); static int getColumnNumber();
static FString getKeyName (int); static FString getKeyName (int);
@ -144,6 +145,8 @@ class FTerm
static bool setCursorOptimisation (bool); static bool setCursorOptimisation (bool);
static void setXTermDefaultColors (bool); static void setXTermDefaultColors (bool);
static void setConsoleCursor (fc::consoleCursorStyle, bool); static void setConsoleCursor (fc::consoleCursorStyle, bool);
static void setTTY (termios&);
static void noHardwareEcho();
static bool setRawMode (bool); static bool setRawMode (bool);
static bool setRawMode(); static bool setRawMode();
static bool unsetRawMode(); static bool unsetRawMode();
@ -156,7 +159,7 @@ class FTerm
static bool unsetNonBlockingInput(); static bool unsetNonBlockingInput();
// Methods // Methods
static int parseKeyString (char*, int, timeval*); static int parseKeyString (char[], int, timeval*);
static bool& unprocessedInput(); static bool& unprocessedInput();
static bool setVGAFont(); static bool setVGAFont();
static bool setNewFont(); static bool setNewFont();
@ -216,7 +219,7 @@ class FTerm
static void putstring (const char*, int = 1); static void putstring (const char*, int = 1);
static int putchar_ASCII (register int); static int putchar_ASCII (register int);
static int putchar_UTF8 (register int); static int putchar_UTF8 (register int);
static int UTF8decode (char*); static int UTF8decode (const char[]);
protected: protected:
// Typedefs // Typedefs
@ -260,6 +263,7 @@ class FTerm
private: private:
// Typedefs // Typedefs
typedef FTermcap::tcap_map termcap_map; typedef FTermcap::tcap_map termcap_map;
typedef struct typedef struct
{ {
uChar red; uChar red;
@ -289,6 +293,8 @@ class FTerm
static int openConsole(); static int openConsole();
static int closeConsole(); static int closeConsole();
static void identifyTermType(); static void identifyTermType();
static void storeTTYsettings();
static void restoreTTYsettings();
static int getScreenFont(); static int getScreenFont();
static int setScreenFont (uChar*, uInt, uInt, uInt, bool = false); static int setScreenFont (uChar*, uInt, uInt, uInt, bool = false);
static int setUnicodeMap (struct unimapdesc*); static int setUnicodeMap (struct unimapdesc*);

View File

@ -550,7 +550,8 @@ int FVTerm::print (term_area* area, FString& s)
nc.inherit_bg = next_attribute.inherit_bg; nc.inherit_bg = next_attribute.inherit_bg;
if ( area if ( area
&& ax >= 0 && ay >= 0 && area->cursor_x > 0
&& area->cursor_y > 0
&& ax < area->width + area->right_shadow && ax < area->width + area->right_shadow
&& ay < area->height + area->bottom_shadow ) && ay < area->height + area->bottom_shadow )
{ {
@ -664,7 +665,8 @@ int FVTerm::print (term_area* area, register int c)
nc.trans_shadow = next_attribute.trans_shadow; nc.trans_shadow = next_attribute.trans_shadow;
nc.inherit_bg = next_attribute.inherit_bg; nc.inherit_bg = next_attribute.inherit_bg;
if ( ax >= 0 && ay >= 0 if ( area->cursor_x > 0
&& area->cursor_y > 0
&& ax < area->width + area->right_shadow && ax < area->width + area->right_shadow
&& ay < area->height + area->bottom_shadow ) && ay < area->height + area->bottom_shadow )
{ {