From 76d72208e544f94a009de5bc14931cd8783ad1a5 Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Wed, 3 Jan 2018 08:42:10 +0100 Subject: [PATCH] Refactoring FTerm::parseKeyString and timeout settings --- ChangeLog | 3 + include/final/fterm.h | 54 ++++++-- include/final/fvterm.h | 34 ++--- src/fapplication.cpp | 16 ++- src/foptiattr.cpp | 2 +- src/fterm.cpp | 300 +++++++++++++++++++++++++---------------- 6 files changed, 259 insertions(+), 150 deletions(-) diff --git a/ChangeLog b/ChangeLog index def42f60..b3a822dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2017-01-02 Markus Gans + * Refactoring FTerm::parseKeyString and timeout settings + 2017-01-02 Markus Gans * Refactoring of secondary device attributes parsing * Small menu improvements diff --git a/include/final/fterm.h b/include/final/fterm.h index a999f728..2d05d729 100644 --- a/include/final/fterm.h +++ b/include/final/fterm.h @@ -193,7 +193,8 @@ class FTerm #endif // Inquiries - static bool isKeyTimeout (timeval*, register long); + static bool isKeypressTimeout (timeval*); + static bool isDblclickTimeout (timeval*); static bool isNormal (char_data*&); static bool isRaw(); static bool hasPCcharset(); @@ -236,6 +237,8 @@ class FTerm (fc::freebsdConsoleCursorStyle, bool); #endif + static void setKeypressTimeout (const long); + static void setDblclickInterval (const long); static void setTTY (const termios&); static void noHardwareEcho(); static bool setRawMode (bool); @@ -423,6 +426,8 @@ class FTerm FTerm& operator = (const FTerm&); // Inquiries + static bool isTimeout (timeval*, register long); + #if defined(__linux__) static int isLinuxConsole(); #endif @@ -538,6 +543,10 @@ class FTerm void init(); void finish(); static uInt cp437_to_unicode (uChar); + static int getMouseProtocolKey (char[]); + static int getTermcapKey (char[], int); + static int getMetaKey (char[], int, timeval*); + static int getSingleKey (char[], int); static void setSignalHandler(); static void resetSignalHandler(); static void signal_handler (int); @@ -586,13 +595,15 @@ class FTerm static char term_name[256]; static char* locale_name; static char* locale_xterm; - static FRect* term; // current terminal geometry - static FPoint* mouse; // mouse click position + static FRect* term; // current terminal geometry + static FPoint* mouse; // mouse click position static int gnome_terminal_id; static int stdin_status_flags; static int fd_tty; static uInt baudrate; + static long key_timeout; + static long dblclick_interval; static bool resize_term; static struct termios term_init; @@ -618,6 +629,16 @@ class FTerm static struct colorEnv { + void setDefault() + { + string1 = 0; + string2 = 0; + string3 = 0; + string4 = 0; + string5 = 0; + string6 = 0; + } + char* string1; char* string2; char* string3; @@ -628,11 +649,12 @@ class FTerm static struct secondaryDA { - secondaryDA() - : terminal_id_type (-1) - , terminal_id_version (-1) - , terminal_id_hardware (-1) - { } + void setDefault() + { + terminal_id_type = -1; + terminal_id_version = -1; + terminal_id_hardware = -1; + } int terminal_id_type; int terminal_id_version; @@ -678,6 +700,14 @@ inline const FString& FTerm::getSecDAString() { return ( sec_da ) ? *sec_da : fc::emptyFString::get(); } #endif +//---------------------------------------------------------------------- +inline bool FTerm::isKeypressTimeout (timeval* time) +{ return isTimeout (time, key_timeout); } + +//---------------------------------------------------------------------- +inline bool FTerm::isDblclickTimeout (timeval* time) +{ return isTimeout (time, dblclick_interval); } + //---------------------------------------------------------------------- inline bool FTerm::isRaw() { return raw_mode; } @@ -790,6 +820,14 @@ inline bool FTerm::setCursorOptimisation (bool on) inline void FTerm::setXTermDefaultColors (bool on) { xterm_default_colors = on; } +//---------------------------------------------------------------------- +inline void FTerm::setKeypressTimeout (const long timeout) +{ key_timeout = timeout; } + +//---------------------------------------------------------------------- +inline void FTerm::setDblclickInterval (const long timeout) +{ dblclick_interval = timeout; } + //---------------------------------------------------------------------- inline bool FTerm::setRawMode() { return setRawMode(true); } diff --git a/include/final/fvterm.h b/include/final/fvterm.h index c04ba303..a3f6596d 100644 --- a/include/final/fvterm.h +++ b/include/final/fvterm.h @@ -437,23 +437,23 @@ struct FVTerm::term_area // define virtual terminal character properties { public: term_area() - : offset_left (0) - , offset_top (0) - , width (-1) - , height (-1) - , right_shadow (0) - , bottom_shadow (0) - , cursor_x (0) - , cursor_y (0) - , input_cursor_x (-1) - , input_cursor_y (-1) - , widget() - , preprocessing_call() - , changes (0) - , text (0) - , input_cursor_visible (false) - , has_changes (false) - , visible (false) + : offset_left (0) + , offset_top (0) + , width (-1) + , height (-1) + , right_shadow (0) + , bottom_shadow (0) + , cursor_x (0) + , cursor_y (0) + , input_cursor_x (-1) + , input_cursor_y (-1) + , widget() + , preprocessing_call() + , changes (0) + , text (0) + , input_cursor_visible (false) + , has_changes (false) + , visible (false) { } ~term_area() diff --git a/src/fapplication.cpp b/src/fapplication.cpp index c5b7e625..9e615cae 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -80,6 +80,12 @@ FApplication::FApplication ( const int& _argc && "FApplication: There should be only one application object" ); rootObj = this; + // Set the keyboard keypress timeout + setKeypressTimeout (key_timeout); + + // Set the double click interval + setDblclickInterval (dblclick_interval); + if ( ! (_argc && _argv) ) { static char* empty = C_STR(""); @@ -558,7 +564,7 @@ inline FWidget* FApplication::findKeyboardWidget() inline void FApplication::keyboardBufferTimeout (FWidget*) { // Empty the buffer on timeout - if ( fifo_in_use && isKeyTimeout(&time_keypressed, key_timeout) ) + if ( fifo_in_use && isKeypressTimeout(&time_keypressed) ) { fifo_offset = 0; key = 0; @@ -688,7 +694,7 @@ inline void FApplication::sendEscapeKeyPressEvent (FWidget* widget) && fifo_offset == 1 && fifo_buf[0] == 0x1b && fifo_buf[1] == 0x00 - && isKeyTimeout(&time_keypressed, key_timeout) ) + && isKeypressTimeout(&time_keypressed) ) { FKeyEvent k_press_ev (fc::KeyPress_Event, fc::Fkey_escape); sendEvent (widget, &k_press_ev); @@ -783,7 +789,7 @@ void FApplication::processKeyboardEvent() } // read the rest from the fifo buffer - while ( ! widget->isKeyTimeout(&time_keypressed, key_timeout) + while ( ! widget->isKeypressTimeout(&time_keypressed) && fifo_offset > 0 && key != NEED_MORE_DATA ) { @@ -1265,7 +1271,7 @@ void FApplication::getX11ButtonState (int button) case button1_pressed_move: if ( mouse_position == new_mouse_position && x11_button_state == all_buttons_released - && ! isKeyTimeout(&time_mousepressed, dblclick_interval) ) + && ! isDblclickTimeout(&time_mousepressed) ) { time_mousepressed.tv_sec = 0; time_mousepressed.tv_usec = 0; @@ -1481,7 +1487,7 @@ bool FApplication::parseSGRMouse() case button1_move: if ( mouse_position == new_mouse_position && (((x11_button_state & 0x80) >> 2) + 'M') == released - && ! isKeyTimeout(&time_mousepressed, dblclick_interval) ) + && ! isDblclickTimeout(&time_mousepressed) ) { time_mousepressed.tv_sec = 0; time_mousepressed.tv_usec = 0; diff --git a/src/foptiattr.cpp b/src/foptiattr.cpp index 2519b72b..1cb5b9ef 100644 --- a/src/foptiattr.cpp +++ b/src/foptiattr.cpp @@ -3,7 +3,7 @@ * * * This file is part of the Final Cut widget toolkit * * * -* Copyright 2016-2017 Markus Gans * +* Copyright 2016-2018 Markus Gans * * * * The Final Cut is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * diff --git a/src/fterm.cpp b/src/fterm.cpp index f673d491..8f68e311 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -57,6 +57,8 @@ int FTerm::clr_bol_length; int FTerm::clr_eol_length; int FTerm::cursor_addres_lengths; uInt FTerm::baudrate; +long FTerm::key_timeout; +long FTerm::dblclick_interval; bool FTerm::resize_term; bool FTerm::mouse_support; bool FTerm::decscusr_support; @@ -270,27 +272,6 @@ fc::freebsdConsoleCursorStyle FTerm::getFreeBSDConsoleCursorStyle() } #endif -//---------------------------------------------------------------------- -bool FTerm::isKeyTimeout (timeval* time, register long timeout) -{ - register long diff_usec; - struct timeval now; - struct timeval diff; - - FObject::getCurrentTime(&now); - diff.tv_sec = now.tv_sec - time->tv_sec; - diff.tv_usec = now.tv_usec - time->tv_usec; - - if ( diff.tv_usec < 0 ) - { - diff.tv_sec--; - diff.tv_usec += 1000000; - } - - diff_usec = (diff.tv_sec * 1000000) + diff.tv_usec; - return ( diff_usec > timeout ); -} - //---------------------------------------------------------------------- bool FTerm::isNormal (char_data*& ch) { @@ -465,113 +446,30 @@ int FTerm::parseKeyString ( char buffer[] , int buf_size , timeval* time_keypressed ) { - static const long key_timeout = 100000; // 100 ms - register uChar firstchar = uChar(buffer[0]); - register std::size_t buf_len = std::strlen(buffer); - int key, len, n; + uChar firstchar = uChar(buffer[0]); if ( firstchar == ESC[0] ) { - // x11 mouse tracking - if ( buf_len >= 6 && buffer[1] == '[' && buffer[2] == 'M' ) - return fc::Fkey_mouse; + int key = getMouseProtocolKey(buffer); - // SGR mouse tracking - if ( buffer[1] == '[' && buffer[2] == '<' && buf_len >= 9 - && (buffer[buf_len - 1] == 'M' || buffer[buf_len - 1] == 'm') ) - return fc::Fkey_extended_mouse; + if ( key > 0 ) + return key; - // urxvt mouse tracking - if ( buffer[1] == '[' && buffer[2] >= '1' && buffer[2] <= '9' - && buffer[3] >= '0' && buffer[3] <= '9' && buf_len >= 9 - && buffer[buf_len - 1] == 'M' ) - return fc::Fkey_urxvt_mouse; + key = getTermcapKey(buffer, buf_size); - // look for termcap keys - for (int i = 0; fc::Fkey[i].tname[0] != 0; i++) - { - char* k = fc::Fkey[i].string; - len = ( k ) ? int(std::strlen(k)) : 0; + if ( key > 0 ) + return key; - if ( k && std::strncmp(k, buffer, uInt(len)) == 0 ) // found - { - for (n = len; n < buf_size; n++) // Remove founded entry - buffer[n - len] = buffer[n]; + key = getMetaKey(buffer, buf_size, time_keypressed); - for (; n - len < len; n++) // Fill rest with '\0' - buffer[n - len] = '\0'; + if ( key > 0 ) + return key; - input_data_pending = bool(buffer[0] != '\0'); - return fc::Fkey[i].num; - } - } - - // look for meta keys - for (int i = 0; fc::Fmetakey[i].string[0] != 0; i++) - { - char* kmeta = fc::Fmetakey[i].string; // The string is never null - len = int(std::strlen(kmeta)); - - if ( std::strncmp(kmeta, buffer, uInt(len)) == 0 ) // found - { - if ( len == 2 && ( buffer[1] == 'O' - || buffer[1] == '[' - || buffer[1] == ']' ) ) - { - if ( ! isKeyTimeout(time_keypressed, key_timeout) ) - return NEED_MORE_DATA; - } - - for (n = len; n < buf_size; n++) // Remove founded entry - buffer[n - len] = buffer[n]; - - for (; n - len < len; n++) // Fill rest with '\0' - buffer[n - len] = '\0'; - - input_data_pending = bool(buffer[0] != '\0'); - return fc::Fmetakey[i].num; - } - } - - if ( ! isKeyTimeout(time_keypressed, key_timeout) ) + if ( ! isKeypressTimeout(time_keypressed) ) return NEED_MORE_DATA; } - // look for utf-8 character - - len = 1; - - if ( utf8_input && (firstchar & 0xc0) == 0xc0 ) - { - char utf8char[4] = {}; // init array with '\0' - - if ( (firstchar & 0xe0) == 0xc0 ) - len = 2; - else if ( (firstchar & 0xf0) == 0xe0 ) - len = 3; - else if ( (firstchar & 0xf8) == 0xf0 ) - len = 4; - - for (n = 0; n < len ; n++) - utf8char[n] = char(buffer[n] & 0xff); - - key = UTF8decode(utf8char); - } - else - key = uChar(buffer[0] & 0xff); - - for (n = len; n < buf_size; n++) // remove the key from the buffer front - buffer[n - len] = buffer[n]; - - for (n = n - len; n < buf_size; n++) // fill the rest with '\0' bytes - buffer[n] = '\0'; - - input_data_pending = bool(buffer[0] != '\0'); - - if ( key == 0 ) // Ctrl+Space or Ctrl+@ - key = fc::Fckey_space; - - return int(key == 127 ? fc::Fkey_backspace : key); + return getSingleKey(buffer, buf_size); } //---------------------------------------------------------------------- @@ -1950,6 +1848,27 @@ void FTerm::exitWithMessage (std::string message) // private methods of FTerm +//---------------------------------------------------------------------- +bool FTerm::isTimeout (timeval* time, register long timeout) +{ + register long diff_usec; + struct timeval now; + struct timeval diff; + + FObject::getCurrentTime(&now); + diff.tv_sec = now.tv_sec - time->tv_sec; + diff.tv_usec = now.tv_usec - time->tv_usec; + + if ( diff.tv_usec < 0 ) + { + diff.tv_sec--; + diff.tv_usec += 1000000; + } + + diff_usec = (diff.tv_sec * 1000000) + diff.tv_usec; + return ( diff_usec > timeout ); +} + //---------------------------------------------------------------------- #if defined(__linux__) int FTerm::isLinuxConsole() @@ -2686,6 +2605,12 @@ void FTerm::init_global_values() // a.b.c = a * 100 + b * 100 + c gnome_terminal_id = 0; + // Set default timeout for keypress + key_timeout = 100000; // 100 ms + + // Set the default double click interval + dblclick_interval = 500000; // 500 ms + // Preset to false utf8_console = \ utf8_input = \ @@ -2728,6 +2653,10 @@ void FTerm::init_global_values() // Init arrays with '\0' std::fill_n (exit_message, sizeof(exit_message), '\0'); + // Initialize the structs + color_env.setDefault(); + secondary_da.setDefault(); + if ( ! init_values.terminal_detection ) terminal_detection = false; } @@ -3210,7 +3139,7 @@ inline char* FTerm::secDA_Analysis_0 (char current_termtype[]) //---------------------------------------------------------------------- inline char* FTerm::secDA_Analysis_1 (char current_termtype[]) { - // Terminal ID 1 - DEC VT220 + // Terminal ID 1 - DEC VT220 char* new_termtype = current_termtype; @@ -4405,7 +4334,7 @@ void FTerm::redefineColorPalette() setPalette (fc::Blue, 0x22, 0x22, 0xb2); setPalette (fc::Green, 0x18, 0x78, 0x18); setPalette (fc::Cyan, 0x4a, 0x4a, 0xe4); - setPalette (fc::Red, 0xb2, 0x18, 0x18); + setPalette (fc::Red, 0xba, 0x1a, 0x1a); setPalette (fc::Magenta, 0xb2, 0x18, 0xb2); setPalette (fc::Brown, 0xe8, 0x87, 0x1f); setPalette (fc::LightGray, 0xbc, 0xbc, 0xbc); @@ -4413,7 +4342,7 @@ void FTerm::redefineColorPalette() setPalette (fc::LightBlue, 0x80, 0xa4, 0xec); setPalette (fc::LightGreen, 0x5e, 0xeb, 0x5c); setPalette (fc::LightCyan, 0x62, 0xbf, 0xf8); - setPalette (fc::LightRed, 0xed, 0x57, 0x31); + setPalette (fc::LightRed, 0xee, 0x44, 0x44); setPalette (fc::LightMagenta, 0xe9, 0xad, 0xff); setPalette (fc::Yellow, 0xfb, 0xe8, 0x67); setPalette (fc::White, 0xff, 0xff, 0xff); @@ -4845,6 +4774,139 @@ uInt FTerm::cp437_to_unicode (uChar c) return ucs; } +//---------------------------------------------------------------------- +inline int FTerm::getMouseProtocolKey (char buffer[]) +{ + // Looking for mouse string in the key buffer + register std::size_t buf_len = std::strlen(buffer); + + // x11 mouse tracking + if ( buf_len >= 6 && buffer[1] == '[' && buffer[2] == 'M' ) + return fc::Fkey_mouse; + + // SGR mouse tracking + if ( buffer[1] == '[' && buffer[2] == '<' && buf_len >= 9 + && (buffer[buf_len - 1] == 'M' || buffer[buf_len - 1] == 'm') ) + return fc::Fkey_extended_mouse; + + // urxvt mouse tracking + if ( buffer[1] == '[' && buffer[2] >= '1' && buffer[2] <= '9' + && buffer[3] >= '0' && buffer[3] <= '9' && buf_len >= 9 + && buffer[buf_len - 1] == 'M' ) + return fc::Fkey_urxvt_mouse; + + return -1; +} + +//---------------------------------------------------------------------- +inline int FTerm::getTermcapKey (char buffer[], int buf_size) +{ + // Looking for termcap key strings in the buffer + assert ( buf_size > 0 ); + + register int len, n; + + for (int i = 0; fc::Fkey[i].tname[0] != 0; i++) + { + char* k = fc::Fkey[i].string; + len = ( k ) ? int(std::strlen(k)) : 0; + + if ( k && std::strncmp(k, buffer, uInt(len)) == 0 ) // found + { + for (n = len; n < buf_size; n++) // Remove founded entry + buffer[n - len] = buffer[n]; + + for (; n - len < len; n++) // Fill rest with '\0' + buffer[n - len] = '\0'; + + input_data_pending = bool(buffer[0] != '\0'); + return fc::Fkey[i].num; + } + } + + return -1; +} + +//---------------------------------------------------------------------- +inline int FTerm::getMetaKey ( char buffer[] + , int buf_size + , timeval* time_keypressed ) +{ + // Looking for meta key strings in the buffer + assert ( buf_size > 0 ); + + register int len, n; + + for (int i = 0; fc::Fmetakey[i].string[0] != 0; i++) + { + char* kmeta = fc::Fmetakey[i].string; // The string is never null + len = int(std::strlen(kmeta)); + + if ( std::strncmp(kmeta, buffer, uInt(len)) == 0 ) // found + { + if ( len == 2 && ( buffer[1] == 'O' + || buffer[1] == '[' + || buffer[1] == ']' ) ) + { + if ( ! isKeypressTimeout(time_keypressed) ) + return NEED_MORE_DATA; + } + + for (n = len; n < buf_size; n++) // Remove founded entry + buffer[n - len] = buffer[n]; + + for (; n - len < len; n++) // Fill rest with '\0' + buffer[n - len] = '\0'; + + input_data_pending = bool(buffer[0] != '\0'); + return fc::Fmetakey[i].num; + } + } + + return -1; +} + +//---------------------------------------------------------------------- +int FTerm::getSingleKey (char buffer[], int buf_size) +{ + register uChar firstchar = uChar(buffer[0]); + int key, n, len; + len = 1; + + // Look for a utf-8 character + if ( utf8_input && (firstchar & 0xc0) == 0xc0 ) + { + char utf8char[4] = {}; // Init array with '\0' + + if ( (firstchar & 0xe0) == 0xc0 ) + len = 2; + else if ( (firstchar & 0xf0) == 0xe0 ) + len = 3; + else if ( (firstchar & 0xf8) == 0xf0 ) + len = 4; + + for (int i = 0; i < len ; i++) + utf8char[i] = char(buffer[i] & 0xff); + + key = UTF8decode(utf8char); + } + else + key = uChar(buffer[0] & 0xff); + + for (n = len; n < buf_size; n++) // Remove the key from the buffer front + buffer[n - len] = buffer[n]; + + for (n = n - len; n < buf_size; n++) // Fill the rest with '\0' bytes + buffer[n] = '\0'; + + input_data_pending = bool(buffer[0] != '\0'); + + if ( key == 0 ) // Ctrl+Space or Ctrl+@ + key = fc::Fckey_space; + + return int(key == 127 ? fc::Fkey_backspace : key); +} + //---------------------------------------------------------------------- void FTerm::setSignalHandler() {