From dcea675e5b4525ecd511013e6e1d3bfab17a98cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sat, 24 May 2025 20:48:42 -0300 Subject: [PATCH] Fix input methods that depend on OpenKey, Unikey and similar software. Fix flashing cursor on Windows! How this was not reported?! Fix crash when closing ecode on Windows and tabs with same name where present. --- include/eepp/ui/doc/textdocument.hpp | 4 + include/eepp/ui/uicodeeditor.hpp | 1 + include/eepp/ui/uiconsole.hpp | 1 + include/eepp/ui/uitextinput.hpp | 1 + src/eepp/ui/doc/textdocument.cpp | 15 ++++ src/eepp/ui/uicodeeditor.cpp | 12 +-- src/eepp/ui/uiconsole.cpp | 4 +- src/eepp/ui/uitextinput.cpp | 4 +- src/tools/ecode/ecode.cpp | 116 ++++++++++++++------------- src/tools/ecode/settingsmenu.cpp | 3 + 10 files changed, 100 insertions(+), 61 deletions(-) diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index 623791748..518227204 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -37,6 +37,10 @@ struct DocumentContentChange { class EE_API TextDocument { public: + static bool isTextDocummentCommand( std::string_view cmd ); + + static bool isTextDocummentCommand( String::HashType cmdHash ); + enum class UndoRedo { Undo, Redo }; enum class IndentType { IndentSpaces, IndentTabs }; diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index 6e26bacd8..a7795b9fa 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -920,6 +920,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { std::vector mPluginTopSpaces; Float mPluginsTopSpace{ 0 }; Uint64 mLastExecuteEventId{ 0 }; + String::HashType mLastCmdHash{ 0 }; Text mLineTextCache; size_t mJumpLinesLength{ 5 }; UIIcon* mFileLockIcon{ nullptr }; diff --git a/include/eepp/ui/uiconsole.hpp b/include/eepp/ui/uiconsole.hpp index da8430bce..8cac7eac2 100644 --- a/include/eepp/ui/uiconsole.hpp +++ b/include/eepp/ui/uiconsole.hpp @@ -189,6 +189,7 @@ class EE_API UIConsole : public UIWidget, Float mQuakeModeHeightPercent{ 0.6f }; #endif Uint64 mLastExecuteEventId{ 0 }; + String::HashType mLastCmdHash{ 0 }; UIPopUpMenu* mCurrentMenu{ nullptr }; size_t mMenuIconSize{ 16 }; diff --git a/include/eepp/ui/uitextinput.hpp b/include/eepp/ui/uitextinput.hpp index 66ae3323a..28b94f770 100644 --- a/include/eepp/ui/uitextinput.hpp +++ b/include/eepp/ui/uitextinput.hpp @@ -145,6 +145,7 @@ class EE_API UITextInput : public UITextView, public TextDocument::Client { size_t mMenuIconSize{ 16 }; UIPopUpMenu* mCurrentMenu{ nullptr }; Uint64 mLastExecuteEventId{ 0 }; + String::HashType mLastCmdHash{ 0 }; HintDisplay mHintDisplay{ HintDisplay::Always }; void resetWaitCursor(); diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index 92a14addb..a1c5f2c4b 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -26,6 +26,16 @@ namespace EE { namespace UI { namespace Doc { static constexpr char DEFAULT_NON_WORD_CHARS[] = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"; +static UnorderedSet TEXT_DOCUMENT_COMMANDS = {}; + +bool TextDocument::isTextDocummentCommand( std::string_view cmd ) { + return TEXT_DOCUMENT_COMMANDS.contains( String::hash( cmd ) ); +} + +bool TextDocument::isTextDocummentCommand( String::HashType cmdHash ) { + return TEXT_DOCUMENT_COMMANDS.contains( cmdHash ); +} + bool TextDocument::isNonWord( String::StringBaseType ch ) const { return mNonWordChars.find_first_of( ch ) != String::InvalidPos; } @@ -3793,6 +3803,11 @@ void TextDocument::initializeCommands() { mCommands["unescape"] = [this] { unescape(); }; mCommands["to-base64"] = [this] { toBase64(); }; mCommands["from-base64"] = [this] { fromBase64(); }; + + if ( TEXT_DOCUMENT_COMMANDS.empty() ) { + for ( const auto& [cmd, _] : mCommands ) + TEXT_DOCUMENT_COMMANDS.insert( String::hash( cmd ) ); + } } TextRange TextDocument::getTopMostCursor() { diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 2cfdd77a3..6b9763c03 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -1078,7 +1078,8 @@ Uint32 UICodeEditor::onTextInput( const TextInputEvent& event ) { input->isMetaPressed() || ( input->isLeftAltPressed() && !input->isLeftControlPressed() ) ) return 0; - if ( mLastExecuteEventId == getUISceneNode()->getWindow()->getInput()->getEventsSentId() ) + if ( mLastExecuteEventId == getUISceneNode()->getWindow()->getInput()->getEventsSentId() && + !TextDocument::isTextDocummentCommand( mLastCmdHash ) ) return 0; mDoc->textInput( event.getText() ); @@ -1291,11 +1292,16 @@ Uint32 UICodeEditor::onKeyDown( const KeyEvent& event ) { // Allow copy selection on locked mode if ( !mLocked || mUnlockedCmd.find( cmd ) != mUnlockedCmd.end() ) { mDoc->execute( cmd, this ); + mLastCmdHash = String::hash( cmd ); mLastExecuteEventId = getUISceneNode()->getWindow()->getInput()->getEventsSentId(); return 1; } } + return 0; +} + +Uint32 UICodeEditor::onKeyUp( const KeyEvent& event ) { if ( isEnabledFlashCursor() && event.getSanitizedMod() == KeyMod::getDefaultModifier() ) { if ( mModDownCount == 0 ) mModDownClock.restart(); @@ -1312,10 +1318,6 @@ Uint32 UICodeEditor::onKeyDown( const KeyEvent& event ) { mModDownClock.restart(); } - return 0; -} - -Uint32 UICodeEditor::onKeyUp( const KeyEvent& event ) { mLastActivity.restart(); for ( auto& plugin : mPlugins ) if ( plugin->onKeyUp( this, event ) ) diff --git a/src/eepp/ui/uiconsole.cpp b/src/eepp/ui/uiconsole.cpp index 3e2009fe3..583e0423b 100644 --- a/src/eepp/ui/uiconsole.cpp +++ b/src/eepp/ui/uiconsole.cpp @@ -920,6 +920,7 @@ Uint32 UIConsole::onKeyDown( const KeyEvent& event ) { std::string cmd = mKeyBindings.getCommandFromKeyBind( { event.getKeyCode(), event.getMod() } ); if ( !cmd.empty() ) { mDoc.execute( cmd ); + mLastCmdHash = String::hash( cmd ); mLastExecuteEventId = getUISceneNode()->getWindow()->getInput()->getEventsSentId(); return 1; } @@ -935,7 +936,8 @@ Uint32 UIConsole::onTextInput( const TextInputEvent& event ) { input->isMetaPressed() || ( input->isLeftAltPressed() && !input->isLeftControlPressed() ) ) return 0; - if ( mLastExecuteEventId == getUISceneNode()->getWindow()->getInput()->getEventsSentId() ) + if ( mLastExecuteEventId == getUISceneNode()->getWindow()->getInput()->getEventsSentId() && + !TextDocument::isTextDocummentCommand( mLastCmdHash ) ) return 0; const String& text = event.getText(); diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index 9e626a729..4418e3acf 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -770,6 +770,7 @@ Uint32 UITextInput::onKeyDown( const KeyEvent& event ) { // Allow copy selection on locked mode if ( mAllowEditing ) { mDoc.execute( cmd ); + mLastCmdHash = String::hash( cmd ); mLastExecuteEventId = getUISceneNode()->getWindow()->getInput()->getEventsSentId(); return 1; } @@ -788,7 +789,8 @@ Uint32 UITextInput::onTextInput( const TextInputEvent& event ) { input->isMetaPressed() || ( input->isLeftAltPressed() && !input->isLeftControlPressed() ) ) return 0; - if ( mLastExecuteEventId == getUISceneNode()->getWindow()->getInput()->getEventsSentId() ) + if ( mLastExecuteEventId == getUISceneNode()->getWindow()->getInput()->getEventsSentId() && + !TextDocument::isTextDocummentCommand( mLastCmdHash ) ) return 0; const String& text = event.getText(); diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 015a1ab69..0f8197f85 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1786,67 +1786,73 @@ std::map App::getDefaultKeybindings() { std::map App::getLocalKeybindings() { return { { { KEY_RETURN, KEYMOD_LALT | KEYMOD_LCTRL }, "fullscreen-toggle" }, - { { KEY_F3, KEYMOD_NONE }, "repeat-find" }, - { { KEY_F3, KEYMOD_SHIFT }, "find-prev" }, - { { KEY_F12, KEYMOD_NONE }, "console-toggle" }, - { { KEY_F, KeyMod::getDefaultModifier() }, "find-replace" }, - { { KEY_Q, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "close-app" }, - { { KEY_O, KeyMod::getDefaultModifier() }, "open-file" }, - { { KEY_W, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "download-file-web" }, - { { KEY_O, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "open-folder" }, - { { KEY_F11, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "debug-widget-tree-view" }, - { { KEY_K, KeyMod::getDefaultModifier() }, "open-locatebar" }, - { { KEY_P, KeyMod::getDefaultModifier() }, "open-command-palette" }, - { { KEY_F, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "open-global-search" }, - { { KEY_L, KeyMod::getDefaultModifier() }, "go-to-line" }, + { { KEY_F3, KEYMOD_NONE }, "repeat-find" }, { { KEY_F3, KEYMOD_SHIFT }, "find-prev" }, + { { KEY_F12, KEYMOD_NONE }, "console-toggle" }, + { { KEY_F, KeyMod::getDefaultModifier() }, "find-replace" }, + { { KEY_Q, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "close-app" }, + { { KEY_O, KeyMod::getDefaultModifier() }, "open-file" }, + { { KEY_W, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "download-file-web" }, + { { KEY_O, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "open-folder" }, + { { KEY_F11, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "debug-widget-tree-view" }, + { { KEY_K, KeyMod::getDefaultModifier() }, "open-locatebar" }, + { { KEY_P, KeyMod::getDefaultModifier() }, "open-command-palette" }, + { { KEY_F, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "open-global-search" }, + { { KEY_L, KeyMod::getDefaultModifier() }, "go-to-line" }, #if EE_PLATFORM == EE_PLATFORM_MACOS - { { KEY_M, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "menu-toggle" }, + { { KEY_M, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "menu-toggle" }, #else - { { KEY_M, KeyMod::getDefaultModifier() }, "menu-toggle" }, + { { KEY_M, KeyMod::getDefaultModifier() }, "menu-toggle" }, #endif - { { KEY_S, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "save-all" }, - { { KEY_F9, KEYMOD_LALT }, "switch-side-panel" }, - { { KEY_J, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, - "terminal-split-left" }, - { { KEY_L, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, - "terminal-split-right" }, - { { KEY_I, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, - "terminal-split-top" }, - { { KEY_K, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, - "terminal-split-bottom" }, - { { KEY_S, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, - "terminal-split-swap" }, - { { KEY_T, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, - "reopen-closed-tab" }, - { { KEY_1, KEYMOD_LALT }, "toggle-status-locate-bar" }, - { { KEY_2, KEYMOD_LALT }, "toggle-status-global-search-bar" }, - { { KEY_3, KEYMOD_LALT }, "toggle-status-terminal" }, - { { KEY_4, KEYMOD_LALT }, "toggle-status-build-output" }, - { { KEY_5, KEYMOD_LALT }, "toggle-status-app-output" }, - { { KEY_B, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "project-build-start-cancel" }, - { { KEY_C, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "project-build-cancel" }, - { { KEY_R, KeyMod::getDefaultModifier() }, "project-build-and-run" }, - { { KEY_O, KEYMOD_LALT | KEYMOD_SHIFT }, "show-open-documents" }, - { { KEY_K, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "open-workspace-symbol-search" }, - { { KEY_P, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "open-document-symbol-search" }, - { { KEY_N, KEYMOD_SHIFT | KEYMOD_LALT }, "create-new-window" }, + { { KEY_S, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "save-all" }, + { { KEY_F9, KEYMOD_LALT }, "switch-side-panel" }, + { { KEY_J, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, + "terminal-split-left" }, + { { KEY_L, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, + "terminal-split-right" }, + { { KEY_I, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, + "terminal-split-top" }, + { { KEY_K, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, + "terminal-split-bottom" }, + { { KEY_S, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, + "terminal-split-swap" }, + { { KEY_T, KeyMod::getDefaultModifier() | KEYMOD_LALT | KEYMOD_SHIFT }, + "reopen-closed-tab" }, + { { KEY_1, KEYMOD_LALT }, "toggle-status-locate-bar" }, + { { KEY_2, KEYMOD_LALT }, "toggle-status-global-search-bar" }, + { { KEY_3, KEYMOD_LALT }, "toggle-status-terminal" }, + { { KEY_4, KEYMOD_LALT }, "toggle-status-build-output" }, + { { KEY_5, KEYMOD_LALT }, "toggle-status-app-output" }, + { { KEY_B, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, + "project-build-start-cancel" }, + { { KEY_C, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, "project-build-cancel" }, + { { KEY_R, KeyMod::getDefaultModifier() }, "project-build-and-run" }, + { { KEY_O, KEYMOD_LALT | KEYMOD_SHIFT }, "show-open-documents" }, + { { KEY_K, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, + "open-workspace-symbol-search" }, + { { KEY_P, KeyMod::getDefaultModifier() | KEYMOD_SHIFT }, + "open-document-symbol-search" }, + { { KEY_N, KEYMOD_SHIFT | KEYMOD_LALT }, "create-new-window" }, }; } // Old keybindings will be rebinded to the new keybindings when they are still set to the old // keybindind std::map App::getMigrateKeybindings() { - return { { "fullscreen-toggle", "alt+return" }, { "switch-to-tab-1", "alt+1" }, - { "switch-to-tab-2", "alt+2" }, { "switch-to-tab-3", "alt+3" }, - { "switch-to-tab-4", "alt+4" }, { "switch-to-tab-5", "alt+5" }, - { "switch-to-tab-6", "alt+6" }, { "switch-to-tab-7", "alt+7" }, - { "switch-to-tab-8", "alt+8" }, { "switch-to-tab-9", "alt+9" }, - { "switch-to-last-tab", "alt+0" }, + return { + { "fullscreen-toggle", "alt+return" }, { "switch-to-tab-1", "alt+1" }, + { "switch-to-tab-2", "alt+2" }, { "switch-to-tab-3", "alt+3" }, + { "switch-to-tab-4", "alt+4" }, { "switch-to-tab-5", "alt+5" }, + { "switch-to-tab-6", "alt+6" }, { "switch-to-tab-7", "alt+7" }, + { "switch-to-tab-8", "alt+8" }, { "switch-to-tab-9", "alt+9" }, + { "switch-to-last-tab", "alt+0" }, #if EE_PLATFORM == EE_PLATFORM_MACOS - { "menu-toggle", "mod+shift+m" }, + { "menu-toggle", "mod+shift+m" }, #endif - { "lock-toggle", "mod+shift+l" }, { "debug-widget-tree-view", "f11" }, - { "project-build-and-run", "f5" }, { "project-build-start", "mod+shift+b" } }; + { "lock-toggle", "mod+shift+l" }, { "debug-widget-tree-view", "f11" }, + { "project-build-and-run", "f5" }, { + "project-build-start", "mod+shift+b" + } + }; } std::vector App::getUnlockedCommands() { @@ -2482,7 +2488,8 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { } editor->on( Event::OnClose, [this, editor]( auto ) { - if ( editor->hasClass( NOT_UNIQUE_FILENAME ) ) + if ( SceneManager::existsSingleton() && !SceneManager::instance()->isShuttingDown() && + editor->hasClass( NOT_UNIQUE_FILENAME ) ) updateNonUniqueTabTitles(); } ); @@ -3491,9 +3498,10 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe mConfig.windowState.pixelDensity = pidelDensity > 0 ? pidelDensity - : ( mConfig.windowState.pixelDensity > 0 ? mConfig.windowState.pixelDensity - : currentDisplay->getPixelDensity() > 2 ? currentDisplay->getPixelDensity() / 2 - : currentDisplay->getPixelDensity() ); + : ( mConfig.windowState.pixelDensity > 0 + ? mConfig.windowState.pixelDensity + : currentDisplay->getPixelDensity() > 2 ? currentDisplay->getPixelDensity() / 2 + : currentDisplay->getPixelDensity() ); #else mConfig.windowState.pixelDensity = pidelDensity > 0 diff --git a/src/tools/ecode/settingsmenu.cpp b/src/tools/ecode/settingsmenu.cpp index 0c6140140..39cdc4d34 100644 --- a/src/tools/ecode/settingsmenu.cpp +++ b/src/tools/ecode/settingsmenu.cpp @@ -742,6 +742,9 @@ UIMenu* SettingsMenu::createDocumentMenu() { mApp->getConfig().workspace.sessionSnapshot = item->isActive(); } else if ( "allow_flash_cursor" == id ) { mApp->getConfig().editor.flashCursor = item->isActive(); + mSplitter->forEachEditor( [this]( UICodeEditor* editor ) { + editor->setEnableFlashCursor( mApp->getConfig().editor.flashCursor ); + } ); } else if ( "tab_stops" == id ) { mApp->getConfig().doc.tabStops = item->isActive(); mSplitter->forEachEditor( [this]( UICodeEditor* editor ) {