diff --git a/ChangeLog b/ChangeLog index 9777cb82..f7dcfd4d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2020-11-01 Markus Gans + * Now FINAL CUT queues keyboard and mouse input to speed up + the processing of widget events + 2020-10-22 Markus Gans * Repair terminal update skipping diff --git a/examples/opti-move.cpp b/examples/opti-move.cpp index 79f9c359..dfeb007c 100644 --- a/examples/opti-move.cpp +++ b/examples/opti-move.cpp @@ -27,10 +27,6 @@ #include - -// Global FApplication object -static finalcut::FApplication* app{nullptr}; - // function prototype bool keyPressed(); void term_boundaries (int&, int&); @@ -66,8 +62,8 @@ bool keyPressed() void term_boundaries (int& x, int& y) { // checks and corrects the terminal boundaries - const auto term_width = int(app->getDesktopWidth()); - const auto term_height = int(app->getDesktopHeight()); + const auto term_width = int(finalcut::FTerm::getColumnNumber()); + const auto term_height = int(finalcut::FTerm::getLineNumber()); if ( x < 0 ) x = 0; @@ -226,9 +222,6 @@ int main (int argc, char* argv[]) if ( finalcut::FApplication::isQuit() ) return 0; - // Pointer to the global virtual terminal object - app = &term_app; - // Get screen dimension auto xmax = int(term_app.getDesktopWidth() - 1); auto ymax = int(term_app.getDesktopHeight() - 1); @@ -282,7 +275,5 @@ int main (int argc, char* argv[]) // Waiting for keypress keyPressed(); - app = nullptr; // End of term_app object scope - return 0; } diff --git a/src/fapplication.cpp b/src/fapplication.cpp index 4421a77d..bdb19250 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -46,11 +46,19 @@ namespace finalcut { -// Global application object -static FApplication* app_object{nullptr}; +namespace internal +{ -// Flag to exit the local event loop -static bool app_exit_loop{false}; +struct var +{ + static FApplication* app_object; // Global application object + static bool exit_loop; // Flag to exit the local event loop +}; + +FApplication* var::app_object {nullptr}; +bool var::exit_loop {false}; + +} // namespace internal // Static attributes FWidget* FWidget::main_widget {nullptr}; // main application widget @@ -66,7 +74,7 @@ int FApplication::loop_level {0}; // event loop level int FApplication::quit_code {EXIT_SUCCESS}; bool FApplication::quit_now {false}; uInt64 FApplication::next_event_wait {5000}; // preset to 5 ms (200 Hz) -struct timeval FApplication::time_last_event{}; +struct timeval FApplication::time_last_event {}; //---------------------------------------------------------------------- @@ -83,7 +91,7 @@ FApplication::FApplication (const int& _argc, char* _argv[]) if ( quit_now ) return; - if ( app_object ) + if ( internal::var::app_object ) { auto ftermdata = FTerm::getFTermData(); ftermdata->setExitMessage("FApplication: There should be " @@ -93,7 +101,7 @@ FApplication::FApplication (const int& _argc, char* _argv[]) } // First define the application object - app_object = this; + internal::var::app_object = this; if ( ! (_argc && _argv) ) { @@ -109,7 +117,7 @@ FApplication::FApplication (const int& _argc, char* _argv[]) //---------------------------------------------------------------------- FApplication::~FApplication() // destructor { - app_object = nullptr; + internal::var::app_object = nullptr; if ( eventInQueue() ) event_queue.clear(); @@ -122,7 +130,7 @@ FApplication::~FApplication() // destructor //---------------------------------------------------------------------- FApplication* FApplication::getApplicationObject() { - return app_object; + return internal::var::app_object; } //---------------------------------------------------------------------- @@ -162,7 +170,7 @@ void FApplication::setLog (const FLogPtr& log) //---------------------------------------------------------------------- bool FApplication::isQuit() { - return ( app_object ) ? quit_now : true; + return ( internal::var::app_object ) ? quit_now : true; } //---------------------------------------------------------------------- @@ -185,13 +193,13 @@ int FApplication::enterLoop() // event loop loop_level++; quit_now = false; - const bool old_app_exit_loop = app_exit_loop; - app_exit_loop = false; + const bool old_app_exit_loop = internal::var::exit_loop; + internal::var::exit_loop = false; - while ( ! (quit_now || app_exit_loop) ) + while ( ! (quit_now || internal::var::exit_loop) ) processNextEvent(); - app_exit_loop = old_app_exit_loop; + internal::var::exit_loop = old_app_exit_loop; loop_level--; return 0; } @@ -199,7 +207,7 @@ int FApplication::enterLoop() // event loop //---------------------------------------------------------------------- void FApplication::exitLoop() const { - app_exit_loop = true; + internal::var::exit_loop = true; } //---------------------------------------------------------------------- @@ -218,7 +226,7 @@ void FApplication::quit() const //---------------------------------------------------------------------- bool FApplication::sendEvent (FObject* receiver, FEvent* event ) { - if ( quit_now || app_exit_loop || ! (bool(receiver) && bool(event)) ) + if ( quit_now || internal::var::exit_loop || ! (bool(receiver) && bool(event)) ) return false; if ( ! isEventProcessable (receiver, event) ) @@ -256,7 +264,7 @@ void FApplication::sendQueuedEvents() //---------------------------------------------------------------------- bool FApplication::eventInQueue() const { - if ( app_object ) + if ( internal::var::app_object ) return ( ! event_queue.empty() ); else return false; @@ -358,7 +366,7 @@ void FApplication::setKeyboardWidget (FWidget* widget) //---------------------------------------------------------------------- void FApplication::closeConfirmationDialog (FWidget* w, FCloseEvent* ev) { - app_object->unsetMoveSizeMode(); + internal::var::app_object->unsetMoveSizeMode(); const int ret = FMessageBox::info ( w, "Quit" , "Do you really want\n" "to quit the program ?" @@ -402,31 +410,39 @@ void FApplication::init() // Initialize keyboard keyboard = FTerm::getFKeyboard(); - // Set the keyboard keypress timeout + if ( keyboard ) { auto cmd1 = std::bind(&FApplication::keyPressed, this); auto cmd2 = std::bind(&FApplication::keyReleased, this); auto cmd3 = std::bind(&FApplication::escapeKeyPressed, this); + auto cmd4 = std::bind(&FApplication::mouseTracking, this); FKeyboardCommand key_cmd1 (cmd1); FKeyboardCommand key_cmd2 (cmd2); FKeyboardCommand key_cmd3 (cmd3); + FKeyboardCommand key_cmd4 (cmd4); keyboard->setPressCommand (key_cmd1); keyboard->setReleaseCommand (key_cmd2); keyboard->setEscPressedCommand (key_cmd3); + keyboard->setMouseTrackingCommand (key_cmd4); + // Set the keyboard keypress timeout keyboard->setKeypressTimeout (key_timeout); } // Initialize mouse control mouse = FTerm::getFMouseControl(); - // Set stdin number for a gpm-mouse if ( mouse ) + { + using namespace std::placeholders; + auto cmd = std::bind(&FApplication::mouseEvent, this, _1); + FMouseCommand mouse_cmd (cmd); + mouse->setEventCommand (mouse_cmd); + // Set stdin number for a gpm-mouse mouse->setStdinNo (FTermios::getStdIn()); - - // Set the default double click interval - if ( mouse ) + // Set the default double click interval mouse->setDblclickInterval (dblclick_interval); + } // Initialize logging if ( ! getStartOptions().logfile_stream.is_open() ) @@ -676,54 +692,71 @@ void FApplication::escapeKeyPressed() const sendEscapeKeyPressEvent(); } +//---------------------------------------------------------------------- +void FApplication::mouseTracking() +{ + performMouseAction(); +} + //---------------------------------------------------------------------- inline void FApplication::performKeyboardAction() { + if ( keyboard->getKey() == fc::Fckey_l ) // Ctrl-L (redraw the screen) + { + redraw(); + } + else + { + const bool acceptKeyDown = sendKeyDownEvent (keyboard_widget); + const bool acceptKeyPress = sendKeyPressEvent (keyboard_widget); + + if ( ! (acceptKeyDown || acceptKeyPress) ) + sendKeyboardAccelerator(); + } +} + +//---------------------------------------------------------------------- +inline void FApplication::performMouseAction() +{ + if ( ! mouse ) + return; + + auto& buffer = keyboard->getKeyBuffer(); + switch ( keyboard->getKey() ) { - case fc::Fckey_l: // Ctrl-L (redraw the screen) - redraw(); - break; - case fc::Fkey_mouse: - if ( mouse ) - { - FKeyboard::keybuffer& buffer = keyboard->getKeyBuffer(); - mouse->setRawData (FMouse::x11, buffer); - keyboard->hasUnprocessedInput() = mouse->hasUnprocessedInput(); - processMouseEvent(); - } + mouse->setRawData (FMouse::x11, buffer); break; case fc::Fkey_extended_mouse: - if ( mouse ) - { - FKeyboard::keybuffer& buffer = keyboard->getKeyBuffer(); - mouse->setRawData (FMouse::sgr, buffer); - keyboard->hasUnprocessedInput() = mouse->hasUnprocessedInput(); - processMouseEvent(); - } + mouse->setRawData (FMouse::sgr, buffer); break; case fc::Fkey_urxvt_mouse: - if ( mouse ) - { - FKeyboard::keybuffer& buffer = keyboard->getKeyBuffer(); - mouse->setRawData (FMouse::urxvt, buffer); - keyboard->hasUnprocessedInput() = mouse->hasUnprocessedInput(); - processMouseEvent(); - } - break; - - default: - const bool acceptKeyDown = sendKeyDownEvent (keyboard_widget); - const bool acceptKeyPress = sendKeyPressEvent (keyboard_widget); - - if ( ! (acceptKeyDown || acceptKeyPress) ) - sendKeyboardAccelerator(); - + mouse->setRawData (FMouse::urxvt, buffer); break; } + + keyboard->hasUnprocessedInput() = mouse->hasUnprocessedInput(); + queuingMouseInput(); +} + +//---------------------------------------------------------------------- +void FApplication::mouseEvent (const FMouseData& md) +{ + determineClickedWidget (md); + + if ( FWidget::getClickedWidget() ) + { + unsetMoveSizeMode(); + closeDropDown (md); + unselectMenubarItems (md); + sendMouseEvent (md); + } + + if ( mouse ) + mouse->drawGpmPointer(); } //---------------------------------------------------------------------- @@ -790,20 +823,62 @@ inline void FApplication::sendKeyboardAccelerator() } //---------------------------------------------------------------------- -void FApplication::processKeyboardEvent() const +inline bool FApplication::hasDataInQueue() const { - if ( quit_now || app_exit_loop ) + if ( keyboard && keyboard->hasDataInQueue() ) + return true; + else if ( mouse && mouse->hasDataInQueue() ) + return true; + + return false; +} + +//---------------------------------------------------------------------- +void FApplication::queuingKeyboardInput() const +{ + if ( quit_now || internal::var::exit_loop || ! keyboard ) return; findKeyboardWidget(); - flush(); keyboard->escapeKeyHandling(); // special case: Esc key keyboard->clearKeyBufferOnTimeout(); + std::fflush(stdout); if ( isKeyPressed() ) keyboard->fetchKeyCode(); } +//---------------------------------------------------------------------- +void FApplication::queuingMouseInput() const +{ + if ( quit_now || internal::var::exit_loop + || ! mouse || ! mouse->hasData() ) + return; + + struct timeval* time_keypressed = keyboard->getKeyPressedTime(); + mouse->processEvent (time_keypressed); + keyboard->hasUnprocessedInput() = mouse->hasUnprocessedInput(); + mouse->clearEvent(); +} + +//---------------------------------------------------------------------- +void FApplication::processKeyboardEvent() const +{ + if ( quit_now || internal::var::exit_loop || ! keyboard ) + return; + + keyboard->processQueuedInput(); +} + +//---------------------------------------------------------------------- +void FApplication::processMouseEvent() const +{ + if ( quit_now || internal::var::exit_loop || ! mouse ) + return; + + mouse->processQueuedInput(); +} + //---------------------------------------------------------------------- bool FApplication::processDialogSwitchAccelerator() const { @@ -859,7 +934,7 @@ bool FApplication::processAccelerator (const FWidget& widget) const return a_ev.isAccepted(); } - if ( quit_now || app_exit_loop ) + if ( quit_now || internal::var::exit_loop ) break; } @@ -867,38 +942,22 @@ bool FApplication::processAccelerator (const FWidget& widget) const } //---------------------------------------------------------------------- -bool FApplication::getMouseEvent() const +void FApplication::determineClickedWidget (const FMouseData& md) { - bool mouse_event_occurred{false}; + clicked_widget = FWidget::getClickedWidget(); - if ( mouse && mouse->hasData() ) - { - struct timeval* time_keypressed = keyboard->getKeyPressedTime(); - mouse->processEvent (time_keypressed); - keyboard->hasUnprocessedInput() = mouse->hasUnprocessedInput(); - mouse_event_occurred = mouse->hasEvent(); - } + if ( clicked_widget ) + return; // The clicked widget was already found - return mouse_event_occurred; -} + if ( ! md.isLeftButtonPressed() + && ! md.isLeftButtonDoubleClick() + && ! md.isRightButtonPressed() + && ! md.isMiddleButtonPressed() + && ! md.isWheelUp() + && ! md.isWheelDown() ) + return; -//---------------------------------------------------------------------- -FWidget*& FApplication::determineClickedWidget() -{ - FWidget*& clicked = FWidget::getClickedWidget(); - - if ( clicked || ! mouse ) - return clicked; - - if ( ! mouse->isLeftButtonPressed() - && ! mouse->isLeftButtonDoubleClick() - && ! mouse->isRightButtonPressed() - && ! mouse->isMiddleButtonPressed() - && ! mouse->isWheelUp() - && ! mouse->isWheelDown() ) - return clicked; - - auto mouse_position = mouse->getPos(); + const auto& mouse_position = md.getPos(); // Determine the window object on the current click position auto window = FWindow::getWindowWidgetAt (mouse_position); @@ -906,12 +965,10 @@ FWidget*& FApplication::determineClickedWidget() if ( window ) { // Determine the widget at the current click position - auto child = window->childWidgetAt (mouse_position); - clicked = ( child != nullptr ) ? child : window; - setClickedWidget (clicked); + auto child = window->childWidgetAt(mouse_position); + clicked_widget = ( child != nullptr ) ? child : window; + setClickedWidget (clicked_widget); } - - return clicked; } //---------------------------------------------------------------------- @@ -919,43 +976,43 @@ void FApplication::unsetMoveSizeMode() const { // Unset the move/size mode - auto move_size = getMoveSizeWidget(); + auto& move_size = getMoveSizeWidget(); if ( move_size ) { - auto w = move_size; - setMoveSizeWidget(nullptr); + FWidget* w{nullptr}; + std::swap(w, move_size); // Clear move_size_widget w->redraw(); } } //---------------------------------------------------------------------- -void FApplication::closeDropDown() const +void FApplication::closeDropDown (const FMouseData& md) const { // Close the open menu - if ( ! mouse || mouse->isMoved() ) + if ( md.isMoved() ) return; - auto mouse_position = mouse->getPos(); + const auto& mouse_position = md.getPos(); finalcut::closeDropDown (this, mouse_position); } //---------------------------------------------------------------------- -void FApplication::unselectMenubarItems() const +void FApplication::unselectMenubarItems (const FMouseData& md) const { // Unselect the menu bar items const auto& openmenu = FWidget::getOpenMenu(); auto menu_bar = FWidget::getMenuBar(); - if ( openmenu || (mouse && mouse->isMoved()) ) + if ( openmenu || md.isMoved() ) return; - if ( ! (menu_bar && menu_bar->hasSelectedItem() && mouse) ) + if ( ! (menu_bar && menu_bar->hasSelectedItem()) ) return; - const auto& mouse_position = mouse->getPos(); + const auto& mouse_position = md.getPos(); if ( ! menu_bar->getTermGeometry().contains(mouse_position) ) { @@ -975,116 +1032,102 @@ void FApplication::unselectMenubarItems() const } //---------------------------------------------------------------------- -void FApplication::sendMouseEvent() const +void FApplication::sendMouseEvent (const FMouseData& md) const { - auto clicked = FWidget::getClickedWidget(); - - if ( ! (clicked && mouse) ) - return; - - const auto& mouse_position = mouse->getPos(); + const auto& mouse_position = md.getPos(); int key_state{0}; - if ( mouse->isShiftKeyPressed() ) + if ( md.isShiftKeyPressed() ) key_state |= fc::ShiftButton; - if ( mouse->isControlKeyPressed() ) + if ( md.isControlKeyPressed() ) key_state |= fc::ControlButton; - if ( mouse->isMetaKeyPressed() ) + if ( md.isMetaKeyPressed() ) key_state |= fc::MetaButton; - const auto& widgetMousePos = clicked->termToWidgetPos(mouse_position); + const auto& widgetMousePos = clicked_widget->termToWidgetPos(mouse_position); - if ( mouse->isMoved() ) + if ( md.isMoved() ) { - sendMouseMoveEvent (widgetMousePos, mouse_position, key_state); + sendMouseMoveEvent (md, widgetMousePos, mouse_position, key_state); } else { - sendMouseLeftClickEvent (widgetMousePos, mouse_position, key_state); - sendMouseRightClickEvent (widgetMousePos, mouse_position, key_state); - sendMouseMiddleClickEvent (widgetMousePos, mouse_position, key_state); + sendMouseLeftClickEvent (md, widgetMousePos, mouse_position, key_state); + sendMouseRightClickEvent (md, widgetMousePos, mouse_position, key_state); + sendMouseMiddleClickEvent (md, widgetMousePos, mouse_position, key_state); } - sendWheelEvent (widgetMousePos, mouse_position); - mouse->clearEvent(); + sendWheelEvent (md, widgetMousePos, mouse_position); } //---------------------------------------------------------------------- -void FApplication::sendMouseMoveEvent ( const FPoint& widgetMousePos +void FApplication::sendMouseMoveEvent ( const FMouseData& md + , const FPoint& widgetMousePos , const FPoint& mouse_position , int key_state ) const { - if ( ! mouse ) - return; - - auto clicked = FWidget::getClickedWidget(); - - if ( mouse->isLeftButtonPressed() ) + if ( md.isLeftButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseMove_Event , widgetMousePos , mouse_position , fc::LeftButton | key_state ); - sendEvent (clicked, &m_down_ev); + sendEvent (clicked_widget, &m_down_ev); } - if ( mouse->isRightButtonPressed() ) + if ( md.isRightButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseMove_Event , widgetMousePos , mouse_position , fc::RightButton | key_state ); - sendEvent (clicked, &m_down_ev); + sendEvent (clicked_widget, &m_down_ev); } - if ( mouse->isMiddleButtonPressed() ) + if ( md.isMiddleButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseMove_Event , widgetMousePos , mouse_position , fc::MiddleButton | key_state ); - sendEvent (clicked, &m_down_ev); + sendEvent (clicked_widget, &m_down_ev); } } //---------------------------------------------------------------------- -void FApplication::sendMouseLeftClickEvent ( const FPoint& widgetMousePos +void FApplication::sendMouseLeftClickEvent ( const FMouseData& md + , const FPoint& widgetMousePos , const FPoint& mouse_position , int key_state ) const { - if ( ! mouse ) - return; - - auto clicked = FWidget::getClickedWidget(); - - if ( mouse->isLeftButtonDoubleClick() ) + if ( md.isLeftButtonDoubleClick() ) { FMouseEvent m_dblclick_ev ( fc::MouseDoubleClick_Event , widgetMousePos , mouse_position , fc::LeftButton | key_state ); - sendEvent (clicked, &m_dblclick_ev); + sendEvent (clicked_widget, &m_dblclick_ev); } - else if ( mouse->isLeftButtonPressed() ) + else if ( md.isLeftButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseDown_Event , widgetMousePos , mouse_position , fc::LeftButton | key_state ); - sendEvent (clicked, &m_down_ev); + sendEvent (clicked_widget, &m_down_ev); } - else if ( mouse->isLeftButtonReleased() ) + else if ( md.isLeftButtonReleased() ) { FMouseEvent m_up_ev ( fc::MouseUp_Event , widgetMousePos , mouse_position , fc::LeftButton | key_state ); - auto released_widget = clicked; + auto released_widget = clicked_widget; - if ( ! mouse->isRightButtonPressed() - && ! mouse->isMiddleButtonPressed() ) + if ( ! md.isRightButtonPressed() + && ! md.isMiddleButtonPressed() ) setClickedWidget(nullptr); sendEvent (released_widget, &m_up_ev); @@ -1092,33 +1135,29 @@ void FApplication::sendMouseLeftClickEvent ( const FPoint& widgetMousePos } //---------------------------------------------------------------------- -void FApplication::sendMouseRightClickEvent ( const FPoint& widgetMousePos +void FApplication::sendMouseRightClickEvent ( const FMouseData& md + , const FPoint& widgetMousePos , const FPoint& mouse_position , int key_state ) const { - if ( ! mouse ) - return; - - auto clicked = FWidget::getClickedWidget(); - - if ( mouse->isRightButtonPressed() ) + if ( md.isRightButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseDown_Event , widgetMousePos , mouse_position , fc::RightButton | key_state ); - sendEvent (clicked, &m_down_ev); + sendEvent (clicked_widget, &m_down_ev); } - else if ( mouse->isRightButtonReleased() ) + else if ( md.isRightButtonReleased() ) { FMouseEvent m_up_ev ( fc::MouseUp_Event , widgetMousePos , mouse_position , fc::RightButton | key_state ); - auto released_widget = clicked; + auto released_widget = clicked_widget; - if ( ! mouse->isLeftButtonPressed() - && ! mouse->isMiddleButtonPressed() ) + if ( ! md.isLeftButtonPressed() + && ! md.isMiddleButtonPressed() ) setClickedWidget(nullptr); sendEvent (released_widget, &m_up_ev); @@ -1126,37 +1165,33 @@ void FApplication::sendMouseRightClickEvent ( const FPoint& widgetMousePos } //---------------------------------------------------------------------- -void FApplication::sendMouseMiddleClickEvent ( const FPoint& widgetMousePos +void FApplication::sendMouseMiddleClickEvent ( const FMouseData& md + , const FPoint& widgetMousePos , const FPoint& mouse_position , int key_state ) const { - if ( ! mouse ) - return; - - auto clicked = FWidget::getClickedWidget(); - - if ( mouse->isMiddleButtonPressed() ) + if ( md.isMiddleButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseDown_Event , widgetMousePos , mouse_position , fc::MiddleButton | key_state ); - sendEvent (clicked, &m_down_ev); + sendEvent (clicked_widget, &m_down_ev); // gnome-terminal sends no released on middle click if ( FTerm::isGnomeTerminal() ) setClickedWidget(nullptr); } - else if ( mouse->isMiddleButtonReleased() ) + else if ( md.isMiddleButtonReleased() ) { FMouseEvent m_up_ev ( fc::MouseUp_Event , widgetMousePos , mouse_position , fc::MiddleButton | key_state ); - auto released_widget = clicked; + auto released_widget = clicked_widget; - if ( ! mouse->isLeftButtonPressed() - && ! mouse->isRightButtonPressed() ) + if ( ! md.isLeftButtonPressed() + && ! md.isRightButtonPressed() ) { setClickedWidget(nullptr); } @@ -1166,32 +1201,28 @@ void FApplication::sendMouseMiddleClickEvent ( const FPoint& widgetMousePos } //---------------------------------------------------------------------- -void FApplication::sendWheelEvent ( const FPoint& widgetMousePos +void FApplication::sendWheelEvent ( const FMouseData& md + , const FPoint& widgetMousePos , const FPoint& mouse_position ) const { - if ( ! mouse ) - return; - - auto clicked = FWidget::getClickedWidget(); - - if ( mouse->isWheelUp() ) + if ( md.isWheelUp() ) { FWheelEvent wheel_ev ( fc::MouseWheel_Event , widgetMousePos , mouse_position , fc::WheelUp ); - auto scroll_over_widget = clicked; + auto scroll_over_widget = clicked_widget; setClickedWidget(nullptr); sendEvent(scroll_over_widget, &wheel_ev); } - if ( mouse->isWheelDown() ) + if ( md.isWheelDown() ) { FWheelEvent wheel_ev ( fc::MouseWheel_Event , widgetMousePos , mouse_position , fc::WheelDown ); - auto scroll_over_widget = clicked; + auto scroll_over_widget = clicked_widget; setClickedWidget(nullptr); sendEvent (scroll_over_widget, &wheel_ev); } @@ -1211,22 +1242,6 @@ FWidget* FApplication::processParameters (const int& argc, char* argv[]) return nullptr; } -//---------------------------------------------------------------------- -void FApplication::processMouseEvent() -{ - if ( ! getMouseEvent() ) - return; - - determineClickedWidget(); - unsetMoveSizeMode(); - closeDropDown(); - unselectMenubarItems(); - sendMouseEvent(); - - if ( mouse ) - mouse->drawGpmPointer(); -} - //---------------------------------------------------------------------- void FApplication::processResizeEvent() const { @@ -1240,7 +1255,7 @@ void FApplication::processResizeEvent() const } FResizeEvent r_ev(fc::Resize_Event); - sendEvent(app_object, &r_ev); + sendEvent(internal::var::app_object, &r_ev); if ( r_ev.isAccepted() ) FTerm::changeTermSizeFinished(); @@ -1284,15 +1299,17 @@ bool FApplication::processNextEvent() uInt num_events{0}; bool is_timeout = isNextEventTimeout(); - if ( is_timeout ) + if ( is_timeout || hasDataInQueue() ) { FObject::getCurrentTime (&time_last_event); - processTerminalUpdate(); // before user input + queuingKeyboardInput(); + queuingMouseInput(); processKeyboardEvent(); processMouseEvent(); processResizeEvent(); - processTerminalUpdate(); // after user input processCloseWidget(); + processTerminalUpdate(); // after terminal changes + flush(); processLogger(); } diff --git a/src/fdialog.cpp b/src/fdialog.cpp index 2748c88d..ef36ef9b 100644 --- a/src/fdialog.cpp +++ b/src/fdialog.cpp @@ -621,7 +621,7 @@ void FDialog::onMouseMove (FMouseEvent* ev) // Mouse event handover to the menu if ( ms.mouse_over_menu ) - passEventToSubMenu (ms, ev); + passEventToSubMenu (ms, std::move(*ev)); leaveZoomButton(ms); // Check zoom button pressed resizeMouseUpMove(ms); // Resize the dialog @@ -1359,7 +1359,7 @@ inline bool FDialog::isMouseOverMenu (const FPoint& termpos) const //---------------------------------------------------------------------- inline void FDialog::passEventToSubMenu ( const MouseStates& ms - , const FMouseEvent* ev ) + , const FMouseEvent&& ev ) { // Mouse event handover to the dialog menu if ( ! ms.mouse_over_menu @@ -1368,7 +1368,7 @@ inline void FDialog::passEventToSubMenu ( const MouseStates& ms const auto& g = ms.termPos; const auto& p = dialog_menu->termToWidgetPos(g); - const int b = ev->getButton(); + const int b = ev.getButton(); try { diff --git a/src/fkeyboard.cpp b/src/fkeyboard.cpp index d8e3b0e7..52e69bc3 100644 --- a/src/fkeyboard.cpp +++ b/src/fkeyboard.cpp @@ -30,10 +30,12 @@ #include #include +#include "final/fapplication.h" #include "final/fkeyboard.h" #include "final/fkey_map.h" #include "final/fobject.h" #include "final/fterm.h" +#include "final/ftermdetection.h" #include "final/ftermios.h" #if defined(__linux__) @@ -46,9 +48,7 @@ namespace finalcut // static class attributes uInt64 FKeyboard::read_blocking_time{100000}; // preset to 100 ms (10 Hz) uInt64 FKeyboard::key_timeout{100000}; // preset to 100 ms (10 Hz) -uInt64 FKeyboard::interval_timeout{33333}; // preset to 33.333 ms (30 Hz) struct timeval FKeyboard::time_keypressed{}; -struct timeval FKeyboard::time_last_request{}; #if defined(__linux__) FTermLinux* FKeyboard::linux{nullptr}; @@ -66,14 +66,14 @@ FKeyboard::FKeyboard() // Initialize keyboard values time_keypressed.tv_sec = 0; time_keypressed.tv_usec = 0; - time_last_request.tv_sec = 0; - time_last_request.tv_usec = 0; // Get the stdin file status flags stdin_status_flags = fcntl(FTermios::getStdIn(), F_GETFL); if ( stdin_status_flags == -1 ) std::abort(); + + term_detection = FTerm::getFTermDetection(); } //---------------------------------------------------------------------- @@ -148,9 +148,9 @@ bool& FKeyboard::hasUnprocessedInput() } //---------------------------------------------------------------------- -bool FKeyboard::isKeyPressed ( uInt64 blocking_time) +bool FKeyboard::isKeyPressed (uInt64 blocking_time) { - if ( has_pending_input || ! isIntervalTimeout() ) + if ( has_pending_input ) return false; fd_set ifds{}; @@ -159,14 +159,26 @@ bool FKeyboard::isKeyPressed ( uInt64 blocking_time) FD_ZERO(&ifds); FD_SET(stdin_no, &ifds); - tv.tv_sec = 0; - tv.tv_usec = suseconds_t(blocking_time); // preset to 100 ms - FObject::getCurrentTime (&time_last_request); - const int result = select (stdin_no + 1, &ifds, nullptr, nullptr, &tv); - has_pending_input = bool( result > 0 ); + tv.tv_sec = tv.tv_usec = 0; // Non-blocking input - if ( has_pending_input && FD_ISSET(stdin_no, &ifds) ) + if ( blocking_time > 0 + && term_detection->hasNonBlockingInputSupport() + && select(stdin_no + 1, &ifds, nullptr, nullptr, &tv) > 0 + && FD_ISSET(stdin_no, &ifds) ) + { + has_pending_input = true; FD_CLR (stdin_no, &ifds); + tv.tv_sec = 0; + } + + tv.tv_usec = suseconds_t(blocking_time); // preset to 100 ms + + if ( ! has_pending_input + && select(stdin_no + 1, &ifds, nullptr, nullptr, &tv) > 0 + && FD_ISSET(stdin_no, &ifds) ) + { + has_pending_input = true; + } return has_pending_input; } @@ -177,6 +189,7 @@ void FKeyboard::clearKeyBuffer() // Empty the buffer fifo_offset = 0; + fkey = 0; key = 0; std::fill_n (fifo_buf, FIFO_BUF_SIZE, '\0'); fifo_in_use = false; @@ -214,6 +227,30 @@ void FKeyboard::escapeKeyHandling() substringKeyHandling(); } +//---------------------------------------------------------------------- +void FKeyboard::processQueuedInput() +{ + while ( ! fkey_queue.empty() ) + { + key = fkey_queue.front(); + fkey_queue.pop(); + + if ( key > 0 ) + { + keyPressed(); + + if ( FApplication::isQuit() ) + return; + + keyReleased(); + + if ( FApplication::isQuit() ) + return; + + key = 0; + } + } +} // private methods of FKeyboard //---------------------------------------------------------------------- @@ -370,12 +407,6 @@ inline bool FKeyboard::isKeypressTimeout() return FObject::isTimeout (&time_keypressed, key_timeout); } -//---------------------------------------------------------------------- -inline bool FKeyboard::isIntervalTimeout() -{ - return FObject::isTimeout (&time_last_request, interval_timeout); -} - //---------------------------------------------------------------------- FKey FKeyboard::UTF8decode (const char utf8[]) const { @@ -440,7 +471,8 @@ void FKeyboard::parseKeyBuffer() ssize_t bytesread{}; FObject::getCurrentTime (&time_keypressed); - while ( (bytesread = readKey()) > 0 ) + while ( fkey_queue.size() < MAX_QUEUE_SIZE + && (bytesread = readKey()) > 0 ) { has_pending_input = false; @@ -454,27 +486,29 @@ void FKeyboard::parseKeyBuffer() // Read the rest from the fifo buffer while ( ! isKeypressTimeout() && fifo_offset > 0 - && key != fc::Fkey_incomplete ) + && fkey != fc::Fkey_incomplete ) { - key = parseKeyString(); - key = keyCorrection(key); + fkey = parseKeyString(); + fkey = keyCorrection(fkey); - if ( key != fc::Fkey_incomplete ) - keyPressed(); - - fifo_offset = int(std::strlen(fifo_buf)); - - if ( key == fc::Fkey_mouse - || key == fc::Fkey_extended_mouse - || key == fc::Fkey_urxvt_mouse ) + if ( fkey == fc::Fkey_mouse + || fkey == fc::Fkey_extended_mouse + || fkey == fc::Fkey_urxvt_mouse ) + { + key = fkey; + mouseTracking(); + fifo_offset = int(std::strlen(fifo_buf)); break; + } + + if ( fkey != fc::Fkey_incomplete ) + { + fkey_queue.push(fkey); + fifo_offset = int(std::strlen(fifo_buf)); + } } - // Send key up event - if ( key > 0 ) - keyReleased(); - - key = 0; + fkey = 0; } read_character = 0; @@ -545,14 +579,13 @@ void FKeyboard::substringKeyHandling() unprocessed_buffer_data = false; if ( fifo_buf[1] == 'O' ) - key = fc::Fmkey_O; + fkey = fc::Fmkey_O; else if ( fifo_buf[1] == '[' ) - key = fc::Fmkey_left_square_bracket; + fkey = fc::Fmkey_left_square_bracket; else - key = fc::Fmkey_right_square_bracket; + fkey = fc::Fmkey_right_square_bracket; - keyPressed(); - keyReleased(); + fkey_queue.push(fkey); } } @@ -574,4 +607,10 @@ void FKeyboard::escapeKeyPressed() const escape_key_cmd.execute(); } +//---------------------------------------------------------------------- +void FKeyboard::mouseTracking() const +{ + mouse_tracking_cmd.execute(); +} + } // namespace finalcut diff --git a/src/fmenu.cpp b/src/fmenu.cpp index 73ba4ee8..96238bc8 100644 --- a/src/fmenu.cpp +++ b/src/fmenu.cpp @@ -279,19 +279,19 @@ void FMenu::onMouseMove (FMouseEvent* ev) if ( ms.mouse_over_submenu ) { - passEventToSubMenu(*ev); // Event handover to sub-menu + passEventToSubMenu(std::move(*ev)); // Event handover to sub-menu return; } if ( ! ms.mouse_over_menu && ms.mouse_over_supermenu ) { - passEventToSuperMenu(*ev); // Event handover to super-menu + passEventToSuperMenu(std::move(*ev)); // Event handover to super-menu return; } if ( ms.mouse_over_menubar ) { - passEventToMenuBar(*ev); // Event handover to the menu bar + passEventToMenuBar(std::move(*ev)); // Event handover to the menu bar return; } @@ -909,7 +909,7 @@ void FMenu::mouseMoveOverBorder (MouseStates& ms) const } //---------------------------------------------------------------------- -void FMenu::passEventToSubMenu (const FMouseEvent& ev) +void FMenu::passEventToSubMenu (const FMouseEvent&& ev) { // Mouse event handover to sub-menu @@ -932,7 +932,7 @@ void FMenu::passEventToSubMenu (const FMouseEvent& ev) } //---------------------------------------------------------------------- -void FMenu::passEventToSuperMenu (const FMouseEvent& ev) +void FMenu::passEventToSuperMenu (const FMouseEvent&& ev) { // Mouse event handover to super-menu @@ -956,7 +956,7 @@ void FMenu::passEventToSuperMenu (const FMouseEvent& ev) } //---------------------------------------------------------------------- -void FMenu::passEventToMenuBar (const FMouseEvent& ev) const +void FMenu::passEventToMenuBar (const FMouseEvent&& ev) const { // Mouse event handover to the menu bar diff --git a/src/fmenubar.cpp b/src/fmenubar.cpp index 5875bb31..889b656f 100644 --- a/src/fmenubar.cpp +++ b/src/fmenubar.cpp @@ -209,7 +209,7 @@ void FMenuBar::onMouseMove (FMouseEvent* ev) // Handle menu entries if ( mouse_down ) - mouseMoveOverList(ev); + mouseMoveOverList(std::move(*ev)); } //---------------------------------------------------------------------- @@ -867,7 +867,7 @@ void FMenuBar::mouseUpOverList (const FMouseEvent* ev) } //---------------------------------------------------------------------- -void FMenuBar::mouseMoveOverList (const FMouseEvent* ev) +void FMenuBar::mouseMoveOverList (const FMouseEvent&& ev) { auto list = getItemList(); @@ -876,10 +876,10 @@ void FMenuBar::mouseMoveOverList (const FMouseEvent* ev) focus_changed = false; bool mouse_over_menubar{false}; - int mouse_x = ev->getX(); - int mouse_y = ev->getY(); + int mouse_x = ev.getX(); + int mouse_y = ev.getY(); - if ( getTermGeometry().contains(ev->getTermPos()) ) + if ( getTermGeometry().contains(ev.getTermPos()) ) mouse_over_menubar = true; for (auto&& item : list) @@ -904,7 +904,7 @@ void FMenuBar::mouseMoveOverList (const FMouseEvent* ev) else { // Event handover to the menu - passEventToMenu(*ev); + passEventToMenu(std::move(ev)); } } } @@ -926,7 +926,7 @@ void FMenuBar::mouseMoveOverList (const FMouseEvent* ev) } //---------------------------------------------------------------------- -void FMenuBar::passEventToMenu (const FMouseEvent& ev) const +void FMenuBar::passEventToMenu (const FMouseEvent&& ev) const { if ( ! hasSelectedItem() || ! getSelectedItem()->hasMenu() ) return; diff --git a/src/fmouse.cpp b/src/fmouse.cpp index ee65eae2..a0a07249 100644 --- a/src/fmouse.cpp +++ b/src/fmouse.cpp @@ -28,6 +28,7 @@ #include #include +#include "final/fapplication.h" #include "final/fconfig.h" #include "final/fkeyboard.h" #include "final/fmouse.h" @@ -39,6 +40,136 @@ namespace finalcut { +//---------------------------------------------------------------------- +// class FMouseData +//---------------------------------------------------------------------- + +// constructors and destructor +//---------------------------------------------------------------------- +FMouseData::FMouseData() +{ } + +//---------------------------------------------------------------------- +FMouseData::~FMouseData() +{ } + +// public methods of FMouseData +//---------------------------------------------------------------------- +FString FMouseData::getClassName() const +{ + return "FMouseData"; +} + +//---------------------------------------------------------------------- +const FPoint& FMouseData::getPos() const +{ + return mouse; +} +//---------------------------------------------------------------------- +bool FMouseData::isLeftButtonPressed() const +{ + return bool(getButtonState().left_button == Pressed); +} + +//---------------------------------------------------------------------- +bool FMouseData::isLeftButtonReleased() const +{ + return bool(getButtonState().left_button == Released); +} + +//---------------------------------------------------------------------- +bool FMouseData::isLeftButtonDoubleClick() const +{ + return bool(getButtonState().left_button == DoubleClick); +} + +//---------------------------------------------------------------------- +bool FMouseData::isRightButtonPressed() const +{ + return bool(getButtonState().right_button == Pressed); +} + +//---------------------------------------------------------------------- +bool FMouseData::isRightButtonReleased() const +{ + return bool(getButtonState().right_button == Released); +} +//---------------------------------------------------------------------- +bool FMouseData::isMiddleButtonPressed() const +{ + return bool(getButtonState().middle_button == Pressed); +} + +//---------------------------------------------------------------------- +bool FMouseData::isMiddleButtonReleased() const +{ + return bool(getButtonState().middle_button == Released); +} + +//---------------------------------------------------------------------- +bool FMouseData::isShiftKeyPressed() const +{ + return bool(getButtonState().shift_button); +} + +//---------------------------------------------------------------------- +bool FMouseData::isControlKeyPressed() const +{ + return bool(getButtonState().control_button); +} + +//---------------------------------------------------------------------- +bool FMouseData::isMetaKeyPressed() const +{ + return bool(getButtonState().meta_button); +} + +//---------------------------------------------------------------------- +bool FMouseData::isWheelUp() const +{ + return bool(getButtonState().wheel_up); +} + +//---------------------------------------------------------------------- +bool FMouseData::isWheelDown() const +{ + return bool(getButtonState().wheel_down); +} + +//---------------------------------------------------------------------- +bool FMouseData::isMoved() const +{ + return bool(getButtonState().mouse_moved); +} + +//---------------------------------------------------------------------- +void FMouseData::clearButtonState() +{ + // Fill bit field with 0 + std::memset(&b_state, 0x00, sizeof(b_state)); +} + + +// protected methods of FMouseData +//---------------------------------------------------------------------- +inline FMouseData::FMouseButton& FMouseData::getButtonState() +{ + return b_state; +} + +//---------------------------------------------------------------------- +inline const FMouseData::FMouseButton& FMouseData::getButtonState() const +{ + return b_state; +} + +//---------------------------------------------------------------------- +void FMouseData::setPos (const FPoint& m) +{ + mouse = m; +} + + //---------------------------------------------------------------------- // class FMouse //---------------------------------------------------------------------- @@ -51,6 +182,10 @@ FMouse::FMouse() clearButtonState(); } +//---------------------------------------------------------------------- +FMouse::~FMouse() // destructor +{ } + // public methods of FMouse //---------------------------------------------------------------------- @@ -59,12 +194,6 @@ FString FMouse::getClassName() const return "FMouse"; } -//---------------------------------------------------------------------- -inline const FPoint& FMouse::getPos() const -{ - return mouse; -} - //---------------------------------------------------------------------- inline void FMouse::clearEvent() { @@ -95,104 +224,14 @@ inline bool FMouse::hasEvent() const return mouse_event_occurred; } -//---------------------------------------------------------------------- -inline bool FMouse::isLeftButtonPressed() -{ - return bool(getButtonState().left_button == Pressed); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isLeftButtonReleased() -{ - return bool(getButtonState().left_button == Released); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isLeftButtonDoubleClick() -{ - return bool(getButtonState().left_button == DoubleClick); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isRightButtonPressed() -{ - return bool(getButtonState().right_button == Pressed); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isRightButtonReleased() -{ - return bool(getButtonState().right_button == Released); -} -//---------------------------------------------------------------------- -inline bool FMouse::isMiddleButtonPressed() -{ - return bool(getButtonState().middle_button == Pressed); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isMiddleButtonReleased() -{ - return bool(getButtonState().middle_button == Released); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isShiftKeyPressed() -{ - return bool(getButtonState().shift_button); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isControlKeyPressed() -{ - return bool(getButtonState().control_button); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isMetaKeyPressed() -{ - return bool(getButtonState().meta_button); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isWheelUp() -{ - return bool(getButtonState().wheel_up); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isWheelDown() -{ - return bool(getButtonState().wheel_down); -} - -//---------------------------------------------------------------------- -inline bool FMouse::isMoved() -{ - return bool(getButtonState().mouse_moved); -} - //---------------------------------------------------------------------- inline bool FMouse::hasUnprocessedInput() const { return unprocessed_buffer_data; } -//---------------------------------------------------------------------- -void FMouse::clearButtonState() -{ - // Fill bit field with 0 - std::memset(&b_state, 0x00, sizeof(b_state)); -} - // protected methods of FMouse -//---------------------------------------------------------------------- -inline FMouse::FMouseButton& FMouse::getButtonState() -{ - return b_state; -} - //---------------------------------------------------------------------- inline const FPoint& FMouse::getNewPos() const { @@ -223,12 +262,6 @@ timeval* FMouse::getMousePressedTime() return &time_mousepressed; } -//---------------------------------------------------------------------- -void FMouse::setPos (const FPoint& m) -{ - mouse = m; -} - //---------------------------------------------------------------------- void FMouse::setNewPos (int x, int y) { @@ -1514,6 +1547,25 @@ void FMouseControl::setRawData ( FMouse::mouse_type mt mouse->setRawData (fifo_buf); } +//---------------------------------------------------------------------- +void FMouseControl::processQueuedInput() +{ + while ( ! fmousedata_queue.empty() ) + { + if ( FApplication::isQuit() ) + return; + + FMouseDataPtr md(std::move(fmousedata_queue.front())); + fmousedata_queue.pop(); + + if ( md.get() ) + event_cmd.execute(*md); + + if ( FApplication::isQuit() ) + return; + } +} + //---------------------------------------------------------------------- void FMouseControl::processEvent (struct timeval* time) { @@ -1522,7 +1574,10 @@ void FMouseControl::processEvent (struct timeval* time) clearEvent(); if ( mouse_object ) + { mouse_object->processEvent(time); + fmousedata_queue.emplace(new FMouseData(std::move(*mouse_object))); + } } //---------------------------------------------------------------------- diff --git a/src/fstring.cpp b/src/fstring.cpp index c2df210d..06814e2d 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp @@ -1512,7 +1512,7 @@ inline const wchar_t* FString::_extractToken ( wchar_t* rest[] if ( ! token[0] ) return nullptr; - *rest = std::wcspbrk(std::move(token), delim); + *rest = std::wcspbrk(token, delim); if ( *rest ) *(*rest)++ = '\0'; diff --git a/src/fterm.cpp b/src/fterm.cpp index d15cd562..ca220c30 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -63,14 +63,21 @@ namespace finalcut { -// Global FTerm object -static FTerm* init_term_object{nullptr}; +namespace internal +{ -// Global init state -static bool term_initialized{false}; +struct var +{ + static FTerm* init_term_object; // Global FTerm object + static bool term_initialized; // Global init state + static uInt object_counter; // Counts the number of object instances +}; -// Counts the number of object instances -static uInt object_counter{0}; +FTerm* var::init_term_object{nullptr}; +bool var::term_initialized{false}; +uInt var::object_counter{0}; + +} // namespace internal // Static class attributes FTermData* FTerm::data {nullptr}; @@ -107,21 +114,21 @@ FMouseControl* FTerm::mouse {nullptr}; //---------------------------------------------------------------------- FTerm::FTerm() { - if ( object_counter == 0 ) + if ( internal::var::object_counter == 0 ) allocationValues(); // Allocation of global objects - object_counter++; + internal::var::object_counter++; } //---------------------------------------------------------------------- FTerm::~FTerm() // destructor { - if ( init_term_object == this ) + if ( internal::var::init_term_object == this ) finish(); // Resetting console settings - object_counter--; + internal::var::object_counter--; - if ( object_counter == 0 ) + if ( internal::var::object_counter == 0 ) { printExitMessage(); deallocationValues(); // Deallocation of global objects @@ -588,7 +595,7 @@ bool FTerm::isNewFont() //---------------------------------------------------------------------- bool FTerm::isInitialized() { - return term_initialized; + return internal::var::term_initialized; } //---------------------------------------------------------------------- @@ -2271,7 +2278,7 @@ inline void FTerm::deallocationValues() //---------------------------------------------------------------------- void FTerm::init() { - init_term_object = this; + internal::var::init_term_object = this; // Initialize global values for all objects init_global_values(); @@ -2359,7 +2366,7 @@ void FTerm::init() FTermios::setRawMode(); // The terminal is now initialized - term_initialized = true; + internal::var::term_initialized = true; } //---------------------------------------------------------------------- @@ -2584,8 +2591,8 @@ void FTerm::terminalSizeChange() //---------------------------------------------------------------------- void FTerm::processTermination (int signum) { - if ( init_term_object ) - init_term_object->finish(); + if ( internal::var::init_term_object ) + internal::var::init_term_object->finish(); std::fflush (stderr); std::fflush (stdout); @@ -2599,8 +2606,8 @@ void FTerm::processTermination (int signum) printExitMessage(); } - if ( init_term_object ) - init_term_object->deallocationValues(); + if ( internal::var::init_term_object ) + internal::var::init_term_object->deallocationValues(); std::terminate(); } diff --git a/src/ftermdetection.cpp b/src/ftermdetection.cpp index 077e04b2..040ee272 100644 --- a/src/ftermdetection.cpp +++ b/src/ftermdetection.cpp @@ -60,6 +60,7 @@ FKeyboard* FTermDetection::keyboard{nullptr}; char FTermDetection::termtype[256]{}; char FTermDetection::ttytypename[256]{}; bool FTermDetection::decscusr_support{}; +bool FTermDetection::non_blocking_input_support{}; bool FTermDetection::terminal_detection{}; bool FTermDetection::color256{}; const FString* FTermDetection::answer_back{nullptr}; @@ -83,6 +84,7 @@ FTermDetection::FTermDetection() { // Preset to true terminal_detection = true; + non_blocking_input_support = true; // Preset to false decscusr_support = false; @@ -405,6 +407,13 @@ void FTermDetection::detectTerminal() std::strncpy (termtype, new_termtype, sizeof(termtype)); termtype[sizeof(termtype) - 1] = '\0'; } + +#if defined(__CYGWIN__) + const auto& termfilename = fterm_data->getTermFileName(); + + if ( std::strncmp(termfilename, "/dev/cons", 9) == 0 ) + non_blocking_input_support = false; // Fixes problem with mouse input +#endif } //---------------------------------------------------------------------- diff --git a/src/fvterm.cpp b/src/fvterm.cpp index 5352546c..c314cebc 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -50,9 +50,6 @@ namespace finalcut { -// global FVTerm object -static FVTerm* init_object{nullptr}; - // static class attributes bool FVTerm::draw_completed{false}; bool FVTerm::no_terminal_updates{false}; @@ -67,6 +64,7 @@ uInt FVTerm::cursor_address_length{}; struct timeval FVTerm::last_term_size_check{}; std::queue* FVTerm::output_buffer{nullptr}; FPoint* FVTerm::term_pos{nullptr}; +const FVTerm* FVTerm::init_object{nullptr}; FSystem* FVTerm::fsystem{nullptr}; FTerm* FVTerm::fterm{nullptr}; FVTerm::FTermArea* FVTerm::vterm{nullptr}; @@ -277,7 +275,6 @@ void FVTerm::updateTerminal() const return; } - skipped_terminal_update = 0; std::size_t changedlines = 0; static constexpr int check_interval = 5; @@ -296,7 +293,7 @@ void FVTerm::updateTerminal() const } } - + skipped_terminal_update = 0; vterm->has_changes = false; // sets the new input cursor position @@ -359,6 +356,7 @@ int FVTerm::print (FTermArea* area, const FString& s) return -1; std::vector term_string{}; + term_string.reserve(s.getLength()); const wchar_t* p = s.wc_str(); if ( p ) @@ -373,7 +371,7 @@ int FVTerm::print (FTermArea* area, const FString& s) nc.attr.byte[1] = next_attribute.attr.byte[1]; nc.attr.byte[2] = 0; nc.attr.byte[3] = 0; - term_string.push_back(nc); + term_string.push_back(std::move(nc)); p++; } // end of while @@ -2755,7 +2753,7 @@ bool FVTerm::updateTerminalLine (uInt y) const { // Updates pending changes from line y to the terminal - bool ret{}; + bool ret{false}; const auto& vt = vterm; uInt& xmin = vt->changes[y].xmin; uInt& xmax = vt->changes[y].xmax; @@ -2766,9 +2764,6 @@ bool FVTerm::updateTerminalLine (uInt y) const bool draw_leading_ws = false; bool draw_trailing_ws = false; const auto& ce = TCAP(fc::t_clr_eol); - auto& first_char = vt->data[y * uInt(vt->width)]; - auto& last_char = vt->data[(y + 1) * uInt(vt->width) - 1]; - auto& min_char = vt->data[y * uInt(vt->width) + xmin]; // Clear rest of line bool is_eol_clean = canClearToEOL (xmin, y); @@ -2786,6 +2781,7 @@ bool FVTerm::updateTerminalLine (uInt y) const if ( is_eol_clean ) { + auto& min_char = vt->data[y * uInt(vt->width) + xmin]; appendAttributes (min_char); appendOutputBuffer (ce); markAsPrinted (xmin, uInt(vt->width - 1), y); @@ -2795,6 +2791,7 @@ bool FVTerm::updateTerminalLine (uInt y) const if ( draw_leading_ws ) { const auto& cb = TCAP(fc::t_clr_bol); + auto& first_char = vt->data[y * uInt(vt->width)]; appendAttributes (first_char); appendOutputBuffer (cb); markAsPrinted (0, xmin, y); @@ -2804,6 +2801,7 @@ bool FVTerm::updateTerminalLine (uInt y) const if ( draw_trailing_ws ) { + auto& last_char = vt->data[(y + 1) * uInt(vt->width) - 1]; appendAttributes (last_char); appendOutputBuffer (ce); markAsPrinted (xmax + 1, uInt(vt->width - 1), y); @@ -2814,8 +2812,6 @@ bool FVTerm::updateTerminalLine (uInt y) const xmin = uInt(vt->width); xmax = 0; } - else - ret = false; cursorWrap(); return ret; diff --git a/src/fwidget.cpp b/src/fwidget.cpp index 2b0ae510..5873c9d0 100644 --- a/src/fwidget.cpp +++ b/src/fwidget.cpp @@ -37,8 +37,17 @@ namespace finalcut { -// global FWidget object -static FWidget* root_widget{nullptr}; +namespace internal +{ + +struct var +{ + static FWidget* root_widget; // global FWidget object +}; + +FWidget* var::root_widget{nullptr}; + +} // namespace internal // static class attributes FStatusBar* FWidget::statusbar{nullptr}; @@ -74,7 +83,7 @@ FWidget::FWidget (FWidget* parent) if ( ! parent ) { - if ( root_widget ) + if ( internal::var::root_widget ) { auto ftermdata = FTerm::getFTermData(); ftermdata->setExitMessage("FWidget: No parent defined! " @@ -134,7 +143,7 @@ FWidget::~FWidget() // destructor accelerator_list.clear(); // finish the program - if ( root_widget == this ) + if ( internal::var::root_widget == this ) finish(); } @@ -496,7 +505,7 @@ void FWidget::setTopPadding (int top, bool adjust) { if ( isRootWidget() ) { - auto r = root_widget; + auto r = internal::var::root_widget; r->wclient_offset.setY1 (r->padding.top); adjustSizeGlobal(); } @@ -517,7 +526,7 @@ void FWidget::setLeftPadding (int left, bool adjust) { if ( isRootWidget() ) { - auto r = root_widget; + auto r = internal::var::root_widget; r->wclient_offset.setX1 (r->padding.left); adjustSizeGlobal(); } @@ -538,7 +547,7 @@ void FWidget::setBottomPadding (int bottom, bool adjust) { if ( isRootWidget() ) { - auto r = root_widget; + auto r = internal::var::root_widget; r->wclient_offset.setY2 (int(r->getHeight()) - 1 - r->padding.bottom); adjustSizeGlobal(); } @@ -559,7 +568,7 @@ void FWidget::setRightPadding (int right, bool adjust) { if ( isRootWidget() ) { - auto r = root_widget; + auto r = internal::var::root_widget; r->wclient_offset.setX2 (int(r->getWidth()) - 1 - r->padding.right); adjustSizeGlobal(); } @@ -575,8 +584,8 @@ void FWidget::setTermSize (const FSize& size) const if ( FTerm::isXTerminal() ) { - root_widget->wsize.setRect(FPoint{1, 1}, size); - root_widget->adjust_wsize = root_widget->wsize; + internal::var::root_widget->wsize.setRect(FPoint{1, 1}, size); + internal::var::root_widget->adjust_wsize = internal::var::root_widget->wsize; FTerm::setTermSize(size); // width = columns / height = lines detectTermSize(); } @@ -944,8 +953,8 @@ void FWidget::show() return; // Initialize desktop on first call - if ( ! init_desktop && root_widget ) - root_widget->initDesktop(); + if ( ! init_desktop && internal::var::root_widget ) + internal::var::root_widget->initDesktop(); if ( ! show_root_widget ) { @@ -1237,8 +1246,8 @@ void FWidget::initTerminal() // Set default foreground and background color of the desktop/terminal auto color_theme = getColorTheme(); - root_widget->foreground_color = color_theme->term_fg; - root_widget->background_color = color_theme->term_bg; + internal::var::root_widget->foreground_color = color_theme->term_fg; + internal::var::root_widget->background_color = color_theme->term_bg; resetColors(); // The terminal is now initialized @@ -1278,7 +1287,7 @@ void FWidget::adjustSize() if ( ignore_padding && ! isDialogWidget() ) setTermOffset(); else - woffset = root_widget->wclient_offset; + woffset = internal::var::root_widget->wclient_offset; } else if ( ignore_padding && p ) { @@ -1674,8 +1683,8 @@ void FWidget::onAccel (FAccelEvent*) void FWidget::onResize (FResizeEvent* ev) { // The terminal was resized - root_widget->resize(); - root_widget->redraw(); + internal::var::root_widget->resize(); + internal::var::root_widget->redraw(); ev->accept(); } @@ -1733,11 +1742,11 @@ void FWidget::initRootWidget() } // Initialize default widget colors - // (before terminal detection and root_widget is set) + // (before terminal detection and internal::var::root_widget is set) initColorTheme(); // Root widget basic initialization - root_widget = this; + internal::var::root_widget = this; show_root_widget = nullptr; redraw_root_widget = nullptr; modal_dialog_counter = 0; @@ -2094,7 +2103,7 @@ void FWidget::setStatusbarText (bool enable) const //---------------------------------------------------------------------- void detectTermSize() { - const auto& r = root_widget; + const auto& r = internal::var::root_widget; FTerm::detectTermSize(); r->adjust_wsize.setRect (1, 1, r->getDesktopWidth(), r->getDesktopHeight()); r->woffset.setRect (0, 0, r->getDesktopWidth(), r->getDesktopHeight()); diff --git a/src/include/final/fapplication.h b/src/include/final/fapplication.h index c57bd424..af494560 100644 --- a/src/include/final/fapplication.h +++ b/src/include/final/fapplication.h @@ -80,6 +80,7 @@ class FEvent; class FFocusEvent; class FKeyEvent; class FLog; +class FMouseData; class FMouseEvent; class FStartOptions; class FTimerEvent; @@ -181,36 +182,47 @@ class FApplication : public FWidget void keyPressed(); void keyReleased() const; void escapeKeyPressed() const; + void mouseTracking(); void performKeyboardAction(); + void performMouseAction(); + void mouseEvent (const FMouseData&); void sendEscapeKeyPressEvent() const; bool sendKeyDownEvent (FWidget*) const; bool sendKeyPressEvent (FWidget*) const; bool sendKeyUpEvent (FWidget*) const; void sendKeyboardAccelerator(); + bool hasDataInQueue() const; + void queuingKeyboardInput() const; + void queuingMouseInput() const; void processKeyboardEvent() const; + void processMouseEvent() const; bool processDialogSwitchAccelerator() const; bool processAccelerator (const FWidget&) const; - bool getMouseEvent() const; - FWidget*& determineClickedWidget(); + void determineClickedWidget (const FMouseData&); void unsetMoveSizeMode() const; - void closeDropDown() const; - void unselectMenubarItems() const; - void sendMouseEvent() const; - void sendMouseMoveEvent ( const FPoint& + void closeDropDown (const FMouseData&) const; + void unselectMenubarItems (const FMouseData&) const; + void sendMouseEvent (const FMouseData&) const; + void sendMouseMoveEvent ( const FMouseData& + , const FPoint& , const FPoint& , int ) const; - void sendMouseLeftClickEvent ( const FPoint& + void sendMouseLeftClickEvent ( const FMouseData& + , const FPoint& , const FPoint& , int ) const; - void sendMouseRightClickEvent ( const FPoint& + void sendMouseRightClickEvent ( const FMouseData& + , const FPoint& , const FPoint& , int ) const; - void sendMouseMiddleClickEvent ( const FPoint& + void sendMouseMiddleClickEvent ( const FMouseData& + , const FPoint& , const FPoint& , int ) const; - void sendWheelEvent (const FPoint&, const FPoint&) const; + void sendWheelEvent ( const FMouseData& + , const FPoint& + , const FPoint& ) const; static FWidget* processParameters (const int&, char*[]); - void processMouseEvent(); void processResizeEvent() const; void processCloseWidget(); void processLogger() const; @@ -225,6 +237,7 @@ class FApplication : public FWidget uInt64 key_timeout{100000}; // 100 ms uInt64 dblclick_interval{500000}; // 500 ms std::streambuf* default_clog_rdbuf{std::clog.rdbuf()}; + FWidget* clicked_widget{}; FEventQueue event_queue{}; static uInt64 next_event_wait; static timeval time_last_event; diff --git a/src/include/final/fdialog.h b/src/include/final/fdialog.h index 16ac4f30..fd4ea073 100644 --- a/src/include/final/fdialog.h +++ b/src/include/final/fdialog.h @@ -195,7 +195,7 @@ class FDialog : public FWindow void pressZoomButton (const MouseStates&); bool isMouseOverMenu (const FPoint&) const; void passEventToSubMenu ( const MouseStates& - , const FMouseEvent* ); + , const FMouseEvent&& ); void moveSizeKey (FKeyEvent*); void raiseActivateDialog(); void lowerActivateDialog(); diff --git a/src/include/final/fkeyboard.h b/src/include/final/fkeyboard.h index bc7276e5..a7b6d3b9 100644 --- a/src/include/final/fkeyboard.h +++ b/src/include/final/fkeyboard.h @@ -40,6 +40,7 @@ #include #include #include +#include #include "final/fkey_map.h" #include "final/fstring.h" @@ -51,6 +52,7 @@ namespace finalcut // class forward declaration class FApplication; class FString; +class FTermDetection; class FTermLinux; //---------------------------------------------------------------------- @@ -127,9 +129,11 @@ class FKeyboard final void setPressCommand (const FKeyboardCommand&); void setReleaseCommand (const FKeyboardCommand&); void setEscPressedCommand (const FKeyboardCommand&); + void setMouseTrackingCommand (const FKeyboardCommand&); // Inquiry bool hasPendingInput() const; + bool hasDataInQueue() const; // Methods static void init(); @@ -139,6 +143,7 @@ class FKeyboard final void clearKeyBufferOnTimeout(); void fetchKeyCode(); void escapeKeyHandling(); + void processQueuedInput(); private: // Using-declaration @@ -146,6 +151,7 @@ class FKeyboard final // Constants static constexpr FKey NOT_SET = static_cast(-1); + static constexpr std::size_t MAX_QUEUE_SIZE = 32; // Accessors FKey getMouseProtocolKey() const; @@ -167,23 +173,26 @@ class FKeyboard final void keyPressed() const; void keyReleased() const; void escapeKeyPressed() const; + void mouseTracking() const; // Data members FKeyboardCommand keypressed_cmd{}; FKeyboardCommand keyreleased_cmd{}; FKeyboardCommand escape_key_cmd{}; + FKeyboardCommand mouse_tracking_cmd{}; #if defined(__linux__) #undef linux static FTermLinux* linux; #endif + FTermDetection* term_detection{nullptr}; static timeval time_keypressed; - static timeval time_last_request; static uInt64 read_blocking_time; static uInt64 key_timeout; - static uInt64 interval_timeout; FKeyMapPtr key_map{}; + std::queue fkey_queue{}; + FKey fkey{0}; FKey key{0}; uChar read_character{}; char fifo_buf[FIFO_BUF_SIZE]{'\0'}; @@ -247,6 +256,10 @@ inline bool FKeyboard::unsetNonBlockingInput() inline bool FKeyboard::hasPendingInput() const { return has_pending_input; } +//---------------------------------------------------------------------- +inline bool FKeyboard::hasDataInQueue() const +{ return ! fkey_queue.empty(); } + //---------------------------------------------------------------------- inline void FKeyboard::enableUTF8() { utf8_input = true; } @@ -275,6 +288,10 @@ inline void FKeyboard::setReleaseCommand (const FKeyboardCommand& cmd) inline void FKeyboard::setEscPressedCommand (const FKeyboardCommand& cmd) { escape_key_cmd = cmd; } +//---------------------------------------------------------------------- +inline void FKeyboard::setMouseTrackingCommand (const FKeyboardCommand& cmd) +{ mouse_tracking_cmd = cmd; } + } // namespace finalcut #endif // FKEYBOARD_H diff --git a/src/include/final/fmenu.h b/src/include/final/fmenu.h index 81bd4cb1..ceeeda0e 100644 --- a/src/include/final/fmenu.h +++ b/src/include/final/fmenu.h @@ -192,9 +192,9 @@ class FMenu : public FWindow, public FMenuList void mouseMoveDeselection (FMenuItem*, MouseStates&); void mouseUpOverBorder(); void mouseMoveOverBorder (MouseStates&) const; - void passEventToSubMenu (const FMouseEvent&); - void passEventToSuperMenu (const FMouseEvent&); - void passEventToMenuBar (const FMouseEvent&) const; + void passEventToSubMenu (const FMouseEvent&&); + void passEventToSuperMenu (const FMouseEvent&&); + void passEventToMenuBar (const FMouseEvent&&) const; bool containsMenuStructure (const FPoint&); bool containsMenuStructure (int, int); FMenu* superMenuAt (const FPoint&); diff --git a/src/include/final/fmenubar.h b/src/include/final/fmenubar.h index 1760cab5..4807386b 100644 --- a/src/include/final/fmenubar.h +++ b/src/include/final/fmenubar.h @@ -139,8 +139,8 @@ class FMenuBar : public FWindow, public FMenuList void selectMenuItem (FMenuItem*); void mouseDownOverList (const FMouseEvent*); void mouseUpOverList (const FMouseEvent*); - void mouseMoveOverList (const FMouseEvent*); - void passEventToMenu (const FMouseEvent&) const; + void mouseMoveOverList (const FMouseEvent&&); + void passEventToMenu (const FMouseEvent&&) const; void leaveMenuBar(); // Data members diff --git a/src/include/final/fmouse.h b/src/include/final/fmouse.h index f16e172f..28ad2800 100644 --- a/src/include/final/fmouse.h +++ b/src/include/final/fmouse.h @@ -23,6 +23,11 @@ /* Inheritance diagram * ═══════════════════ * + * ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏ + * ▕ FMouseData ▏ + * ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏ + * ▲ + * │ * ▕▔▔▔▔▔▔▔▔▔▔▏ * ▕ FMouse ▏ * ▕▁▁▁▁▁▁▁▁▁▁▏ @@ -61,7 +66,9 @@ #endif #include +#include #include +#include #include "final/fkeyboard.h" #include "final/fpoint.h" @@ -78,63 +85,47 @@ namespace finalcut { //---------------------------------------------------------------------- -// class FMouse +// class FMouseData //---------------------------------------------------------------------- - -class FMouse +class FMouseData { public: - // Enumeration - enum mouse_type - { - none = 0, - gpm = 1, - x11 = 2, - sgr = 3, - urxvt = 4 - }; - - // Constructor - FMouse(); - - // Destructor - virtual ~FMouse() - { } - // Accessors virtual FString getClassName() const; const FPoint& getPos() const; - void clearEvent(); - // Mutators - void setMaxWidth (uInt16); - void setMaxHeight (uInt16); - void setDblclickInterval (const uInt64); + // Constructor + FMouseData(); + + // Default copy constructor + FMouseData (const FMouseData&) = default; + // Default move constructor + FMouseData (FMouseData&&) = default; + // Default copy assignment operator (=) + FMouseData& operator = (const FMouseData&) = default; + // Default move assignment operator (=) + FMouseData& operator = (FMouseData&&) = default; + + // Destructor + virtual ~FMouseData(); // Inquiries - virtual bool hasData() = 0; - bool hasEvent() const; - bool isLeftButtonPressed(); - bool isLeftButtonReleased(); - bool isLeftButtonDoubleClick(); - bool isRightButtonPressed(); - bool isRightButtonReleased(); - bool isMiddleButtonPressed(); - bool isMiddleButtonReleased(); - bool isShiftKeyPressed(); - bool isControlKeyPressed(); - bool isMetaKeyPressed(); - bool isWheelUp(); - bool isWheelDown(); - bool isMoved(); - bool hasUnprocessedInput() const; + bool isLeftButtonPressed() const; + bool isLeftButtonReleased() const; + bool isLeftButtonDoubleClick() const; + bool isRightButtonPressed() const; + bool isRightButtonReleased() const; + bool isMiddleButtonPressed() const; + bool isMiddleButtonReleased() const; + bool isShiftKeyPressed() const; + bool isControlKeyPressed() const; + bool isMetaKeyPressed() const; + bool isWheelUp() const; + bool isWheelDown() const; + bool isMoved() const; // Methods - template - static FMouse* createMouseObject (); void clearButtonState(); - virtual void setRawData (FKeyboard::keybuffer&) = 0; - virtual void processEvent (struct timeval*) = 0; protected: // Typedef and Enumerations @@ -162,34 +153,88 @@ class FMouse // Accessors FMouseButton& getButtonState(); - const FPoint& getNewPos() const; - uInt16 getMaxWidth() const; - uInt16 getMaxHeight() const; - uInt64 getDblclickInterval() const; - timeval* getMousePressedTime(); + const FMouseButton& getButtonState() const; // Mutator void setPos (const FPoint&); - void setNewPos (int, int); - void setPending (bool); - void setEvent(); - void setMousePressedTime (const timeval*); - void resetMousePressedTime(); - - // Inquiry - bool isDblclickTimeout (const timeval*) const; private: // Data members FMouseButton b_state{}; - bool mouse_event_occurred{false}; - bool unprocessed_buffer_data{false}; - uInt16 max_width{80}; - uInt16 max_height{25}; - uInt64 dblclick_interval{500000}; // 500 ms - struct timeval time_mousepressed{}; - FPoint mouse{0, 0}; // mouse click position - FPoint new_mouse_position{}; + FPoint mouse{0, 0}; // mouse click position +}; + + +//---------------------------------------------------------------------- +// class FMouse +//---------------------------------------------------------------------- + +class FMouse : public FMouseData +{ + public: + // Enumeration + enum mouse_type + { + none = 0, + gpm = 1, + x11 = 2, + sgr = 3, + urxvt = 4 + }; + + // Constructor + FMouse(); + + // Destructor + ~FMouse() override; + + // Accessors + FString getClassName() const override; + void clearEvent(); + + // Mutators + void setMaxWidth (uInt16); + void setMaxHeight (uInt16); + void setDblclickInterval (const uInt64); + + // Inquiries + virtual bool hasData() = 0; + bool hasEvent() const; + bool hasUnprocessedInput() const; + + // Methods + template + static FMouse* createMouseObject (); + virtual void setRawData (FKeyboard::keybuffer&) = 0; + virtual void processEvent (struct timeval*) = 0; + + protected: + // Accessors + const FPoint& getNewPos() const; + uInt16 getMaxWidth() const; + uInt16 getMaxHeight() const; + uInt64 getDblclickInterval() const; + timeval* getMousePressedTime(); + + // Mutator + void setNewPos (int, int); + void setPending (bool); + void setEvent(); + void setMousePressedTime (const timeval*); + void resetMousePressedTime(); + + // Inquiry + bool isDblclickTimeout (const timeval*) const; + + private: + // Data members + bool mouse_event_occurred{false}; + bool unprocessed_buffer_data{false}; + uInt16 max_width{80}; + uInt16 max_height{25}; + uInt64 dblclick_interval{500000}; // 500 ms + struct timeval time_mousepressed{}; + FPoint new_mouse_position{}; }; //---------------------------------------------------------------------- @@ -446,6 +491,32 @@ class FMouseUrxvt final : public FMouse }; +//---------------------------------------------------------------------- +// class FMouseCommand +//---------------------------------------------------------------------- + +class FMouseCommand final +{ + public: + // Constructors + FMouseCommand () = default; + explicit FMouseCommand (const std::function& fn) + : handler(fn) + { } + + // Method + template + void execute(T&& arg) const + { + handler(std::forward(arg)); + } + + private: + // Data members + std::function handler{}; +}; + + //---------------------------------------------------------------------- // class FMouseControl //---------------------------------------------------------------------- @@ -466,62 +537,68 @@ class FMouseControl FMouseControl& operator = (const FMouseControl&) = delete; // Accessors - virtual FString getClassName() const; - const FPoint& getPos(); - void clearEvent(); + virtual FString getClassName() const; + const FPoint& getPos(); + void clearEvent(); // Mutators - void setStdinNo (int); - void setMaxWidth (uInt16); - void setMaxHeight (uInt16); - void setDblclickInterval (const uInt64); - void useGpmMouse (bool = true); - void useXtermMouse (bool = true); + void setStdinNo (int); + void setMaxWidth (uInt16); + void setMaxHeight (uInt16); + void setDblclickInterval (const uInt64); + void setEventCommand (const FMouseCommand&); + void useGpmMouse (bool = true); + void useXtermMouse (bool = true); // Inquiries - bool hasData(); - bool hasEvent(); - bool isLeftButtonPressed(); - bool isLeftButtonReleased(); - bool isLeftButtonDoubleClick(); - bool isRightButtonPressed(); - bool isRightButtonReleased(); - bool isMiddleButtonPressed(); - bool isMiddleButtonReleased(); - bool isShiftKeyPressed(); - bool isControlKeyPressed(); - bool isMetaKeyPressed(); - bool isWheelUp(); - bool isWheelDown(); - bool isMoved(); - bool hasUnprocessedInput(); - bool isGpmMouseEnabled(); + bool hasData(); + bool hasEvent(); + bool isLeftButtonPressed(); + bool isLeftButtonReleased(); + bool isLeftButtonDoubleClick(); + bool isRightButtonPressed(); + bool isRightButtonReleased(); + bool isMiddleButtonPressed(); + bool isMiddleButtonReleased(); + bool isShiftKeyPressed(); + bool isControlKeyPressed(); + bool isMetaKeyPressed(); + bool isWheelUp(); + bool isWheelDown(); + bool isMoved(); + bool hasUnprocessedInput(); + bool hasDataInQueue() const; + bool isGpmMouseEnabled(); // Methods - void enable(); - void disable(); - virtual void setRawData ( FMouse::mouse_type - , FKeyboard::keybuffer& ); - virtual void processEvent (struct timeval* time); - bool getGpmKeyPressed (bool); - void drawGpmPointer(); + void enable(); + void disable(); + virtual void setRawData ( FMouse::mouse_type + , FKeyboard::keybuffer& ); + virtual void processEvent (struct timeval* time); + void processQueuedInput(); + bool getGpmKeyPressed (bool); + void drawGpmPointer(); private: // Typedef typedef std::map FMouseProtocol; + typedef std::unique_ptr FMouseDataPtr; // Accessor - FMouse* getMouseWithData(); - FMouse* getMouseWithEvent(); - void xtermMouse (bool) const; - void enableXTermMouse() const; - void disableXTermMouse() const; + FMouse* getMouseWithData(); + FMouse* getMouseWithEvent(); + void xtermMouse (bool) const; + void enableXTermMouse() const; + void disableXTermMouse() const; // Data member - FMouseProtocol mouse_protocol{}; - FPoint zero_point{0, 0}; - bool use_gpm_mouse{false}; - bool use_xterm_mouse{false}; + FMouseProtocol mouse_protocol{}; + FMouseCommand event_cmd{}; + std::queue fmousedata_queue{}; + FPoint zero_point{0, 0}; + bool use_gpm_mouse{false}; + bool use_xterm_mouse{false}; }; // FMouseControl inline functions @@ -529,6 +606,14 @@ class FMouseControl inline FString FMouseControl::getClassName() const { return "FMouseControl"; } +//---------------------------------------------------------------------- +inline void FMouseControl::setEventCommand (const FMouseCommand& cmd) +{ event_cmd = cmd; } + +//---------------------------------------------------------------------- +inline bool FMouseControl::hasDataInQueue() const +{ return ! fmousedata_queue.empty(); } + //---------------------------------------------------------------------- inline void FMouseControl::enableXTermMouse() const { xtermMouse(true); } diff --git a/src/include/final/ftermdetection.h b/src/include/final/ftermdetection.h index 89798b87..0fff311a 100644 --- a/src/include/final/ftermdetection.h +++ b/src/include/final/ftermdetection.h @@ -128,6 +128,7 @@ class FTermDetection final static bool isMltermTerminal(); static bool canDisplay256Colors(); static bool hasTerminalDetection(); + static bool hasNonBlockingInputSupport(); static bool hasSetCursorStyleSupport(); // Mutators @@ -203,6 +204,7 @@ class FTermDetection final static char termtype[256]; static char ttytypename[256]; static bool decscusr_support; + static bool non_blocking_input_support; static bool terminal_detection; static bool color256; static int gnome_terminal_id; @@ -277,6 +279,10 @@ inline const char* FTermDetection::getTermType_SecDA() inline bool FTermDetection::canDisplay256Colors() { return color256; } +//---------------------------------------------------------------------- +inline bool FTermDetection::hasNonBlockingInputSupport() +{ return non_blocking_input_support; } + //---------------------------------------------------------------------- inline bool FTermDetection::hasSetCursorStyleSupport() { return decscusr_support; } diff --git a/src/include/final/fvterm.h b/src/include/final/fvterm.h index f5bacd49..e59093dc 100644 --- a/src/include/final/fvterm.h +++ b/src/include/final/fvterm.h @@ -427,6 +427,7 @@ class FVTerm FTermArea* print_area{nullptr}; // print area for this object FTermArea* child_print_area{nullptr}; // print area for children FTermArea* vwin{nullptr}; // virtual window + static const FVTerm* init_object; // Global FVTerm object static FSystem* fsystem; static FTerm* fterm; static FTermArea* vterm; // virtual terminal diff --git a/test/fkeyboard-test.cpp b/test/fkeyboard-test.cpp index 867a0153..b58ef0a9 100644 --- a/test/fkeyboard-test.cpp +++ b/test/fkeyboard-test.cpp @@ -49,6 +49,24 @@ void check_c_string ( const char* s1 ::CppUnit::Asserter::fail ("Strings are not equal", sourceLine); } +namespace finalcut +{ + +namespace internal +{ + +struct var +{ + // Global application object is need for FApplication::isQuit() + static FApplication* app_object; +}; + +FApplication* var::app_object {nullptr}; +} // namespace internal + +} // namespace finalcut + + namespace test { @@ -311,6 +329,7 @@ class FKeyboardTest : public CPPUNIT_NS::TestFixture void keyPressed(); void keyReleased(); void escapeKeyPressed(); + void mouseTracking(); // Data members FKey key_pressed{0}; @@ -2152,6 +2171,7 @@ void FKeyboardTest::metaKeyTest() const struct timespec ms[]{{0, 100000000L}}; nanosleep (ms, NULL); keyboard->escapeKeyHandling(); + keyboard->processQueuedInput(); std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl; CPPUNIT_ASSERT ( key_pressed == finalcut::fc::Fmkey_O ); clear(); @@ -2239,6 +2259,7 @@ void FKeyboardTest::metaKeyTest() // Wait 100 ms - Substring keys needs a timeout nanosleep (ms, NULL); keyboard->escapeKeyHandling(); + keyboard->processQueuedInput(); std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl; CPPUNIT_ASSERT ( key_pressed == finalcut::fc::Fmkey_left_square_bracket ); clear(); @@ -2256,6 +2277,7 @@ void FKeyboardTest::metaKeyTest() // Wait 100 ms - Substring keys needs a timeout nanosleep (ms, NULL); keyboard->escapeKeyHandling(); + keyboard->processQueuedInput(); std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl; CPPUNIT_ASSERT ( key_pressed == finalcut::fc::Fmkey_right_square_bracket ); clear(); @@ -2954,16 +2976,21 @@ void FKeyboardTest::unknownKeyTest() //---------------------------------------------------------------------- void FKeyboardTest::init() { + finalcut::internal::var::app_object \ + = reinterpret_cast(this); // Need for isQuit() keyboard = new finalcut::FKeyboard(); auto cmd1 = std::bind(&FKeyboardTest::keyPressed, this); auto cmd2 = std::bind(&FKeyboardTest::keyReleased, this); auto cmd3 = std::bind(&FKeyboardTest::escapeKeyPressed, this); + auto cmd4 = std::bind(&FKeyboardTest::mouseTracking, this); finalcut::FKeyboardCommand key_cmd1 (cmd1); finalcut::FKeyboardCommand key_cmd2 (cmd2); finalcut::FKeyboardCommand key_cmd3 (cmd3); + finalcut::FKeyboardCommand key_cmd4 (cmd4); keyboard->setPressCommand (key_cmd1); keyboard->setReleaseCommand (key_cmd2); keyboard->setEscPressedCommand (key_cmd3); + keyboard->setMouseTrackingCommand (key_cmd4); keyboard->setKeypressTimeout (100000); // 100 ms processInput(); CPPUNIT_ASSERT ( key_pressed == 0 ); @@ -3008,6 +3035,7 @@ void FKeyboardTest::processInput() if ( keyboard->isKeyPressed() ) keyboard->fetchKeyCode(); + keyboard->processQueuedInput(); // Keyboard interval timeout 75 ms (= 75,000,000 ns) const struct timespec ms[]{{0, 75000000L}}; nanosleep (ms, NULL); @@ -3043,6 +3071,12 @@ void FKeyboardTest::escapeKeyPressed() number_of_keys++; } +//---------------------------------------------------------------------- +void FKeyboardTest::mouseTracking() +{ + key_pressed = keyboard->getKey(); +} + // Put the test suite in the registry CPPUNIT_TEST_SUITE_REGISTRATION (FKeyboardTest);