Optimized input cursor positioning for terminals without hidden cursor

This commit is contained in:
Markus Gans 2016-11-12 22:59:48 +01:00
parent 125c4b961b
commit 04a483526f
11 changed files with 141 additions and 107 deletions

View File

@ -1,5 +1,11 @@
2016-11-12 Markus Gans <guru.mail@muenster.de>
* Better support for Linux terminals with 8 colors
* Optimized input cursor positioning for terminals without hidden cursor
* Switch locale name from "en_US" to "C"
* Fix FString toLong()
2016-11-06 Markus Gans <guru.mail@muenster.de> 2016-11-06 Markus Gans <guru.mail@muenster.de>
* The use of xterm default colors now is configurable * The adjustment of xterm default colors now is configurable
2016-11-05 Markus Gans <guru.mail@muenster.de> 2016-11-05 Markus Gans <guru.mail@muenster.de>
* Determine xterm maximum number of colors via OSC 4 * Determine xterm maximum number of colors via OSC 4

View File

@ -79,6 +79,7 @@ void FButton::setHotkeyForegroundColor (short color)
button_hotkey_fg = color; button_hotkey_fg = color;
} }
//----------------------------------------------------------------------
void FButton::setFocusForegroundColor (short color) void FButton::setFocusForegroundColor (short color)
{ {
// valid colors -1..254 // valid colors -1..254

View File

@ -592,6 +592,7 @@ void FMenu::onMouseMove (FMouseEvent* ev)
{ {
// Unselect selected item without mouse focus // Unselect selected item without mouse focus
(*iter)->unsetSelected(); (*iter)->unsetSelected();
(*iter)->unsetFocus();
if ( getSelectedItem() == *iter ) if ( getSelectedItem() == *iter )
setSelectedItem(0); setSelectedItem(0);
@ -1055,12 +1056,12 @@ bool FMenu::selectNextItem()
unselectItem(); unselectItem();
next->setSelected(); next->setSelected();
setSelectedItem(next); setSelectedItem(next);
redraw();
next->setFocus(); next->setFocus();
if ( getStatusBar() ) if ( getStatusBar() )
getStatusBar()->drawMessage(); getStatusBar()->drawMessage();
redraw();
updateTerminal(); updateTerminal();
flush_out(); flush_out();
break; break;

View File

@ -256,47 +256,30 @@ void FMenuBar::onMouseUp (FMouseEvent* ev)
x1 = (*iter)->getX(); x1 = (*iter)->getX();
x2 = (*iter)->getX() + (*iter)->getWidth(); x2 = (*iter)->getX() + (*iter)->getWidth();
if ( mouse_y == 1 ) if ( mouse_y == 1 && (*iter)->isEnabled() && (*iter)->isSelected() )
{ {
if ( (*iter)->isEnabled() && (*iter)->isSelected() ) if ( mouse_x >= x1 && mouse_x < x2 )
{ {
if ( mouse_x >= x1 && mouse_x < x2 ) // Mouse pointer over item
if ( (*iter)->hasMenu() )
{ {
// Mouse pointer over item FMenu* menu = (*iter)->getMenu();
if ( (*iter)->hasMenu() )
if ( ! menu->hasSelectedItem() )
{ {
FMenu* menu = (*iter)->getMenu(); FMenuItem* first_item;
menu->selectFirstItem();
first_item = menu->getSelectedItem();
if ( ! menu->hasSelectedItem() ) if ( first_item )
{ first_item->setFocus();
FMenuItem* first_item;
menu->selectFirstItem();
first_item = menu->getSelectedItem();
if ( first_item ) if ( getStatusBar() )
first_item->setFocus(); getStatusBar()->drawMessage();
menu->redraw(); redraw();
menu->redraw();
if ( getStatusBar() ) drop_down = true;
getStatusBar()->drawMessage();
redraw();
drop_down = true;
}
}
else
{
(*iter)->unsetSelected();
if ( getSelectedItem() == *iter )
{
setSelectedItem(0);
leaveMenuBar();
drop_down = false;
(*iter)->processClicked();
return;
}
} }
} }
else else
@ -304,11 +287,24 @@ void FMenuBar::onMouseUp (FMouseEvent* ev)
(*iter)->unsetSelected(); (*iter)->unsetSelected();
if ( getSelectedItem() == *iter ) if ( getSelectedItem() == *iter )
{
setSelectedItem(0); setSelectedItem(0);
leaveMenuBar();
redraw(); drop_down = false;
(*iter)->processClicked();
return;
}
} }
} }
else
{
(*iter)->unsetSelected();
if ( getSelectedItem() == *iter )
setSelectedItem(0);
redraw();
}
} }
++iter; ++iter;

View File

@ -271,6 +271,7 @@ void FMenuItem::setSelected()
void FMenuItem::unsetSelected() void FMenuItem::unsetSelected()
{ {
selected = false; selected = false;
unsetCursorPos();
processDeactivate(); processDeactivate();
} }

View File

@ -690,7 +690,7 @@ long FString::toLong() const
p++; p++;
} }
while ( std::isdigit(*p) ) while ( std::iswdigit(*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 ( ! std::isdigit(*p) ) if ( *p != L'\0' && ! std::iswdigit(*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::isdigit(*p) ) while ( std::iswdigit(*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 ( ! std::isdigit(*p) ) if ( *p != L'\0' && ! std::iswdigit(*p) )
throw std::invalid_argument ("no valid number"); throw std::invalid_argument ("no valid number");
return num; return num;

View File

@ -27,6 +27,7 @@ int FTerm::stdin_status_flags;
uInt FTerm::baudrate; uInt FTerm::baudrate;
bool FTerm::resize_term; bool FTerm::resize_term;
bool FTerm::mouse_support; bool FTerm::mouse_support;
bool FTerm::terminal_detection;
bool FTerm::raw_mode; bool FTerm::raw_mode;
bool FTerm::input_data_pending; bool FTerm::input_data_pending;
bool FTerm::non_blocking_stdin; bool FTerm::non_blocking_stdin;
@ -2265,7 +2266,6 @@ char* FTerm::parseSecDA (char*& current_termtype)
{ {
terminal_id_version = -1; terminal_id_version = -1;
} }
switch ( terminal_id_type ) switch ( terminal_id_type )
{ {
case 0: // DEC VT100 case 0: // DEC VT100
@ -2520,7 +2520,8 @@ void FTerm::init_termcaps()
FTermcap::eat_nl_glitch = true; FTermcap::eat_nl_glitch = true;
// maximum number of colors on screen // maximum number of colors on screen
FTermcap::max_color = tgetnum(const_cast<char*>("Co")); FTermcap::max_color = std::max( FTermcap::max_color
, tgetnum(const_cast<char*>("Co")) );
if ( FTermcap::max_color < 0 ) if ( FTermcap::max_color < 0 )
FTermcap::max_color = 1; FTermcap::max_color = 1;
@ -2577,10 +2578,21 @@ void FTerm::init_termcaps()
// set ansi foreground and background color // set ansi foreground and background color
if ( linux_terminal || cygwin_terminal ) if ( linux_terminal || cygwin_terminal )
{ {
tcap[fc::t_set_a_foreground].string = \ if ( FTermcap::max_color > 8 )
const_cast<char*>(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m"); {
tcap[fc::t_set_a_background].string = \ tcap[fc::t_set_a_foreground].string = \
const_cast<char*>(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m"); const_cast<char*>(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m");
tcap[fc::t_set_a_background].string = \
const_cast<char*>(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m");
}
else
{
tcap[fc::t_set_a_foreground].string = \
const_cast<char*>(CSI "3%p1%dm");
tcap[fc::t_set_a_background].string = \
const_cast<char*>(CSI "4%p1%dm");
}
tcap[fc::t_orig_pair].string = \ tcap[fc::t_orig_pair].string = \
const_cast<char*>(CSI "39;49;25m"); const_cast<char*>(CSI "39;49;25m");
} }
@ -2946,6 +2958,7 @@ void FTerm::init()
VGAFont = \ VGAFont = \
ascii_console = \ ascii_console = \
mouse_support = \ mouse_support = \
force_vt100 = \ force_vt100 = \
tera_terminal = \ tera_terminal = \
kterm_terminal = \ kterm_terminal = \
@ -2960,7 +2973,8 @@ void FTerm::init()
xterm_default_colors = false; xterm_default_colors = false;
// Preset to true // Preset to true
cursor_optimisation = true; cursor_optimisation = \
terminal_detection = true;
// assertion: programm start in cooked mode // assertion: programm start in cooked mode
raw_mode = \ raw_mode = \
@ -3015,33 +3029,61 @@ void FTerm::init()
else else
linux_terminal = false; linux_terminal = false;
// start terminal detection... // terminal detection
setRawMode(); if ( terminal_detection )
// Identify the terminal via the answerback-message
new_termtype = parseAnswerbackMsg (new_termtype);
// Identify the terminal via the secondary device attributes (SEC_DA)
new_termtype = parseSecDA (new_termtype);
if ( ! color256 && getXTermColorName(0) != "" )
{ {
if ( getXTermColorName(256) != "" ) setRawMode();
{
new_termtype = const_cast<char*>("xterm-256color");
}
else if ( FTermcap::max_color < 88 && getXTermColorName(87) != "" )
{
new_termtype = const_cast<char*>("xterm-88color");
}
else if ( FTermcap::max_color < 16 && getXTermColorName(15) != "" )
{
new_termtype = const_cast<char*>("xterm-16color");
}
}
unsetRawMode(); // Identify the terminal via the answerback-message
// ...end of terminal detection new_termtype = parseAnswerbackMsg (new_termtype);
// Identify the terminal via the secondary device attributes (SEC_DA)
new_termtype = parseSecDA (new_termtype);
// Determine xterm maximum number of colors via OSC 4
if ( ! color256 && ! tera_terminal && getXTermColorName(0) != "" )
{
if ( getXTermColorName(256) != "" )
{
new_termtype = const_cast<char*>("xterm-256color");
}
else if ( getXTermColorName(87) != "" )
{
new_termtype = const_cast<char*>("xterm-88color");
}
else if ( getXTermColorName(15) != "" )
{
new_termtype = const_cast<char*>("xterm-16color");
}
}
if ( cygwin_terminal
|| putty_terminal
|| tera_terminal
|| rxvt_terminal )
{
FTermcap::max_color = 16;
}
if ( linux_terminal && openConsole() == 0 )
{
if ( isConsole() )
{
if ( setBlinkAsIntensity(true) == 0 )
FTermcap::max_color = 16;
else
FTermcap::max_color = 8;
}
closeConsole();
setConsoleCursor(fc::underscore_cursor, true);
}
if ( linux_terminal && getFramebuffer_bpp() >= 4 )
FTermcap::max_color = 16;
unsetRawMode();
}
// stop non-blocking stdin // stop non-blocking stdin
unsetNonBlockingInput(); unsetNonBlockingInput();
@ -3083,11 +3125,7 @@ void FTerm::init()
// TeraTerm can not show UTF-8 character // TeraTerm can not show UTF-8 character
if ( tera_terminal && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") ) if ( tera_terminal && ! std::strcmp(nl_langinfo(CODESET), "UTF-8") )
locale_name = std::setlocale (LC_ALL, "en_US"); locale_name = std::setlocale (LC_ALL, "C");
// if locale C => switch from 7bit ascii -> latin1
if ( isatty(stdout_no) && ! std::strcmp(nl_langinfo(CODESET), "ANSI_X3.4-1968") )
locale_name = std::setlocale (LC_ALL, "en_US");
// try to found a meaningful content for locale_name // try to found a meaningful content for locale_name
if ( locale_name ) if ( locale_name )
@ -3164,29 +3202,6 @@ void FTerm::init()
unsetNonBlockingInput(); unsetNonBlockingInput();
} }
if ( (FTermcap::max_color == 8)
&& ( linux_terminal
|| cygwin_terminal
|| putty_terminal
|| tera_terminal
|| rxvt_terminal) )
{
FTermcap::max_color = 16;
}
if ( linux_terminal && openConsole() == 0 )
{
if ( isConsole() )
if ( setBlinkAsIntensity(true) != 0 )
FTermcap::max_color = 8;
closeConsole();
setConsoleCursor(fc::underscore_cursor, true);
}
if ( linux_terminal && getFramebuffer_bpp() >= 4 )
FTermcap::max_color = 16;
if ( kde_konsole ) if ( kde_konsole )
setKDECursor(fc::UnderlineCursor); setKDECursor(fc::UnderlineCursor);

View File

@ -313,6 +313,7 @@ class FTerm
static FTermcap::tcap_map* tcap; static FTermcap::tcap_map* tcap;
static bool mouse_support; static bool mouse_support;
static bool terminal_detection;
static bool raw_mode; static bool raw_mode;
static bool input_data_pending; static bool input_data_pending;
static bool non_blocking_stdin; static bool non_blocking_stdin;

View File

@ -22,6 +22,8 @@ FWidget::widgetList* FWidget::dialog_list = 0;
FWidget::widgetList* FWidget::always_on_top_list = 0; FWidget::widgetList* FWidget::always_on_top_list = 0;
FWidget::widgetList* FWidget::close_widget = 0; FWidget::widgetList* FWidget::close_widget = 0;
FWidget::widget_colors FWidget::wc; FWidget::widget_colors FWidget::wc;
bool FWidget::hideable;
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// class FWidget // class FWidget
@ -40,7 +42,7 @@ FWidget::FWidget (FWidget* parent)
, shown(false) , shown(false)
, focus(false) , focus(false)
, focusable(true) , focusable(true)
, visible_cursor(false) , visible_cursor(true)
, widget_cursor_position(-1,-1) , widget_cursor_position(-1,-1)
, size_hints() , size_hints()
, double_flatline_mask() , double_flatline_mask()
@ -72,6 +74,7 @@ FWidget::FWidget (FWidget* parent)
} }
else else
{ {
visible_cursor = ! hideable;
offset = parent->client_offset; offset = parent->client_offset;
double_flatline_mask.top.resize (uLong(getWidth()), false); double_flatline_mask.top.resize (uLong(getWidth()), false);
double_flatline_mask.right.resize (uLong(getHeight()), false); double_flatline_mask.right.resize (uLong(getHeight()), false);
@ -2124,6 +2127,15 @@ void FWidget::init()
always_on_top_list = new widgetList(); always_on_top_list = new widgetList();
close_widget = new widgetList(); close_widget = new widgetList();
char* cursor_off_str = disableCursor();
if ( cursor_off_str && std::strlen(cursor_off_str ) > 0 )
hideable = true;
else
hideable = false;
visible_cursor = ! hideable;
// determine width and height of the terminal // determine width and height of the terminal
detectTermSize(); detectTermSize();
wsize.setRect(1, 1, getColumnNumber(), getLineNumber()); wsize.setRect(1, 1, getColumnNumber(), getLineNumber());

View File

@ -514,6 +514,7 @@ class FWidget : public FVTerm
static FMenuBar* menubar; static FMenuBar* menubar;
static FWidget* show_root_widget; static FWidget* show_root_widget;
static FWidget* redraw_root_widget; static FWidget* redraw_root_widget;
static bool hideable;
// Friend class // Friend class
friend class FToggleButton; friend class FToggleButton;
@ -683,7 +684,7 @@ inline bool FWidget::setDisable()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
inline bool FWidget::setVisibleCursor (bool on) inline bool FWidget::setVisibleCursor (bool on)
{ return visible_cursor = (on) ? true : false; } { return visible_cursor = (on) ? true : ((hideable) ? false : true); }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
inline bool FWidget::setVisibleCursor() inline bool FWidget::setVisibleCursor()
@ -776,7 +777,7 @@ inline bool FWidget::setCursorPos (const FPoint& pos)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
inline void FWidget::unsetCursorPos() inline void FWidget::unsetCursorPos()
{ widget_cursor_position.setPoint(-1,-1); } { setCursorPos(-1,-1); }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
inline void FWidget::setPrintPos (const FPoint& pos) inline void FWidget::setPrintPos (const FPoint& pos)

View File

@ -19,7 +19,7 @@ int main (int, char**)
if ( isatty(1) && ! std::strcmp(nl_langinfo(CODESET), "ANSI_X3.4-1968") ) if ( isatty(1) && ! std::strcmp(nl_langinfo(CODESET), "ANSI_X3.4-1968") )
{ {
// locale C -> switch from 7bit ascii -> latin1 // locale C -> switch from 7bit ascii -> latin1
std::setlocale(LC_ALL, "en_US"); std::setlocale(LC_ALL, "C");
} }
printf (" Codeset: %s\n", nl_langinfo(CODESET)); printf (" Codeset: %s\n", nl_langinfo(CODESET));